Files
slp-modular-cms/aidlc-docs/features/cms-frontend/construction/unit-3/functional-design/frontend-components.md
T
SluijsensandClaude Haiku 4.5 31cc45d79b docs(unit-3): Functional design for Layout & Navigation
- Role-filtered sidebar (Owner/Admin/User visibility rules BR-U3-01–06)
- Topbar removed; UserMenu + LanguageSwitcher move to sidebar footer
- Mobile slide-over sidebar with hamburger button
- Theme toggle (light/dark) with localStorage persistence and no-flash init
- New components: MobileBar, SidebarOverlay, ThemeToggle, useTheme
- Unit 2 marked complete in aidlc-state

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 11:44:24 +02:00

3.9 KiB

Frontend Components — Unit 3: Layout & Navigation

Modified Components

AppLayout.tsx (modify existing)

Path: frontend/src/components/layout/AppLayout.tsx

Remove Topbar import and render. Add MobileBar. Layout becomes:

<div className="flex min-h-svh">
    <Sidebar />                        {/* desktop only */}
    <MobileBar onMenuOpen={...} />     {/* mobile only */}
    <main className="flex-1 p-6" data-testid="app-main">
        <Outlet />
    </main>
</div>

Mobile open/close state lives here (or in MobileBar).


Sidebar.tsx (modify existing)

Path: frontend/src/components/layout/Sidebar.tsx

Changes:

  • Add roles?: Role[] to NavItem interface
  • Filter NAV_ITEMS by user.role before rendering
  • Add SidebarFooter section at bottom with LanguageSwitcher, ThemeToggle, UserMenu
  • Accept optional onClose?: () => void prop for mobile overlay close button
  • data-testid="app-sidebar" retained

Nav items:

Label key Route Roles Icon
nav.dashboard /dashboard all LayoutDashboard
nav.users /users Owner, Administrator Users
nav.settings /settings Owner Settings
nav.cms /cms Owner FileText
nav.profile /profile all User

New Components

MobileBar.tsx

Path: frontend/src/components/layout/MobileBar.tsx

Slim bar, visible only on < md. Contains hamburger button (Menu icon) and app name.

<header className="flex h-14 items-center gap-3 border-b border-border bg-card px-4 md:hidden"
        data-testid="app-mobile-bar">
    <button onClick={onMenuOpen} aria-label="Open navigation" data-testid="mobile-menu-button">
        <Menu />
    </button>
    <span className="font-semibold">{t('common.appName')}</span>
</header>

Props: onMenuOpen: () => void


SidebarOverlay.tsx

Path: frontend/src/components/layout/SidebarOverlay.tsx

Wraps <Sidebar onClose={...} /> in a backdrop overlay for mobile:

<div className="fixed inset-0 z-40 md:hidden">
    <div className="absolute inset-0 bg-black/50" onClick={onClose} data-testid="sidebar-backdrop" />
    <div className="absolute left-0 top-0 h-full w-64 shadow-xl">
        <Sidebar onClose={onClose} />
    </div>
</div>

Only rendered when mobile menu is open.


ThemeToggle.tsx

Path: frontend/src/components/layout/ThemeToggle.tsx

Button that reads/writes cms-theme in localStorage and toggles dark class on <html>.

<button
    onClick={toggleTheme}
    aria-label={isDark ? t('theme.switchToLight') : t('theme.switchToDark')}
    data-testid="theme-toggle"
>
    {isDark ? <Sun /> : <Moon />}
</button>

Uses useTheme() hook (see below).


useTheme.ts

Path: frontend/src/hooks/useTheme.ts

function useTheme(): { theme: Theme; toggleTheme: () => void }
  • Reads initial value from localStorage['cms-theme'] or prefers-color-scheme
  • On toggle: flips theme, writes to localStorage, applies class to document.documentElement

Removed Components

Topbar.tsx

Deleted. Functionality moved to Sidebar footer (LanguageSwitcher, UserMenu). data-testid="app-topbar" removed from the DOM.


i18n Keys (additions to translation.json)

{
    "nav": {
        "settings": "Instellingen"
    },
    "theme": {
        "switchToLight": "Overschakelen naar licht thema",
        "switchToDark": "Overschakelen naar donker thema"
    }
}

(English equivalents added to en/translation.json)


Test IDs Summary

Element data-testid
Sidebar (desktop) app-sidebar
Mobile bar app-mobile-bar
Hamburger button mobile-menu-button
Sidebar backdrop sidebar-backdrop
Theme toggle button theme-toggle
Nav: dashboard nav-dashboard
Nav: users nav-users
Nav: settings nav-settings
Nav: cms nav-cms
Nav: profile nav-profile
Main content area app-main