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:
Iqbal
2026-10-28 13:55:27 +07:00
parent 844c88912a
commit d018c6826f
3 changed files with 29 additions and 12 deletions

View File

@@ -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" />