article and relayout

This commit is contained in:
seb
2026-07-19 19:39:07 +02:00
parent f012f27bf9
commit af9e072427
12 changed files with 878 additions and 209 deletions

View File

@@ -3,26 +3,19 @@ import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import { NavLink, Outlet } from 'react-router-dom';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import UserMenu from './UserMenu';
import { NAV_ITEMS } from '../nav';
import { artikelQueryPath } from '../pages/artikel/artikelQuery';
const SIDEBAR_WIDTH = 144;
const FOCUSABLE =
'a, button, input, textarea, select, [role="button"], [role="menuitem"], [tabindex]:not([tabindex="-1"]), [contenteditable="true"]';
function preserveFocusOnBackground(e) {
if (e.target.closest(FOCUSABLE)) return;
e.preventDefault();
}
export default function AppShell() {
const navigate = useNavigate();
const { pathname } = useLocation();
return (
<Box
onMouseDown={preserveFocusOnBackground}
sx={{ display: 'flex', minHeight: '100vh', bgcolor: 'background.default' }}
>
<Box sx={{ display: 'flex', minHeight: '100vh', bgcolor: 'background.default' }}>
<Box
component="nav"
sx={(theme) => ({
@@ -34,37 +27,48 @@ export default function AppShell() {
})}
>
<List disablePadding sx={{ flexGrow: 1 }}>
{NAV_ITEMS.map(({ path, label, icon: Icon }) => (
<ListItemButton
key={path}
component={NavLink}
to={path}
onMouseDown={(e) => e.preventDefault()}
sx={(theme) => ({
borderRadius: 0,
px: 1.5,
py: 1.25,
borderLeft: '3px solid transparent',
color: theme.nav.item,
'& .MuiListItemIcon-root': { color: 'inherit' },
'&:hover': {
bgcolor: theme.nav.itemHover,
color: theme.nav.itemHoverText,
},
'&.active': {
bgcolor: theme.nav.itemActive,
color: theme.nav.itemActiveText,
fontWeight: 600,
borderLeftColor: theme.nav.itemActiveAccent,
},
})}
>
<ListItemIcon sx={{ minWidth: 36 }}>
<Icon />
</ListItemIcon>
<ListItemText primary={label} />
</ListItemButton>
))}
{NAV_ITEMS.map(({ path, label, icon: Icon }) => {
const active = pathname === path || pathname.startsWith(`${path}/`);
return (
<ListItemButton
key={path}
type="button"
selected={active}
onMouseDown={(e) => e.preventDefault()}
onClick={() => {
navigate(path === '/artikel' ? artikelQueryPath() : path);
}}
sx={(theme) => ({
borderRadius: 0,
px: 1.5,
py: 1.25,
borderLeft: '3px solid transparent',
color: theme.nav.item,
'& .MuiListItemIcon-root': { color: 'inherit' },
'&:hover': {
bgcolor: theme.nav.itemHover,
color: theme.nav.itemHoverText,
},
'&.Mui-selected': {
bgcolor: theme.nav.itemActive,
color: theme.nav.itemActiveText,
fontWeight: 600,
borderLeftColor: theme.nav.itemActiveAccent,
'&:hover': {
bgcolor: theme.nav.itemActive,
color: theme.nav.itemActiveText,
},
},
})}
>
<ListItemIcon sx={{ minWidth: 36 }}>
<Icon />
</ListItemIcon>
<ListItemText primary={label} />
</ListItemButton>
);
})}
</List>
<UserMenu />