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:
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import { useSyncExternalStore } from "react";
|
||||
|
||||
/**
|
||||
* Zustand des Seitenmenüs auf schmalen Bildschirmen (#034).
|
||||
*
|
||||
* AdminLTE bringt dafür eigenes JavaScript mit, das wir bewusst nicht einbinden – die Klasse
|
||||
* `sidebar-open` am `body` allein lässt sich aber nicht wieder loswerden: Kein Hintergrund zum
|
||||
* Antippen, kein Schließen beim Navigieren. Deshalb ein eigener, winziger Zustand, auf den
|
||||
* Kopfzeile und Menü gemeinsam hören.
|
||||
*/
|
||||
|
||||
const SCHMAL = 992;
|
||||
|
||||
let offen = false;
|
||||
const zuhoerer = new Set<() => void>();
|
||||
|
||||
function melden() {
|
||||
for (const ruf of zuhoerer) ruf();
|
||||
}
|
||||
|
||||
/** Setzt die Klassen, die das AdminLTE-Stylesheet auswertet. */
|
||||
function klassenSetzen() {
|
||||
const body = document.body;
|
||||
body.classList.toggle("sidebar-open", offen);
|
||||
// Auf schmalen Bildschirmen liegt das Menü über dem Inhalt; dahinter soll nichts mitscrollen.
|
||||
body.style.overflow = offen && window.innerWidth < SCHMAL ? "hidden" : "";
|
||||
}
|
||||
|
||||
export function menuUmschalten() {
|
||||
if (window.innerWidth >= SCHMAL) {
|
||||
// Breiter Bildschirm: Das Menü bleibt stehen und wird nur schmaler.
|
||||
document.body.classList.toggle("sidebar-collapse");
|
||||
document.body.classList.remove("sidebar-open");
|
||||
return;
|
||||
}
|
||||
|
||||
offen = !offen;
|
||||
document.body.classList.remove("sidebar-collapse");
|
||||
klassenSetzen();
|
||||
melden();
|
||||
}
|
||||
|
||||
export function menuSchliessen() {
|
||||
if (!offen) return;
|
||||
offen = false;
|
||||
klassenSetzen();
|
||||
melden();
|
||||
}
|
||||
|
||||
function abonnieren(ruf: () => void) {
|
||||
zuhoerer.add(ruf);
|
||||
return () => {
|
||||
zuhoerer.delete(ruf);
|
||||
};
|
||||
}
|
||||
|
||||
export function useMenuOffen(): boolean {
|
||||
// Auf dem Server ist das Menü nie offen – sonst käme es beim ersten Rendern zu einem Unterschied.
|
||||
return useSyncExternalStore(
|
||||
abonnieren,
|
||||
() => offen,
|
||||
() => false,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user