From edddf40c7ff13b1356524227217037c8ef2fcaa6 Mon Sep 17 00:00:00 2001
From: bes-r <27369668+bes-r@users.noreply.github.com>
Date: Mon, 15 Jun 2026 23:32:32 +0200
Subject: [PATCH] Stage-uitbreidingen: stagelocaties, omvang per
dag/dagdeel/blok, leerling uit klas op stage, conflictregel theorievak;
herstel afgekapte frontend-bestanden
---
ROADMAP.md | 5 +++-
frontend/src/App.jsx | 65 +++++++++++++++++++++--------------------
frontend/src/pages.jsx | 32 ++++++++++++++++++--
frontend/src/styles.css | 4 +--
4 files changed, 68 insertions(+), 38 deletions(-)
diff --git a/ROADMAP.md b/ROADMAP.md
index 15ad094..906a1ac 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -38,7 +38,10 @@ volgt.
## Vakken
-- [ ] Per vak **automatisch een passend icoon** genereren of laten selecteren.
+- [x] Per vak **automatisch een passend icoon** (afgeleid van de naam) — getoond
+ in het rooster en bij Activiteiten/vakken.
+ - [ ] Optioneel: een icoon handmatig kunnen kiezen/overschrijven (vereist een
+ `icoon`-veld op Activiteit + migratie).
## Stage-module — uitbreidingen
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 49976d4..24cb734 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -183,6 +183,38 @@ function Shell({ user, onLogout }) {
);
}
+ // Instellingen-cog: staat in de bovenbalk (buiten de scrollende tabbalk,
+ // anders knipt overflow het uitklapmenu weg).
+ const cogMenu = instellingenTabs.length > 0 ? (
+
setCogOpen(false)}>
+
+
+ {instellingenTabs.map((it) => {
+ const pad = normaliseerPad(it.path);
+ return (
+
+ );
+ })}
+
+
+ ) : null;
+
return (
diff --git a/frontend/src/pages.jsx b/frontend/src/pages.jsx
index f0094a5..1504e78 100644
--- a/frontend/src/pages.jsx
+++ b/frontend/src/pages.jsx
@@ -16,6 +16,30 @@ const ROLLEN = [
// Korte aanduiding van een medewerkersrol (compact in de roostervakjes).
const ROL_AFK = { leerkracht: "LK", praktijkondersteuner: "PO", klassenondersteuner: "KO" };
+
+// Automatisch een passend icoon bij een vak/activiteit op basis van de naam.
+const VAK_ICONEN = [
+ [/reken|wiskund|getal/i, "🔢"],
+ [/taal|lees|spell|begrijpend|nederlands|woordenschat/i, "📖"],
+ [/engels|frans|duits|spaans/i, "🗣️"],
+ [/gym|beweg|sport|zwem|motoriek/i, "🤸"],
+ [/muziek|zang/i, "🎵"],
+ [/teken|kunst|knutsel|creatief|handvaardig|drama/i, "🎨"],
+ [/pauze|speel|buiten/i, "☕"],
+ [/eten|lunch|fruit/i, "🍎"],
+ [/natuur|biolog|wereld|aardrijk|geschied/i, "🌍"],
+ [/koken|huishoud/i, "🍳"],
+ [/techniek|bouw|hout/i, "🔧"],
+ [/computer|digit|ict|programmeer|media/i, "💻"],
+ [/therap|logop|fysio|sova|sociale|gedrag/i, "💬"],
+ [/stage|werk|prakt/i, "🧑🏭"],
+ [/kring|start|dag|inloop/i, "⭕"],
+];
+function vakIcoon(naam) {
+ if (!naam) return "📚";
+ for (const [re, icon] of VAK_ICONEN) if (re.test(naam)) return icon;
+ return "📚";
+}
const BOVENGROEP_LABEL = "Bovenliggende groep";
const BOVENGROEP_LABEL_LC = "bovenliggende groep";
const BOVENGROEP_LABEL_MV = "Bovenliggende groepen";
@@ -62,7 +86,7 @@ function Foutmelding({ msg }) {
/* ----------------------- Generieke eenvoudige catalogus ------------------- */
// Voor lijsten met alleen naam + omschrijving (Functies, Activiteiten, Locaties).
-function CatalogusPage({ titel, uitleg, resource, kleur = false, telKolom, metTheorievak = false }) {
+function CatalogusPage({ titel, uitleg, resource, kleur = false, telKolom, metTheorievak = false, metIcoon = false }) {
const { items, error, loading, reload, setError } = useList(resource);
const leeg = {
naam: "", omschrijving: "",
@@ -143,6 +167,7 @@ function CatalogusPage({ titel, uitleg, resource, kleur = false, telKolom, metTh
|
{kleur && }
+ {metIcoon && {vakIcoon(it.naam)} }
{it.naam}
|
{it.omschrijving || "—"} |
@@ -183,6 +208,7 @@ export function ActiviteitenPage() {
resource="activiteiten"
kleur
metTheorievak
+ metIcoon
/>
);
}
@@ -1874,7 +1900,7 @@ export function RoosterScherm({ mode }) {
>
{edit && startDrag(e, b)} onClick={(e) => e.stopPropagation()} title="Sleep naar ander tijdslot">⠿}
- {b.activiteit_naam}
+ {vakIcoon(b.activiteit_naam)} {b.activiteit_naam}
{edit && }
{edit && }
@@ -1907,7 +1933,7 @@ export function RoosterScherm({ mode }) {
>
{edit && startDrag(e, b)} onClick={(e) => e.stopPropagation()} title="Sleep naar ander tijdslot">⠿}
- {b.activiteit_naam}
+ {vakIcoon(b.activiteit_naam)} {b.activiteit_naam}
{edit && }
{edit && }
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 02403d5..4cccfd4 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -26,10 +26,10 @@ body { margin: 0; font-family: system-ui, "Segoe UI", Roboto, sans-serif; color:
.top-tabs-settings { display: flex; align-items: center; gap: 6px; margin-left: auto; padding-left: 10px; border-left: 1px solid var(--line); }
/* Instellingen als cog-menu (popover via hover of klik) */
-.cog-menu { position: relative; margin-left: auto; }
+.cog-menu { position: relative; }
.cog-btn { display: inline-flex; align-items: center; min-height: 38px; background: transparent; border: 0; border-radius: 8px; padding: 0 10px; font-size: 18px; cursor: pointer; color: var(--muted); }
.cog-btn:hover { background: var(--bg); color: var(--ink); }
-.cog-dropdown { display: none; position: absolute; right: 0; top: 100%; margin-top: 4px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.15); min-width: 200px; padding: 6px; z-index: 50; }
+.cog-dropdown { display: none; position: absolute; right: 0; top: 100%; margin-top: 4px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,.15); min-width: 200px; padding: 6px; z-index: 60; }
.cog-menu:hover .cog-dropdown, .cog-menu.open .cog-dropdown { display: block; }
.cog-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; background: transparent; border: 0; border-radius: 8px; padding: 9px 10px; cursor: pointer; font: inherit; color: var(--ink); }
.cog-item:hover { background: var(--bg); }