feat(01-02): portal layout with header, sidebar, theme toggle, locale switcher

- Zustand sidebar store with persist middleware (collapse/expand, mobile open)
- Sticky header with logo, breadcrumb, theme toggle, locale switcher, user avatar
- Collapsible sidebar with Dashboard/Marketplace nav, accordion categories, footer
- Mobile responsive: hamburger menu with overlay sidebar on small screens
- Theme toggle cycling light/dark/system with mounted guard
- Locale switcher setting NEXT_LOCALE cookie with router.refresh
- Empty dashboard state with grid icon, "Keine Widgets aktiv" text, add button
- AppShell composing header + sidebar + responsive main content area
- All user-visible strings via useTranslations (UI-03 compliance)
This commit is contained in:
2026-06-18 10:27:46 +02:00
parent f3791c6cdd
commit 6039387857
12 changed files with 577 additions and 9 deletions
+7
View File
@@ -96,3 +96,10 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* App shell main content responsive margin */
@media (min-width: 768px) {
.app-shell-main {
margin-left: var(--current-sidebar-width, var(--sidebar-width));
}
}
+42 -7
View File
@@ -1,10 +1,45 @@
export default function Home() {
'use client';
import { useTranslations } from 'next-intl';
import { AppShell } from '@/components/layout/app-shell';
export default function DashboardPage() {
const t = useTranslations('dashboard');
return (
<main className="flex min-h-screen flex-col items-center justify-center">
<h1 className="text-4xl font-bold">Tessera</h1>
<p className="mt-4 text-lg text-gray-600">
Portal wird geladen...
</p>
</main>
<AppShell>
<div className="flex flex-col items-center justify-center min-h-[60vh] gap-4">
{/* Grid icon */}
<div className="rounded-lg bg-muted p-4">
<svg
xmlns="http://www.w3.org/2000/svg"
width="48"
height="48"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className="text-muted-foreground"
>
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="14" y="3" width="7" height="7" rx="1" />
<rect x="14" y="14" width="7" height="7" rx="1" />
<rect x="3" y="14" width="7" height="7" rx="1" />
</svg>
</div>
{/* Empty state text (D-16) */}
<p className="text-lg text-muted-foreground">
{t('empty')}
</p>
{/* Add widget button */}
<button className="mt-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity">
{t('addWidget')}
</button>
</div>
</AppShell>
);
}