smooth sidebar

This commit is contained in:
2026-04-02 21:16:49 +05:30
parent 08a84ea63f
commit 4b0d9ca425

View File

@@ -12,15 +12,19 @@ import {
ListItemIcon, ListItemIcon,
ListItemText, ListItemText,
CssBaseline, CssBaseline,
IconButton IconButton,
Tooltip,
} from '@mui/material'; } from '@mui/material';
import TableViewIcon from '@mui/icons-material/TableView'; import TableViewIcon from '@mui/icons-material/TableView';
import DashboardIcon from '@mui/icons-material/Dashboard'; import DashboardIcon from '@mui/icons-material/Dashboard';
import LogoutIcon from '@mui/icons-material/Logout'; import LogoutIcon from '@mui/icons-material/Logout';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import { ResourceConfig } from '../types/config'; import { ResourceConfig } from '../types/config';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
const drawerWidth = 240; const drawerWidth = 240;
const collapsedWidth = 64;
interface AdminLayoutProps { interface AdminLayoutProps {
children: React.ReactNode; children: React.ReactNode;
@@ -39,67 +43,148 @@ export default function AdminLayout({
}: AdminLayoutProps) { }: AdminLayoutProps) {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const [isCollapsed, setIsCollapsed] = React.useState(false);
const activeResourceName = location.pathname.split('/')[1] || null; const activeResourceName = location.pathname.split('/')[1] || null;
// AUTO-TOGGLE LOGIC
React.useEffect(() => {
if (location.pathname === '/' || location.pathname === '') {
setIsCollapsed(false);
} else {
setIsCollapsed(true);
}
}, [location.pathname]);
const currentWidth = isCollapsed ? collapsedWidth : drawerWidth;
const handleToggle = () => {
setIsCollapsed(!isCollapsed);
};
return ( return (
<Box sx={{ display: 'flex' }}> <Box sx={{ display: 'flex' }}>
<CssBaseline /> <CssBaseline />
<AppBar position="fixed" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}> <AppBar
position="fixed"
sx={{
zIndex: (theme) => theme.zIndex.drawer + 1,
backdropFilter: 'blur(8px)',
backgroundColor: 'rgba(255, 255, 255, 0.8)', // Adjust based on theme in real app
color: 'text.primary',
boxShadow: 'none',
borderBottom: '1px solid',
borderColor: 'divider',
}}
>
<Toolbar> <Toolbar>
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}> <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1, fontWeight: 'bold' }}>
Admin Panel Admin Panel
</Typography> </Typography>
<Typography variant="body1" sx={{ mr: 2 }}> <Typography variant="body1" sx={{ mr: 2, fontWeight: 500 }}>
{username} {username}
</Typography> </Typography>
<IconButton color="inherit" onClick={onLogout}> <Tooltip title="Logout">
<LogoutIcon /> <IconButton color="inherit" onClick={onLogout}>
</IconButton> <LogoutIcon />
</IconButton>
</Tooltip>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
<Drawer <Drawer
variant="permanent" variant="permanent"
sx={{ sx={{
width: drawerWidth, width: currentWidth,
flexShrink: 0, flexShrink: 0,
[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box' }, whiteSpace: 'nowrap',
boxSizing: 'border-box',
// TRANSITION
transition: (theme) => theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
[`& .MuiDrawer-paper`]: {
width: currentWidth,
boxSizing: 'border-box',
overflowX: 'hidden',
transition: (theme) => theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
}} }}
> >
<Toolbar /> <Toolbar />
<Box sx={{ overflow: 'auto' }}> <Box sx={{ overflow: 'hidden', display: 'flex', flexDirection: 'column', height: '100%' }}>
<Box sx={{ display: 'flex', justifyContent: isCollapsed ? 'center' : 'flex-end', p: 1 }}>
<IconButton onClick={handleToggle}>
{isCollapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}
</IconButton>
</Box>
<Divider />
<List> <List>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemButton <Tooltip title={isCollapsed ? "Dashboard" : ""} placement="right">
selected={location.pathname === '/'} <ListItemButton
onClick={() => navigate('/')} selected={location.pathname === '/'}
> onClick={() => navigate('/')}
<ListItemIcon> sx={{
<DashboardIcon /> minHeight: 48,
</ListItemIcon> justifyContent: isCollapsed ? 'center' : 'initial',
<ListItemText primary="Dashboard" /> px: 2.5,
</ListItemButton> }}
>
<ListItemIcon sx={{
minWidth: 0,
mr: isCollapsed ? 0 : 3,
justifyContent: 'center',
}}>
<DashboardIcon color={location.pathname === '/' ? 'primary' : 'inherit'} />
</ListItemIcon>
{!isCollapsed && <ListItemText primary="Dashboard" />}
</ListItemButton>
</Tooltip>
</ListItem> </ListItem>
</List> </List>
<Divider /> <Divider />
<List> <List sx={{ flexGrow: 1 }}>
{resources.map((res) => ( {resources.map((res) => (
<ListItem key={res.name} disablePadding> <ListItem key={res.name} disablePadding>
<ListItemButton <Tooltip title={isCollapsed ? res.pluralLabel : ""} placement="right">
selected={activeResourceName === res.name} <ListItemButton
onClick={() => onSelectResource(res.name)} selected={activeResourceName === res.name}
> onClick={() => onSelectResource(res.name)}
<ListItemIcon> sx={{
<TableViewIcon /> minHeight: 48,
</ListItemIcon> justifyContent: isCollapsed ? 'center' : 'initial',
<ListItemText primary={res.pluralLabel} /> px: 2.5,
</ListItemButton> }}
>
<ListItemIcon sx={{
minWidth: 0,
mr: isCollapsed ? 0 : 3,
justifyContent: 'center',
}}>
<TableViewIcon color={activeResourceName === res.name ? 'primary' : 'inherit'} />
</ListItemIcon>
{!isCollapsed && <ListItemText primary={res.pluralLabel} />}
</ListItemButton>
</Tooltip>
</ListItem> </ListItem>
))} ))}
</List> </List>
<Divider />
</Box> </Box>
</Drawer> </Drawer>
<Box component="main" sx={{ flexGrow: 1, p: 3 }}> <Box
component="main"
sx={{
flexGrow: 1,
p: 3,
transition: (theme) => theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
}}
>
<Toolbar /> <Toolbar />
{children} {children}
</Box> </Box>