From 168c71d2fbc3643ac4a23f84e0a564d4af6efc97 Mon Sep 17 00:00:00 2001 From: bes-r <27369668+bes-r@users.noreply.github.com> Date: Thu, 18 Jun 2026 22:21:46 +0200 Subject: [PATCH] menu's: gegroepeerde bovenbalk-dropdowns + icoon-tabbalk (inklapbaar) --- backend/core/apps.py | 8 ++--- backend/modules/stage/apps.py | 2 +- backend/modules/uren/apps.py | 2 +- frontend/src/App.jsx | 57 ++++++++++++++++++++++++++++++++++- frontend/src/pages.jsx | 12 ++++---- frontend/src/styles.css | 16 +++++++++- 6 files changed, 83 insertions(+), 14 deletions(-) diff --git a/backend/core/apps.py b/backend/core/apps.py index 1c51211..3238e81 100644 --- a/backend/core/apps.py +++ b/backend/core/apps.py @@ -28,10 +28,10 @@ class CoreConfig(AppConfig): core=True, menu_items=( # Hoofdniveau: Rooster = weergave, Roostermaker = aanpasser. - MenuItem("Rooster", "/rooster", icon="calendar", order=10), - MenuItem("Roostermaker", "/roostermaker", icon="calendar", order=12), - MenuItem("Leerlingrooster", "/leerlingrooster", icon="book", order=14), - MenuItem("Ouderrooster", "/ouderrooster", icon="badge", order=16), + MenuItem("Rooster", "/rooster", icon="calendar", order=10, group="Rooster"), + MenuItem("Roostermaker", "/roostermaker", icon="calendar", order=12, group="Rooster"), + MenuItem("Leerlingrooster", "/leerlingrooster", icon="book", order=14, group="Rooster"), + MenuItem("Ouderrooster", "/ouderrooster", icon="badge", order=16, group="Rooster"), # Submenu Organisatie: wie hoort waar. MenuItem("Personen", "/personen", icon="users", order=20, group="Organisatie"), MenuItem("Groepsindeling", "/groepsindeling", icon="layers", order=24, group="Organisatie"), diff --git a/backend/modules/stage/apps.py b/backend/modules/stage/apps.py index f7c27e0..a3ee3c8 100644 --- a/backend/modules/stage/apps.py +++ b/backend/modules/stage/apps.py @@ -23,7 +23,7 @@ class StageConfig(AppConfig): core=False, default_enabled=False, menu_items=( - MenuItem("Stage", "/stage", icon="pin", order=60, group="Groepen"), + MenuItem("Stage", "/stage", icon="pin", order=60, group="Organisatie"), ), ) ) diff --git a/backend/modules/uren/apps.py b/backend/modules/uren/apps.py index e88f051..cb3259f 100644 --- a/backend/modules/uren/apps.py +++ b/backend/modules/uren/apps.py @@ -24,7 +24,7 @@ class UrenConfig(AppConfig): core=False, default_enabled=False, menu_items=( - MenuItem("Urenoverzicht", "/uren", icon="clock", order=30), + MenuItem("Urenoverzicht", "/uren", icon="clock", order=30, group="Overzicht"), ), ) ) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index aeeff54..a911a8c 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -16,6 +16,9 @@ const ICONS = { away: "🌴", gear: "⚙️", door: "🚪", }; +// Iconen voor de groep-dropdowns in de bovenbalk. +const GROEP_ICON = { Rooster: "calendar", Organisatie: "users", Overzicht: "clock", Hulpmiddelen: "puzzle", Toegang: "key" }; + const GROEPSINDELING_PADEN = new Set(["/groepsindeling", "/structuur", "/leerplein", "/groepen", "/subgroepen"]); const GROEPSINDELING_ITEM = { label: "Groepsindeling", path: "/groepsindeling", icon: "layers", order: 24, group: "Organisatie" }; const normaliseerPad = (path) => (GROEPSINDELING_PADEN.has(path) ? "/groepsindeling" : path); @@ -174,6 +177,7 @@ function Shell({ user, onLogout }) { const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [cogOpen, setCogOpen] = useState(false); + const [openMenu, setOpenMenu] = useState(null); async function load() { setLoading(true); @@ -228,6 +232,24 @@ function Shell({ user, onLogout }) { const activePad = normaliseerPad(active); const Page = PAGES[activePad]; + // Groepeer de hoofdtabs: groepen met meerdere items worden een dropdown, + // groepen met één item en losse items blijven directe tabs. + const navEntries = (() => { + const directe = []; + const groepMap = new Map(); + for (const it of tabs) { + if (it.group) { if (!groepMap.has(it.group)) groepMap.set(it.group, []); groepMap.get(it.group).push(it); } + else directe.push(it); + } + const entries = directe.map((it) => ({ type: "tab", order: it.order, it })); + for (const [groep, items] of groepMap) { + if (items.length === 1) entries.push({ type: "tab", order: items[0].order, it: items[0] }); + else entries.push({ type: "group", order: Math.min(...items.map((i) => i.order)), groep, items }); + } + entries.sort((a, b) => a.order - b.order); + return entries; + })(); + function TabKnop({ it, compact }) { const pad = normaliseerPad(it.path); return ( @@ -243,6 +265,37 @@ function Shell({ user, onLogout }) { ); } + function NavDropdown({ groep, items }) { + const open = openMenu === groep; + const actief = items.some((i) => normaliseerPad(i.path) === activePad); + const icon = GROEP_ICON[groep] || items[0].icon; + return ( +