feat(unit-3): Layout & Navigation — sidebar, mobile overlay, theme toggle
- Remove Topbar; move UserMenu + LanguageSwitcher to sidebar footer - Add ThemeToggle (dark/light) with localStorage persistence - Add useTheme hook; no-flash inline script in index.html - Add MobileBar (hamburger + app name, mobile-only) - Add SidebarOverlay (slide-in from left, backdrop closes it) - Sidebar: role-filtered nav (BR-U3-01–06), onClose prop for mobile - AppLayout: desktop sidebar-only layout, mobile bar + overlay - i18n: theme.* and nav.openMenu/closeMenu keys (NL + EN) - Tests: 43/43 passing (14 new — useTheme, Sidebar roles, AppLayout) Stories: US-08, US-18, US-19 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,14 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Outlet, useNavigate } from '@tanstack/react-router';
|
||||
import { useAuth } from '@/contexts/auth-context';
|
||||
import { Sidebar } from '@/components/layout/Sidebar';
|
||||
import { Topbar } from '@/components/layout/Topbar';
|
||||
import { MobileBar } from '@/components/layout/MobileBar';
|
||||
import { SidebarOverlay } from '@/components/layout/SidebarOverlay';
|
||||
|
||||
/**
|
||||
* Shell for authenticated routes. Renders the persistent chrome and reacts to
|
||||
* runtime auth loss (e.g. a failed refresh during an API call) by redirecting
|
||||
* to /login (BR-U1-14).
|
||||
*/
|
||||
export function AppLayout() {
|
||||
const { isAuthenticated, status } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'guest') {
|
||||
@@ -25,9 +22,12 @@ export function AppLayout() {
|
||||
|
||||
return (
|
||||
<div className="flex min-h-svh">
|
||||
<Sidebar />
|
||||
<div className="hidden md:flex">
|
||||
<Sidebar />
|
||||
</div>
|
||||
{isMenuOpen && <SidebarOverlay onClose={() => setIsMenuOpen(false)} />}
|
||||
<div className="flex flex-1 flex-col">
|
||||
<Topbar />
|
||||
<MobileBar onMenuOpen={() => setIsMenuOpen(true)} />
|
||||
<main className="flex-1 p-6" data-testid="app-main">
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user