Collapse sidebar nav groups into dropdowns that open on the active page
Each group label (Dashboard, Settings) toggles its items; a group starts closed unless it holds the current route, and a manual toggle resets on the next navigation. Mobile keeps every item visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -135,6 +135,9 @@ export function AppLayout() {
|
||||
const { signOut } = useClerk()
|
||||
const { pathname } = useLocation()
|
||||
const current = NAV.find(n => pathname.startsWith(n.to))
|
||||
// Nav groups stay closed unless they hold the current page; a click on the label overrides that until the next route.
|
||||
const [toggled, setToggled] = useState<Partial<Record<Key, boolean>>>({})
|
||||
useEffect(() => setToggled({}), [pathname])
|
||||
const name = user?.fullName || user?.primaryEmailAddress?.emailAddress || '-'
|
||||
|
||||
return (
|
||||
@@ -143,14 +146,22 @@ export function AppLayout() {
|
||||
<NavLink to="/production"><Brand /></NavLink>
|
||||
<OrgSwitcher />
|
||||
<nav aria-label={t('layout.mainNav')}>
|
||||
{NAV_GROUPS.map(g => [
|
||||
<div key={g.label} className="nav-label">{t(g.label)}</div>,
|
||||
...g.items.map(n => (
|
||||
<NavLink key={n.to} to={n.to} className={({ isActive }) => (isActive ? 'active' : undefined)}>
|
||||
<Icon name={n.icon} />{t(n.label)}
|
||||
</NavLink>
|
||||
)),
|
||||
])}
|
||||
{NAV_GROUPS.map(g => {
|
||||
const open = toggled[g.label] ?? g.items.some(n => pathname.startsWith(n.to))
|
||||
return [
|
||||
<button key={g.label} type="button" className="nav-label" aria-expanded={open} aria-controls={`nav-${g.label}`}
|
||||
onClick={() => setToggled(s => ({ ...s, [g.label]: !open }))}>
|
||||
{t(g.label)}<Icon name="chevron-down" />
|
||||
</button>,
|
||||
<div key={`${g.label}-items`} id={`nav-${g.label}`} className={open ? 'nav-items' : 'nav-items closed'}>
|
||||
{g.items.map(n => (
|
||||
<NavLink key={n.to} to={n.to} className={({ isActive }) => (isActive ? 'active' : undefined)}>
|
||||
<Icon name={n.icon} />{t(n.label)}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>,
|
||||
]
|
||||
})}
|
||||
</nav>
|
||||
<div className="sidebar-help">
|
||||
<Icon name="info" />
|
||||
|
||||
@@ -17,6 +17,7 @@ const paths: Record<string, string> = {
|
||||
search: '<circle cx="10" cy="10" r="6"/><path d="m15 15 5 5"/>',
|
||||
info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v6M12 7v.2"/>',
|
||||
check: '<path d="m5 12 4 4L19 6"/>',
|
||||
'chevron-down': '<path d="m6 9 6 6 6-6"/>',
|
||||
'chevron-updown': '<path d="m8 9 4-4 4 4M8 15l4 4 4-4"/>',
|
||||
logout:'<path d="M10 4H4v16h6M10 12h11m-4-4 4 4-4 4"/>',
|
||||
plus: '<path d="M12 4v16M4 12h16"/>',
|
||||
|
||||
Reference in New Issue
Block a user