fix(ui): Seitenmenue auf dem Handy schliessbar machen (#034)

Das Markup stammt von AdminLTE, dessen JavaScript wir bewusst nicht
einbinden. Die Klasse sidebar-open liess sich damit setzen, aber nichts nahm
sie wieder weg: keine Flaeche zum Antippen, kein Schliessen beim Navigieren,
kein Escape. Auf dem Telefon blieb das Menue ueber dem Inhalt stehen.

Jetzt gibt es einen eigenen Zustand, auf den Kopfzeile und Menue gemeinsam
hoeren, eine abdunkelnde Flaeche dahinter, einen Schliessen-Knopf im Menuekopf
und das Schliessen beim Navigieren. Der Inhalt dahinter scrollt nicht mehr mit.

Ausserdem zeigt die Dashboard-Tabelle auf dem Telefon nur Host und Ablauf, den
Kunden klein darunter - vorher war rechts die Haelfte abgeschnitten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-03 15:55:59 +02:00
co-authored by Claude Opus 5
parent 4bcf3daedd
commit 09bb98235b
34 changed files with 286 additions and 25 deletions
+40 -4
View File
@@ -2,10 +2,11 @@
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { useState } from "react";
import { useEffect, useState } from "react";
import { LogoMitSchriftzug } from "@/components/Logo";
import type { Rolle } from "@/generated/prisma/enums";
import { darf } from "@/server/auth/rollen";
import { menuSchliessen, useMenuOffen } from "./menuZustand";
interface MenuEintrag {
href: string;
@@ -30,6 +31,21 @@ export function Sidebar({
const pathname = usePathname();
const router = useRouter();
const [suche, setSuche] = useState("");
const menuOffen = useMenuOffen();
// Nach dem Navigieren hat das Menü seinen Zweck erfüllt – auf dem Handy verdeckt es sonst alles.
useEffect(() => {
menuSchliessen();
}, [pathname]);
// Escape schließt, wie bei jedem anderen Overlay auch.
useEffect(() => {
function taste(ereignis: KeyboardEvent) {
if (ereignis.key === "Escape") menuSchliessen();
}
window.addEventListener("keydown", taste);
return () => window.removeEventListener("keydown", taste);
}, []);
const haupt: MenuEintrag[] = [
{ href: "/", titel: "Dashboard", icon: "bi-speedometer2" },
@@ -105,11 +121,30 @@ export function Sidebar({
}
return (
<aside className="app-sidebar shadow" data-bs-theme="dark">
<div className="sidebar-brand">
<>
{/* Fläche hinter dem Menü: antippen schließt. Ohne sie bleibt das Menü auf dem Handy stehen. */}
{menuOffen ? (
<button
type="button"
className="pl-menu-hintergrund d-lg-none"
aria-label="Menü schließen"
onClick={menuSchliessen}
/>
) : null}
<aside className="app-sidebar shadow" data-bs-theme="dark">
<div className="sidebar-brand d-flex align-items-center justify-content-between">
<Link href="/" className="brand-link">
<LogoMitSchriftzug variante="sidebar" groesse={34} />
</Link>
<button
type="button"
className="btn btn-link text-white d-lg-none pl-touch-target me-2"
aria-label="Menü schließen"
onClick={menuSchliessen}
>
<i className="bi bi-x-lg" aria-hidden="true" />
</button>
</div>
<div className="pl-sidebar-user">
@@ -147,6 +182,7 @@ export function Sidebar({
</ul>
</nav>
</div>
</aside>
</aside>
</>
);
}