diff --git a/frontend/src/pages.jsx b/frontend/src/pages.jsx
index 803ae3f..1f02ac2 100644
--- a/frontend/src/pages.jsx
+++ b/frontend/src/pages.jsx
@@ -2303,33 +2303,39 @@ export function RoosterScherm({ mode }) {
const editorCtx = { activiteiten, locaties, lokalen, groepen, subgroepen, leerlingen, medewerkers, tijdsloten };
const isOpenBlok = (b) => edit && bewerkBlok && bewerkBlok.id === b.id;
const toggleOpenBlok = (b) => setBewerkBlok((huidig) => (huidig && huidig.id === b.id ? null : b));
- function renderRoosterBlok(b, iso, kal) {
+ // Eén uniform vak-kaartje, gebruikt in álle situaties (los vak of vak per
+ // subgroep) zodat de weergave overal hetzelfde oogt.
+ function renderVakKaart(b, iso, kal) {
const uit = uitzOp(b.id, iso);
const vervallen = !!kal || (uit && uit.vervalt);
return (
toggleOpenBlok(b) : undefined}
title={edit ? "Klik om te bewerken" : undefined}
>
-
+
{edit &&
startDrag(e, b)} onClick={(e) => e.stopPropagation()} title="Sleep naar ander tijdslot">⠿}
- {b.activiteit_pictogram &&

}
{b.activiteit_icoon || vakIcoon(b.activiteit_naam)} {b.activiteit_naam}
+ {b.activiteit_pictogram &&

}
+
{b.activiteit_icoon || vakIcoon(b.activiteit_naam)} {b.activiteit_naam}
{edit &&
}
{edit &&
}
-
Doel: {b.doel_naam} ({b.doel_type})
- {b.locatie_naam &&
Locatie: {b.locatie_naam}
}
- {b.lokaal_naam &&
Lokaal: {b.lokaal_naam}
}
- {b.begeleiders_namen.length > 0 && (
-
Begeleiding: {b.begeleiders_namen.map((x, idx) => (
- {idx > 0 ? ", " : ""}{x.naam}{rolAfk(x.id) ? ` (${rolAfk(x.id)})` : ""}
- ))}
+ {(b.locatie_naam || b.lokaal_naam || b.begeleiders_namen.length > 0) && (
+
+ {b.locatie_naam && 📍 {b.locatie_naam}}
+ {b.lokaal_naam && 🚪 {b.lokaal_naam}}
+ {b.begeleiders_namen.length > 0 && (
+ 👤 {b.begeleiders_namen.map((x, idx) => (
+ {idx > 0 ? ", " : ""}{x.naam}{rolAfk(x.id) ? ` (${rolAfk(x.id)})` : ""}
+ ))}
+ )}
+
)}
{stageNoot(b)}
- {kal &&
Vervalt - {kal.type_label}
}
+ {kal &&
Vervalt — {kal.type_label}
}
{!kal && uit && uit.vervalt &&
Vervalt {uit.opmerking ? `(${uit.opmerking})` : ""}{edit && }
}
{!kal && uit && !uit.vervalt && uit.vervanger_naam &&
Vervanger: {uit.vervanger_naam}
}
{edit && !kal && !uit && (
@@ -2338,33 +2344,15 @@ export function RoosterScherm({ mode }) {
);
}
- function renderCompactBlok(b, iso, kal) {
- const uit = uitzOp(b.id, iso);
- const vervallen = !!kal || (uit && uit.vervalt);
- return (
-
toggleOpenBlok(b) : undefined}
- title={edit ? "Klik om te bewerken" : undefined}
- >
-
- {edit &&
startDrag(e, b)} onClick={(e) => e.stopPropagation()} title="Sleep naar ander tijdslot">⠿}
- {b.activiteit_pictogram &&

}
{b.activiteit_icoon || vakIcoon(b.activiteit_naam)} {b.activiteit_naam}
- {edit &&
}
- {edit &&
}
-
-
- {b.locatie_naam && {b.locatie_naam}}
- {b.lokaal_naam && {b.lokaal_naam}}
- {b.begeleiders_namen.length > 0 && {b.begeleiders_namen.map((x) => x.naam).join(", ")}}
- {vervallen && Vervalt}
-
- {stageNoot(b)}
-
- );
- }
+ // Klas-/doelgroepkop boven de vakken: altijd duidelijk in beeld.
+ const doelIcoon = (t) => (t === "leerling" ? "🧒" : t === "leerplein" ? "🏫" : "👥");
+ const klasKop = (naam, sub, count, icoon) => (
+
+
{icoon}
+
{naam}{sub}
+ {count != null &&
{count}}
+
+ );
function renderSlotBlokken(slotBlokken, iso, kal) {
const losse = [];
const perGroep = new Map();
@@ -2374,27 +2362,38 @@ export function RoosterScherm({ mode }) {
if (!perGroep.has(gid)) perGroep.set(gid, []);
perGroep.get(gid).push(b);
});
- const out = losse.map((b) => renderRoosterBlok(b, iso, kal));
+ const out = [];
+
+ // Losse doelen (individuele leerling e.d.): per doel een klas-kop + vakken.
+ const losPerDoel = new Map();
+ losse.forEach((b) => {
+ const k = `${b.doel_type}:${b.doel_naam}`;
+ if (!losPerDoel.has(k)) losPerDoel.set(k, []);
+ losPerDoel.get(k).push(b);
+ });
+ losPerDoel.forEach((blks, k) => {
+ const eerste = blks[0];
+ out.push(
+
+ {klasKop(eerste.doel_naam, eerste.doel_type, blks.length > 1 ? blks.length : null, doelIcoon(eerste.doel_type))}
+
{blks.map((b) => renderVakKaart(b, iso, kal))}
+
+ );
+ });
+
if (scopeType === "leerplein" && scopeId && perGroep.size > 0) {
const leerplein = leerpleinen.find((l) => l.id === Number(scopeId));
const kolommen = [...perGroep.entries()];
out.push(
-
-
⤴
-
- {leerplein ? leerplein.naam : BOVENGROEP_LABEL}
- {BOVENGROEP_LABEL} → groepen
-
-
{kolommen.length}
-
+ {klasKop(leerplein ? leerplein.naam : BOVENGROEP_LABEL, `${BOVENGROEP_LABEL} → groepen`, kolommen.length, "🏫")}
{kolommen.map(([gid, groepBlokken]) => {
const groep = groepen.find((g) => g.id === gid);
return (
{groep ? groep.naam : "Groep"}
-
{groepBlokken.map((b) => renderCompactBlok(b, iso, kal))}
+
{groepBlokken.map((b) => renderVakKaart(b, iso, kal))}
);
})}
@@ -2403,31 +2402,31 @@ export function RoosterScherm({ mode }) {
);
return out;
}
+
perGroep.forEach((groepBlokken, gid) => {
+ const groep = groepen.find((g) => g.id === gid);
+ const groepNaam = groep ? groep.naam : "Groep";
const heeftSplitsing = groepBlokken.some((b) => b.subgroep);
if (!heeftSplitsing) {
- groepBlokken.forEach((b) => out.push(renderRoosterBlok(b, iso, kal)));
+ out.push(
+
+ {klasKop(groepNaam, "groep", groepBlokken.length > 1 ? groepBlokken.length : null, "👥")}
+
{groepBlokken.map((b) => renderVakKaart(b, iso, kal))}
+
+ );
return;
}
- const groep = groepen.find((g) => g.id === gid);
const heleGroep = groepBlokken.filter((b) => b.groep === gid);
const subIds = [...new Set(groepBlokken.filter((b) => b.subgroep).map((b) => b.subgroep))];
const kolomAantal = subIds.length + (heleGroep.length > 0 ? 1 : 0);
out.push(
-
-
⤴
-
- {groep ? groep.naam : "Groep"}
- Groep → subgroepen
-
-
{kolomAantal}
-
+ {klasKop(groepNaam, "groep → subgroepen", kolomAantal, "👥")}
{heleGroep.length > 0 && (
Hele groep
-
{heleGroep.map((b) => renderCompactBlok(b, iso, kal))}
+
{heleGroep.map((b) => renderVakKaart(b, iso, kal))}
)}
{subIds.map((sid) => {
@@ -2436,7 +2435,7 @@ export function RoosterScherm({ mode }) {
return (
{sub ? sub.naam : "Subgroep"}
-
{blocks.map((b) => renderCompactBlok(b, iso, kal))}
+
{blocks.map((b) => renderVakKaart(b, iso, kal))}
);
})}
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 23658ef..9862ec1 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -219,6 +219,20 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
.split-vak-kop { display: flex; align-items: center; gap: 5px; }
.split-vak-kop strong { min-width: 0; flex: 1; font-size: 12px; }
.split-vak-meta { display: flex; flex-direction: column; gap: 1px; color: var(--muted); font-size: 11px; margin-top: 2px; }
+
+/* Eén uniform vak-kaartje (overal gelijk) + klas-kop-container */
+.blok-splitsing.enkel { background: linear-gradient(180deg, #eff6ff 0, #f8fbff 40px, #fff 100%); }
+.blok-splitsing.enkel .split-header { margin-bottom: 8px; }
+.vak-kaart { position: relative; border: 1px solid var(--line); border-left: 4px solid var(--brand); border-radius: 7px; background: #fff; padding: 7px 8px; cursor: default; box-shadow: 0 1px 0 rgba(31,41,55,.03); touch-action: none; }
+.vak-kaart.klikbaar { cursor: pointer; }
+.vak-kaart.klikbaar:hover, .vak-kaart.open { box-shadow: 0 0 0 2px var(--brand-soft); }
+.vak-kaart.vervallen { opacity: .55; }
+.vak-kaart.vervallen .vk-naam { text-decoration: line-through; }
+.vk-kop { display: flex; align-items: center; gap: 5px; }
+.vk-naam { min-width: 0; flex: 1; font-size: 13px; overflow: hidden; text-overflow: ellipsis; }
+.vk-meta { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 5px; }
+.vk-tag { display: inline-flex; align-items: center; gap: 3px; background: var(--bg); color: var(--muted); border-radius: 999px; padding: 2px 8px; font-size: 11px; line-height: 1.5; max-width: 100%; }
+@media print { .blok-splitsing.enkel { background: #fff; } }
.klas-strip { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }
/* --- Blok-bewerker --- */
@@ -365,7 +379,8 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
/* Stage in het rooster + stagelocatie-beheer */
.rb-stage { color: #b45309; font-weight: 600; }
.rooster-blok.vervallen .rb-stage,
-.split-vak.vervallen .rb-stage { opacity: .7; }
+.split-vak.vervallen .rb-stage,
+.vak-kaart.vervallen .rb-stage { opacity: .7; }
.subsectie { margin-top: 28px; padding-top: 18px; border-top: 1px solid var(--line); }
.subsectie h2 { margin: 0 0 4px; font-size: 18px; }
.veld-kol { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 120px; }
@@ -535,4 +550,4 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
.conflict-lijst li { padding: 4px 0 4px 16px; position: relative; color: #7f1d1d; font-size: 14px; }
.conflict-lijst li::before { content: "•"; position: absolute; left: 2px; }
.conflict-lijst li.waarschuwing { color: #92400e; }
-.rooster-blok.in-conflict, .split-vak.in-conflict { outline: 2px solid #ef4444; outline-offset: 1px; box-shadow: 0 0 0 4px rgba(239,68,68,.15); }
+.rooster-blok.in-conflict, .split-vak.in-conflict, .vak-kaart.in-conflict { outline: 2px solid #ef4444; outline-offset: 1px; box-shadow: 0 0 0 4px rgba(239,68,68,.15); }