👋
MUIでヘッダーのサイドバーを展開したとき、メイン部分の配置がずれないよう固定する
import * as React from 'react';
import { styled, useTheme } from '@mui/material/styles';
import {
Avatar,
Box,
Divider,
Drawer,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Toolbar,
Tooltip,
} from '@mui/material';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar';
import { IconButton, Menu } from '@mui/material';
import HomeIcon from '@mui/icons-material/Home';
import LoginIcon from '@mui/icons-material/Login';
import LogoutIcon from '@mui/icons-material/Logout';
import MenuIcon from '@mui/icons-material/Menu';
import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import InboxIcon from '@mui/icons-material/MoveToInbox';
import MailIcon from '@mui/icons-material/Mail';
import { StyledButton, StyledTypography } from '@/styles/theme';
import Link from 'next/link';
import UserMenu from './Menu/UserMenu';
import LogoutConfirmModal from '../BasicTable/Modal/LogoutConfirmModal';
const drawerWidth = 240;
const navItems = [
{ name: 'ユーザアイコン', path: '/' },
{ name: 'ログイン', path: '/signin' },
{ name: 'サインアップ', path: '/signup' },
// 他のメニュー項目...
];
// メイン部分がDrawer分右にずれるように修正
const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })<{
open?: boolean;
}>(({ theme, open }) => ({
flexGrow: 1,
padding: theme.spacing(3),
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
marginLeft: 0, // ここを修正
// 以下の部分をコメントアウト
// ...(open && {
// transition: theme.transitions.create('margin', {
// easing: theme.transitions.easing.easeOut,
// duration: theme.transitions.duration.enteringScreen,
// }),
// marginLeft: `${drawerWidth}px`, // ここを修正
// }),
}));
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: open ? 0 : `${drawerWidth}px`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
}),
}));
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: 'flex-end',
}));
export default function PersistentDrawerLeft() {
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const menuOpen = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const [openLogoutModal, setOpenLogoutModal] = React.useState(false);
const handleClickOpenLogoutModal = () => {
setOpenLogoutModal(true);
};
const handleCloseLogoutModal = () => {
setOpenLogoutModal(false);
};
return (
<Box sx={{ display: 'flex' }}>
<AppBar position="fixed" open={open} color="darkGray">
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
sx={{ mr: 2, ...(open && { display: 'none' }) }}
>
<MenuIcon color="white" />
</IconButton>
<StyledTypography
variant="h6"
component="div"
sx={{
flexGrow: 1,
display: { xs: 'none', sm: 'block' },
color: 'white.main',
}}
>
SNS APP
</StyledTypography>
<Box sx={{ display: { xs: 'none', sm: 'flex' } }}>
<Tooltip title="Account settings">
<IconButton
onClick={handleClick}
size="small"
sx={{ ml: 2 }}
aria-controls={open ? 'account-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
>
<Avatar sx={{ width: 32, height: 32 }}>M</Avatar>
</IconButton>
</Tooltip>
<UserMenu
handleClose={handleClose}
menuOpen={menuOpen}
anchorEl={anchorEl}
/>
{navItems.map((item, index) => (
<Link href={item.path} key={index}>
<StyledButton sx={{ color: 'white.main' }}>
{item.name}
</StyledButton>
</Link>
))}
</Box>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
},
}}
variant="persistent"
anchor="left"
open={open}
>
<DrawerHeader>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'ltr' ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</DrawerHeader>
<Divider />
<List>
{/* {['SignUp', 'SignIn', 'Top', 'Validation'].map((text, index) => ( */}
{/* <Link href={`${text.toLowerCase()}`} key={index}> */}
<Link href="/">
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText primary="トップ" />
</ListItemButton>
</ListItem>
</Link>
<Link href="/signup">
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>
<PersonAddAltIcon />
</ListItemIcon>
<ListItemText primary="会員登録" />
</ListItemButton>
</ListItem>
</Link>
<Link href="/signin">
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>
<LoginIcon />
</ListItemIcon>
<ListItemText primary="サインイン" />
</ListItemButton>
</ListItem>
</Link>
{/* ))} */}
</List>
<Divider />
<List>
<Link href="/test">
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>
<IconButton onClick={handleClickOpenLogoutModal}>
<LogoutIcon />
</IconButton>
</ListItemIcon>
<ListItemText
primary="ログアウト"
onClick={handleClickOpenLogoutModal}
/>
<LogoutConfirmModal
handleClickOpenLogoutModal={handleClickOpenLogoutModal}
handleCloseLogoutModal={handleCloseLogoutModal}
openLogoutModal={openLogoutModal}
/>
</ListItemButton>
</ListItem>
</Link>
</List>
</Drawer>
<Main open={open}>
<DrawerHeader />
</Main>
</Box>
);
}
Discussion