Files
sshkeyvault/src/components/huelle/Navigation.tsx
T
florian.wildeandClaude Opus 5.5 419e8ff8bd feat(ui): Huelle mit Seitenleiste und Platzhalterseiten (#002)
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>
2026-10-12 09:20:30 +02:00

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>
);
}