Menu-opschoning: Schooljaar als Rooster-tab, subtiel Instellingen-blok (Gebruikers + Modulebeheer), hint verwijderd
This commit is contained in:
parent
b3ce841efd
commit
3318ae601e
7 changed files with 54 additions and 29 deletions
|
|
@ -12,9 +12,11 @@ Fase 3 (afwezigheid, uitzonderingen, effectief weekrooster) en Fase 4
|
||||||
Het Rooster-scherm is een **weekweergave met drag-and-drop** (muis én touch) en
|
Het Rooster-scherm is een **weekweergave met drag-and-drop** (muis én touch) en
|
||||||
een **touch-vriendelijk** ontwerp; vrije dagen, afwezigheid en uitzonderingen
|
een **touch-vriendelijk** ontwerp; vrije dagen, afwezigheid en uitzonderingen
|
||||||
worden automatisch verwerkt. Het Rooster heeft tabs **Weekrooster / Conflicten /
|
worden automatisch verwerkt. Het Rooster heeft tabs **Weekrooster / Conflicten /
|
||||||
Instellingen** (tijdsloten, activiteiten en locaties beheer je daar, zodat het
|
Schooljaar / Instellingen** (tijdsloten, activiteiten en locaties beheer je daar,
|
||||||
menu rustiger is). De zijbalk groepeert items onder inklapbare submenu's
|
en het schooljaar + de kalender voer je in onder de Schooljaar-tab, zodat het menu
|
||||||
(Personen, Groepen).
|
rustiger is). De zijbalk groepeert items onder inklapbare submenu's (Personen,
|
||||||
|
Groepen) en heeft onderaan een subtiel **Instellingen**-blok met Gebruikers en
|
||||||
|
Modulebeheer.
|
||||||
|
|
||||||
Optionele module **Leerplein**: koppelt subgroepen aan groepen en bundelt
|
Optionele module **Leerplein**: koppelt subgroepen aan groepen en bundelt
|
||||||
groepen, subgroepen én losse leerlingen onder een overkoepelend leerplein.
|
groepen, subgroepen én losse leerlingen onder een overkoepelend leerplein.
|
||||||
|
|
|
||||||
12
ROADMAP.md
12
ROADMAP.md
|
|
@ -28,12 +28,12 @@ volgt.
|
||||||
bijvoorbeeld **per leerplein een eigen overzicht** in plaats van alles door
|
bijvoorbeeld **per leerplein een eigen overzicht** in plaats van alles door
|
||||||
elkaar.
|
elkaar.
|
||||||
- [ ] **Snelmenu** om per klas of per leerplein direct het rooster te tonen.
|
- [ ] **Snelmenu** om per klas of per leerplein direct het rooster te tonen.
|
||||||
- [ ] **Schooljaar uit het hoofdmenu** halen en **onder Rooster** plaatsen, met
|
- [x] **Schooljaar uit het hoofdmenu** halen en **onder Rooster** plaatsen
|
||||||
een **snelle invoer** van een schooljaar.
|
(tab "Schooljaar") met snelle invoer + kalenderbeheer.
|
||||||
- [ ] **Instellingenmenu** (subtiel weggewerkt) waaronder o.a. **Gebruikers** en
|
- [x] **Instellingenmenu** (subtiel onderaan de zijbalk) waaronder **Gebruikers**
|
||||||
**Modulebeheer** verdwijnen.
|
en **Modulebeheer** verdwijnen.
|
||||||
- [ ] De hint **"Menu's verschijnen alleen voor ingeschakelde modules."** uit de
|
- [x] De hint **"Menu's verschijnen alleen voor ingeschakelde modules."** uit de
|
||||||
zijbalk verwijderen.
|
zijbalk verwijderd.
|
||||||
|
|
||||||
## Vakken
|
## Vakken
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,8 @@ class CoreConfig(AppConfig):
|
||||||
category="Kern",
|
category="Kern",
|
||||||
core=True,
|
core=True,
|
||||||
menu_items=(
|
menu_items=(
|
||||||
# Hoofdniveau
|
# Hoofdniveau (Schooljaar zit nu als tab in het Rooster)
|
||||||
MenuItem("Rooster", "/rooster", icon="calendar", order=10),
|
MenuItem("Rooster", "/rooster", icon="calendar", order=10),
|
||||||
MenuItem("Schooljaar", "/schooljaar", icon="calendar", order=15),
|
|
||||||
# Submenu Personen
|
# Submenu Personen
|
||||||
MenuItem("Personen", "/personen", icon="users", order=20, group="Personen"),
|
MenuItem("Personen", "/personen", icon="users", order=20, group="Personen"),
|
||||||
MenuItem("Functies", "/functies", icon="badge", order=25, group="Personen"),
|
MenuItem("Functies", "/functies", icon="badge", order=25, group="Personen"),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class AccountsConfig(AppConfig):
|
||||||
core=False,
|
core=False,
|
||||||
default_enabled=False,
|
default_enabled=False,
|
||||||
menu_items=(
|
menu_items=(
|
||||||
MenuItem("Gebruikers", "/gebruikers", icon="key", order=300),
|
MenuItem("Gebruikers", "/gebruikers", icon="key", order=300, group="Instellingen"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
const ICONS = {
|
const ICONS = {
|
||||||
calendar: "📅", users: "👥", layers: "🗂️", printer: "🖨️",
|
calendar: "📅", users: "👥", layers: "🗂️", printer: "🖨️",
|
||||||
key: "🔑", puzzle: "🧩", badge: "🪪", book: "📚", pin: "📍", clock: "🕘",
|
key: "🔑", puzzle: "🧩", badge: "🪪", book: "📚", pin: "📍", clock: "🕘",
|
||||||
away: "🌴",
|
away: "🌴", gear: "⚙️",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Koppel een menu-pad aan een echt scherm. Onbekende paden tonen een
|
// Koppel een menu-pad aan een echt scherm. Onbekende paden tonen een
|
||||||
|
|
@ -134,23 +134,26 @@ function Shell({ user, onLogout }) {
|
||||||
const [openGroups, setOpenGroups] = useState({});
|
const [openGroups, setOpenGroups] = useState({});
|
||||||
|
|
||||||
// Bouw de navigatie op uit de menu-items die ACTIEVE modules aanbieden.
|
// Bouw de navigatie op uit de menu-items die ACTIEVE modules aanbieden.
|
||||||
// Items met een `group` komen onder een inklapbaar submenu.
|
// Items met een `group` komen onder een inklapbaar submenu. De groep
|
||||||
const { topItems, groups, alleItems } = useMemo(() => {
|
// "Instellingen" wordt apart, subtiel onderaan, getoond.
|
||||||
|
const { topItems, groups, instellingenItems, alleItems } = useMemo(() => {
|
||||||
const items = [];
|
const items = [];
|
||||||
for (const m of modules) {
|
for (const m of modules) {
|
||||||
if (!m.enabled) continue;
|
if (!m.enabled) continue;
|
||||||
for (const it of m.menu_items) items.push({ ...it, module: m.key });
|
for (const it of m.menu_items) items.push({ ...it, module: m.key });
|
||||||
}
|
}
|
||||||
if (user.is_staff) {
|
if (user.is_staff) {
|
||||||
items.push({ label: "Modulebeheer", path: "/modules", icon: "puzzle", order: 9999, group: "" });
|
items.push({ label: "Modulebeheer", path: "/modules", icon: "gear", order: 9999, group: "Instellingen" });
|
||||||
}
|
}
|
||||||
items.sort((a, b) => a.order - b.order);
|
items.sort((a, b) => a.order - b.order);
|
||||||
const top = items.filter((i) => !i.group);
|
const top = items.filter((i) => !i.group);
|
||||||
const grouped = {};
|
const grouped = {};
|
||||||
|
const settings = [];
|
||||||
for (const i of items) {
|
for (const i of items) {
|
||||||
if (i.group) (grouped[i.group] = grouped[i.group] || []).push(i);
|
if (i.group === "Instellingen") settings.push(i);
|
||||||
|
else if (i.group) (grouped[i.group] = grouped[i.group] || []).push(i);
|
||||||
}
|
}
|
||||||
return { topItems: top, groups: grouped, alleItems: items };
|
return { topItems: top, groups: grouped, instellingenItems: settings, alleItems: items };
|
||||||
}, [modules, user.is_staff]);
|
}, [modules, user.is_staff]);
|
||||||
|
|
||||||
function NavKnop({ it, indent }) {
|
function NavKnop({ it, indent }) {
|
||||||
|
|
@ -189,11 +192,21 @@ function Shell({ user, onLogout }) {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
<div className="sidebar-user">
|
<div className="sidebar-foot">
|
||||||
<span className="muted small">👤 {user.username}</span>
|
{instellingenItems.length > 0 && (
|
||||||
<button className="link" onClick={doLogout}>uitloggen</button>
|
<div className="nav-group">
|
||||||
|
<button className="nav-group-head subtiel" onClick={() => setOpenGroups((o) => ({ ...o, Instellingen: !o.Instellingen }))}>
|
||||||
|
<span>⚙ Instellingen</span>
|
||||||
|
<span className="nav-chev">{openGroups.Instellingen ? "▾" : "▸"}</span>
|
||||||
|
</button>
|
||||||
|
{openGroups.Instellingen && instellingenItems.map((it) => <NavKnop key={it.path} it={it} indent />)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="sidebar-user">
|
||||||
|
<span className="muted small">👤 {user.username}</span>
|
||||||
|
<button className="link" onClick={doLogout}>uitloggen</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="hint">Menu's verschijnen alleen voor ingeschakelde modules.</div>
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main className="content">
|
<main className="content">
|
||||||
|
|
|
||||||
|
|
@ -1163,13 +1163,12 @@ export function RoosterPage() {
|
||||||
{schooljaar && tab === "week" && <button className="btn primary" onClick={() => setToonForm((v) => !v)}>{toonForm ? "Sluiten" : "+ Blok"}</button>}
|
{schooljaar && tab === "week" && <button className="btn primary" onClick={() => setToonForm((v) => !v)}>{toonForm ? "Sluiten" : "+ Blok"}</button>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{schooljaar && (
|
<div className="tabbar">
|
||||||
<div className="tabbar">
|
<button className={tab === "week" ? "tab on" : "tab"} onClick={() => setTab("week")}>Weekrooster</button>
|
||||||
<button className={tab === "week" ? "tab on" : "tab"} onClick={() => setTab("week")}>Weekrooster</button>
|
<button className={tab === "conflicten" ? "tab on" : "tab"} onClick={() => setTab("conflicten")}>Conflicten</button>
|
||||||
<button className={tab === "conflicten" ? "tab on" : "tab"} onClick={() => setTab("conflicten")}>Conflicten</button>
|
<button className={tab === "schooljaar" ? "tab on" : "tab"} onClick={() => setTab("schooljaar")}>Schooljaar</button>
|
||||||
<button className={tab === "instellingen" ? "tab on" : "tab"} onClick={() => setTab("instellingen")}>Instellingen</button>
|
<button className={tab === "instellingen" ? "tab on" : "tab"} onClick={() => setTab("instellingen")}>Instellingen</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{schooljaar && tab === "week" && toonForm && (
|
{schooljaar && tab === "week" && toonForm && (
|
||||||
<form className="form-card" onSubmit={opslaan}>
|
<form className="form-card" onSubmit={opslaan}>
|
||||||
|
|
@ -1276,6 +1275,13 @@ export function RoosterPage() {
|
||||||
|
|
||||||
{schooljaar && tab === "conflicten" && <Conflicten schooljaar={schooljaar} />}
|
{schooljaar && tab === "conflicten" && <Conflicten schooljaar={schooljaar} />}
|
||||||
|
|
||||||
|
{tab === "schooljaar" && (
|
||||||
|
<div className="instellingen">
|
||||||
|
<p className="muted">Maak hier snel een schooljaar aan en beheer de kalender (studiedagen, vrije dagen, vakanties).</p>
|
||||||
|
<SchooljaarPage />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{schooljaar && tab === "instellingen" && (
|
{schooljaar && tab === "instellingen" && (
|
||||||
<div className="instellingen">
|
<div className="instellingen">
|
||||||
<p className="muted">Bouwstenen van het rooster — beheer ze hier zonder het Rooster te verlaten.</p>
|
<p className="muted">Bouwstenen van het rooster — beheer ze hier zonder het Rooster te verlaten.</p>
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,11 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
|
|
||||||
.drag-ghost { position: fixed; z-index: 1000; pointer-events: none; background: var(--brand); color: #fff; padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: 600; box-shadow: 0 6px 18px rgba(0,0,0,.25); }
|
.drag-ghost { position: fixed; z-index: 1000; pointer-events: none; background: var(--brand); color: #fff; padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: 600; box-shadow: 0 6px 18px rgba(0,0,0,.25); }
|
||||||
|
|
||||||
|
/* --- Onderkant zijbalk: subtiel Instellingen-blok --- */
|
||||||
|
.sidebar-foot { margin-top: auto; padding-top: 10px; border-top: 1px solid var(--line); }
|
||||||
|
.nav-group-head.subtiel { color: var(--muted); opacity: .8; }
|
||||||
|
.nav-group-head.subtiel:hover { opacity: 1; }
|
||||||
|
|
||||||
/* --- Submenu's in de zijbalk --- */
|
/* --- Submenu's in de zijbalk --- */
|
||||||
.nav-group { margin-top: 2px; }
|
.nav-group { margin-top: 2px; }
|
||||||
.nav-group-head { display: flex; justify-content: space-between; align-items: center; width: 100%; background: transparent; border: 0; cursor: pointer; padding: 10px 10px 4px; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); font-weight: 700; }
|
.nav-group-head { display: flex; justify-content: space-between; align-items: center; width: 100%; background: transparent; border: 0; cursor: pointer; padding: 10px 10px 4px; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); font-weight: 700; }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue