この本で作るツールは1ページのみです。
そのページはApp.tsxに記述していきます。
ページのレイアウトを考えてみましょう。
ドロワーやメニューはとりあえず置いておいて、編集画面を作っていきましょう。
編集画面は大きく
- ヘッダー
- 編集パネル
- サイドバー
の3つのパーツに分かれています。
これら3つはAppコンポーネントの子コンポーネントなのでプロジェクトルート/src/components/App/
に配置していきます。
それぞれ
パーツ | ファイル名 |
---|---|
ヘッダー | Header.tsx |
編集パネル | BuildPanel.tsx |
サイドバー | Sidebar.tsx |
と名付けることにします。
グローバルCSS
画面いっぱいに表示させるためにグローバルCSSが必要です。
今回はこちらで用意したCSSを使ってください。
html,
body,
#root{
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
(あとでこのファイルをApp.tsxから読み込みます)
Header.tsx
ヘッダーは以下の通りです。
import AppBar, { AppBarProps } from "@mui/material/AppBar";
import IconButton from "@mui/material/IconButton/IconButton";
import Toolbar from "@mui/material/Toolbar/Toolbar";
import Typography from "@mui/material/Typography/Typography";
import MenuIcon from "@mui/icons-material/Menu" ;
import { FC } from "react";
export type HeaderProps = {} & AppBarProps;
const Header: FC<HeaderProps> = (props) => {
return (
<AppBar position="static">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
タイトル未設定
</Typography>
</Toolbar>
</AppBar>
);
};
export default Header;
いきなり見慣れないコンポーネントがたくさん出てきましたがあまり気にする必要はありません。ちょっといい感じのデザインにするためのコンポーネントだと思ってください。
なお、このコードは公式ドキュメントをちょっといじっただけです。こちらを参照してください。
BuildPane.tsx
編集パネルは今現在特に表示させたいものがないので空のdivタグを置いておきます。後でこの中に記号やフローを追加していきます。
import {FC} from "react" ;
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
return (
<div>
this is build panel
</div>
)
}
export default BuildPanel ;
Sidebar.tsx
サイドバーも今は表示したいものがないので空のdivタグを置いておきましょう。
import {FC} from "react" ;
export interface SidebarProps{
}
const Sidebar :FC<SidebarProps> = ({})=>{
return (
<div>
this is sidebar
</div>
)
}
export default Sidebar ;
App.tsxで読み込む
これまで作った
- App.css
- Header.tsx
- BuildPanel.tsx
- Sidebar.tsx
を読み込んでみましょう。
import BuildPanel from 'components/App/BuildPanel';
import Header from 'components/App/Header';
import Sidebar from 'components/App/Sidebar';
import { FC } from 'react';
import "./App.css" ;
interface AppProps{}
const App :FC<AppProps> = ()=>{
return (
<div>
<Header />
<BuildPanel />
<Sidebar />
</div>
) ;
};
export default App;
Appコンポーネントのdivタグに何もスタイルがかかっていないため、このままではヘッダー・編集パネル・サイドバーが縦並びに表示されてしまいます。ヘッダーはそのままでも大丈夫ですが、編集パネルとサイドバーは横並びになってほしいので別途CSSをあてなければなりません。
そんなときに便利なのがMUIのGridコンポーネントです。
Gridコンポーネントは<Grid container>
と<Grid item>
の2つの使い方があります。
container の中に item を配置します。
<Grid container>
<Grid item> 1 </Grid>
<Grid item> 2 </Grid>
</Grid>
また各itemにはxs props
を指定でき、その設定値によって様々な挙動をします。
xs props
を使うことでitemの横幅を指定することができます。
xs に数値をした場合
<Grid item xs={} >
と指定した場合、そのitemはcontainerの横幅を12としたときの設定値分の割合の大きさを指定したことになります。
例えば<Grid item xs={6} >
は 12分の6 = 半分の大きさなので親要素のちょうど半分の大きさになります。
xs を指定した場合
<Grid item xs>
と指定した場合、そのitemは隙間を埋めるようになるべく大きくなります。
例えば以下のような場合、
<Grid container>
<Grid item xs={2}> item-1 </Grid>
<Grid item xs> item-2 </Grid>
</Grid>
item-1はcontainerの12分の2、item-2はcontainerの12分の10になります。
xs に"auto"を指定した場合
<Grid item xs="auto">
と指定した場合、そのitemは親要素に影響されず、子要素の内容に合わせて自動的に決まります。(おそらく内部的にwidth: auto;
が指定されているのでしょう)
これを使って横幅の大きさを指定することでいい感じのレイアウトを組むことができます。
ここまで理解できた方は是非ご自身でGridを使ったレイアウトを考えてみてください。
ここには一例を示しておきます。
import Grid from '@mui/material/Grid';
import BuildPanel from 'components/App/BuildPanel';
import Header from 'components/App/Header';
import Sidebar from 'components/App/Sidebar';
import { FC } from 'react';
import "./App.css" ;
interface AppProps{}
const App :FC<AppProps> = ()=>{
return (
<Grid container>
<Grid item xs={12}>
<Header />
</Grid>
<Grid item xs>
<BuildPanel />
</Grid>
<Grid item xs="auto">
<Sidebar />
</Grid>
</Grid>
) ;
};
export default App;
見た目を整える
最後に見た目を整えるために、BuildPanelとSidebarをMUIのCard
コンポーネントで囲いましょう。
import Card from '@mui/material/Card'; // 追加
import CardContent from '@mui/material/CardContent'; // 追加
import Grid from '@mui/material/Grid';
import BuildPanel from 'components/App/BuildPanel';
import Header from 'components/App/Header';
import Sidebar from 'components/App/Sidebar';
import { FC } from 'react';
import "./App.css" ;
interface AppProps{}
const App :FC<AppProps> = ()=>{
return (
<Grid container>
<Grid item xs={12}>
<Header />
</Grid>
<Grid item xs>
<Card> {/* 追加 */}
<CardContent> {/* 追加 */}
<BuildPanel />
</CardContent> {/* 追加 */}
</Card> {/* 追加 */}
</Grid>
<Grid item xs="auto">
<Card> {/* 追加 */}
<CardContent> {/* 追加 */}
<Sidebar />
</CardContent> {/* 追加 */}
</Card> {/* 追加 */}
</Grid>
</Grid>
) ;
};
export default App;
ようやくレイアウトが完成しました。
ここで各ファイルの内容を確認しておきたい方は以下をご利用ください。
プロジェクトルート/src/components/App/BuildPane.tsx
import {FC} from "react" ;
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
return (
<div>
this is build panel
</div>
)
}
export default BuildPanel ;
プロジェクトルート/src/components/App/Header.tsx
import AppBar, { AppBarProps } from "@mui/material/AppBar";
import IconButton from "@mui/material/IconButton/IconButton";
import Toolbar from "@mui/material/Toolbar/Toolbar";
import Typography from "@mui/material/Typography/Typography";
import MenuIcon from "@mui/icons-material/Menu" ;
import { FC } from "react";
export type HeaderProps = {} & AppBarProps;
const Header: FC<HeaderProps> = (props) => {
return (
<AppBar position="static">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
タイトル未設定
</Typography>
</Toolbar>
</AppBar>
);
};
export default Header;
プロジェクトルート/src/components/App/Sidebar.tsx
import {FC} from "react" ;
export interface SidebarProps{
}
const Sidebar :FC<SidebarProps> = ({})=>{
return (
<div>
this is sidebar
</div>
)
}
export default Sidebar ;
プロジェクトルート/src/components/util/Button.tsx
import { FC } from "react";
import MUIButton, { ButtonProps as MUIButtonProps } from "@mui/material/Button";
export type ButtonProps = {
} & MUIButtonProps;
const Button: FC<ButtonProps> = (props) => {
const {
children,
...muiProps
} = props;
return (
<MUIButton variant="outlined" {...muiProps}>
{children}
</MUIButton>
);
};
export default Button;
プロジェクトルート/src/components/util/Checkbox.tsx
import { FC } from "react";
import MUICheckbox, { CheckboxProps as MUICheckboxProps } from "@mui/material/Checkbox";
export type CheckboxProps = {
} & MUICheckboxProps;
const Checkbox: FC<CheckboxProps> = (props) => {
const {
...muiProps
} = props;
return (
<MUICheckbox {...muiProps}>
</MUICheckbox>
);
};
export default Checkbox;
プロジェクトルート/src/components/util/TextField.tsx
import { FC } from "react";
import MUITextField, { TextFieldProps as MUITextFieldProps } from "@mui/material/TextField";
export type TextFieldProps = {
} & MUITextFieldProps;
const TextField: FC<TextFieldProps> = (props) => {
const {
...muiProps
} = props;
return (
<MUITextField {...muiProps}>
</MUITextField>
);
};
export default TextField;
プロジェクトルート/src/components/App.css
html,
body,
#root{
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
プロジェクトルート/src/components/App.tsx
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Grid from '@mui/material/Grid';
import BuildPanel from 'components/App/BuildPanel';
import Header from 'components/App/Header';
import Sidebar from 'components/App/Sidebar';
import { FC } from 'react';
import "./App.css" ;
interface AppProps{}
const App :FC<AppProps> = ()=>{
return (
<Grid container>
<Grid item xs={12}>
<Header />
</Grid>
<Grid item xs>
<Card>
<CardContent>
<BuildPanel />
</CardContent>
</Card>
</Grid>
<Grid item xs="auto">
<Card>
<CardContent>
<Sidebar />
</CardContent>
</Card>
</Grid>
</Grid>
) ;
};
export default App;
プロジェクトルート/src/components/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);