From a18203715303b45e6faefaebe1fd449523f5d178 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Fri, 2 Oct 2026 12:36:23 +0200 Subject: [PATCH] Seitenleiste: die vier Bestandslisten klappen zusammen Lebensmittel, Gegenstaende, Einzelstuecke und Chargen stehen jetzt unter einer Gruppe "Listen". Sie ist der laengste Block der Leiste und wird im Alltag selten gebraucht - wer einlagert, nimmt die Knoepfe darueber. Vorgabe ist zugeklappt, der Zustand bleibt im Browser (wie die Spalteneinstellungen der Tabellen). Steht man auf einer dieser Seiten, klappt die Gruppe auf, ohne den gemerkten Zustand zu ueberschreiben - sonst saehe man nicht, wo man ist. Die Eintraege bleiben dabei im Dokument und werden nur per Klasse verborgen: Auf schmalen Bildschirmen wird die Leiste waagerecht, dort gibt es keine Abschnitte und kein Platzproblem, also blendet die CSS sie wieder ein und die Gruppe selbst aus. Waeren sie ausgehaengt, waeren sie dort weg. Die Mobil-Regeln brauchen `.sidebar` davor: Ein Media-Query erhoeht die Spezifitaet nicht, und die Grundregeln stehen weiter unten in der Datei - ohne das gewinnt die spaetere Regel und die Ausnahme greift nie. Co-Authored-By: Claude Opus 5 --- web/src/App.jsx | 54 ++++++++++++++++++++++++++++++++++++++++++---- web/src/styles.css | 24 +++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/web/src/App.jsx b/web/src/App.jsx index 8e904ef..0fa5d20 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -34,6 +34,17 @@ import Konto from "./pages/Konto"; const navClass = ({ isActive }) => (isActive ? "nav-link active" : "nav-link"); +// Die vier Bestandslisten stehen unter einer zuklappbaren Gruppe. Sie sind der +// laengste Block der Leiste und wird im Alltag selten gebraucht – wer einlagert, +// nutzt die Knoepfe darueber. +const LISTEN = [ + { to: "/lebensmittel", icon: "food", label: "Lebensmittel" }, + { to: "/gegenstaende", icon: "package", label: "Gegenstände" }, + { to: "/items", icon: "tag", label: "Einzelstücke" }, + { to: "/chargen", icon: "box", label: "Chargen" }, +]; +const LISTEN_OFFEN_KEY = "nav:listen-offen"; + function NavItem({ to, icon, label, end }) { return ( @@ -46,7 +57,24 @@ function NavItem({ to, icon, label, end }) { function Sidebar() { const { user, isAdmin, logout } = useAuth(); const navigate = useNavigate(); + const { pathname } = useLocation(); const [dashboards, setDashboards] = useState([]); + // Zugeklappt als Vorgabe; der Zustand bleibt im Browser, wie die + // Spalteneinstellungen der Tabellen. + const [listenOffen, setListenOffen] = useState( + () => localStorage.getItem(LISTEN_OFFEN_KEY) === "1", + ); + // Steht man auf einer dieser Seiten, ist die Gruppe offen – ohne den + // gemerkten Zustand zu ueberschreiben. Sonst saehe man nicht, wo man ist. + const aufEinerListe = LISTEN.some((e) => pathname.startsWith(e.to)); + + function klappeListen() { + setListenOffen((alt) => { + const neu = !alt; + localStorage.setItem(LISTEN_OFFEN_KEY, neu ? "1" : "0"); + return neu; + }); + } // Die Dashboards des Benutzers stehen als eigene Eintraege in der Leiste. // Sie aendern sich beim Anlegen und Loeschen, deshalb horcht die Leiste auf @@ -82,10 +110,28 @@ function Sidebar() { ))} - - - - + {/* Auf schmalen Bildschirmen wird die Leiste waagerecht; dort gibt es + keine Abschnitte (styles.css) und die Eintraege stehen flach + nebeneinander – zuklappen loest dort kein Platzproblem. */} + + {LISTEN.map((e) => ( + [ + "nav-link nav-child", + isActive ? "active" : "", + // Nicht ausgehaengt, nur verborgen: auf schmalen Bildschirmen + // blendet die CSS sie wieder ein, dort gibt es keine Gruppe. + listenOffen || aufEinerListe ? "" : "nav-zu", + ].filter(Boolean).join(" ")}> + + {e.label} + + ))} diff --git a/web/src/styles.css b/web/src/styles.css index 0ae2dab..7c726ba 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -1036,6 +1036,15 @@ select.zeitraum:hover { color: var(--text); } .sidebar-brand { padding: var(--sp-3) var(--sp-4); } .sidebar-nav { flex-direction: row; overflow-x: auto; padding: var(--sp-2) var(--sp-3); gap: var(--sp-1); } .nav-section { display: none; } + /* Waagerechte Leiste: Zuklappen loest hier kein Platzproblem, und + untereinander ist ohnehin kein Platz. Die Gruppe verschwindet, ihre + Eintraege stehen flach zwischen den anderen – wie vorher. + Mit `.sidebar` davor, weil die Grundregeln weiter unten in der Datei + stehen: ein Media-Query erhoeht die Spezifitaet nicht, und bei + Gleichstand gewinnt die spaetere Regel. */ + .sidebar .nav-group { display: none; } + .sidebar .nav-link.nav-zu { display: flex; } + .sidebar .nav-link.nav-child { padding-left: 8px; } .nav-link { white-space: nowrap; } .nav-link span.label { display: none; } .nav-link { padding: 8px; } @@ -1088,6 +1097,21 @@ select.zeitraum:hover { color: var(--text); } } .nav-link.sub.active { font-weight: 600; } +/* Zuklappbare Gruppe in der Seitenleiste: sieht aus wie eine + Abschnittsueberschrift, ist aber ein Knopf. */ +.nav-group { + display: flex; align-items: center; gap: var(--sp-2); + width: 100%; background: none; border: none; cursor: pointer; + padding: var(--sp-4) var(--sp-3) var(--sp-1); + font-size: 0.68rem; font-weight: 600; letter-spacing: 0.06em; + text-transform: uppercase; color: var(--muted); opacity: 0.7; + font-family: inherit; text-align: left; +} +.nav-group:hover { opacity: 1; } +/* Eingerueckt wie die Dashboard-Unterpunkte, aber mit Platz fuers Symbol. */ +.nav-link.nav-child { padding-left: 26px; font-size: 0.86rem; } +.nav-link.nav-zu { display: none; } + /* ---- Aktionskarten: Ein- und Auslagern ohne Seitenwechsel ---- */ .aktion-karte { gap: 10px; }