Die Huelle bekommt Benutzer und optional den aktiven Pfad als Props und kennt weder Sitzung noch Datenbank; ohne Pfad ermittelt die Navigation ihn per usePathname(), weil ein Layout den Pfad nicht kennt. Die Benutzerermittlung steckt in huellenBenutzerErmitteln(), damit #004 nur diese Funktion ersetzen muss. Unter 1024 px klappt die Leiste ein; geschlossen ist sie invisible und damit auch nicht per Tab erreichbar. Alle Navigationsziele haben eine Platzhalterseite, damit nichts auf eine 404 fuehrt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { clsx } from "clsx";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { HAUPTNAVIGATION, istAktiv, NEBENNAVIGATION, type NavPunkt } from "./nav-punkte";
|
|
|
|
/**
|
|
* Navigation der Seitenleiste. Client-Komponente, weil ein Layout den aktuellen Pfad
|
|
* nicht kennt: Ohne `aktiverPfad` nimmt sie ihn aus usePathname(); Seiten oder Tests
|
|
* können ihn ausdrücklich vorgeben.
|
|
*/
|
|
export function Navigation({ aktiverPfad }: { aktiverPfad?: string }) {
|
|
const routerPfad = usePathname();
|
|
const pfad = aktiverPfad ?? routerPfad ?? "/";
|
|
return (
|
|
<nav aria-label="Hauptnavigation" className="flex flex-col gap-1">
|
|
<NavListe punkte={HAUPTNAVIGATION} pfad={pfad} />
|
|
<hr className="border-border mx-2 my-3" />
|
|
<NavListe punkte={NEBENNAVIGATION} pfad={pfad} />
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
function NavListe({ punkte, pfad }: { punkte: NavPunkt[]; pfad: string }) {
|
|
return (
|
|
<ul className="flex flex-col gap-1">
|
|
{punkte.map(({ href, titel, icon: Icon }) => {
|
|
const aktiv = istAktiv(href, pfad);
|
|
return (
|
|
<li key={href}>
|
|
<Link
|
|
href={href}
|
|
aria-current={aktiv ? "page" : undefined}
|
|
className={clsx(
|
|
"rounded-box flex min-h-11 items-center gap-3 px-3 text-[14.5px] transition-colors",
|
|
aktiv
|
|
? "bg-raised text-accent font-semibold"
|
|
: "text-muted hover:bg-raised/60 hover:text-text font-medium",
|
|
)}
|
|
>
|
|
<Icon aria-hidden className="size-[18px] shrink-0" strokeWidth={aktiv ? 2.2 : 1.8} />
|
|
{titel}
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
);
|
|
}
|