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:
@@ -0,0 +1,33 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useLocale, useTranslations } from 'next-intl';
|
||||
import { useTransition } from 'react';
|
||||
|
||||
export function LocaleSwitcher() {
|
||||
const router = useRouter();
|
||||
const locale = useLocale();
|
||||
const t = useTranslations('locale');
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
function switchLocale() {
|
||||
const newLocale = locale === 'de' ? 'en' : 'de';
|
||||
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
|
||||
startTransition(() => {
|
||||
router.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
const currentLabel = locale === 'de' ? t('de') : t('en');
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={switchLocale}
|
||||
disabled={isPending}
|
||||
className="inline-flex items-center justify-center rounded-md px-2.5 py-1.5 text-sm font-medium text-muted-foreground hover:bg-muted hover:text-foreground transition-colors disabled:opacity-50"
|
||||
aria-label={currentLabel}
|
||||
>
|
||||
{locale === 'de' ? 'EN' : 'DE'}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user