diff --git a/frontend/src/pages.jsx b/frontend/src/pages.jsx index 5f3639e..653662b 100644 --- a/frontend/src/pages.jsx +++ b/frontend/src/pages.jsx @@ -2401,19 +2401,38 @@ export function RoosterScherm({ mode }) { const editorCtx = { activiteiten, locaties, lokalen, groepen: sortedGroepen, subgroepen, leerlingen, medewerkers: sortedMedewerkers, tijdsloten }; const isOpenBlok = (b) => edit && bewerkBlok && bewerkBlok.id === b.id; const toggleOpenBlok = (b) => setBewerkBlok((huidig) => (huidig && huidig.id === b.id ? null : b)); + const klasAccent = (naam) => { + const palet = ["#2563eb", "#0f766e", "#7c3aed", "#d97706", "#db2777", "#0891b2", "#65a30d", "#dc2626"]; + const s = String(naam || ""); + let n = 0; + for (let i = 0; i < s.length; i++) n = (n + s.charCodeAt(i) * (i + 1)) % palet.length; + return palet[n]; + }; + const klasNaamVanBlok = (b) => { + const gid = bovenliggendeGroep(b, subgroepen); + if (gid) return (sortedGroepen.find((g) => g.id === gid) || {}).naam || b.doel_naam || "Klas"; + return b.doel_naam || "Klas"; + }; // 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); + const klasNaam = klasNaamVanBlok(b); + const conflict = conflictInfo.blokIds.has(b.id); return (
toggleOpenBlok(b) : undefined} title={edit ? "Klik om te bewerken" : undefined} > +
+ {klasNaam} + {b.subgroep && {b.doel_naam}} + {conflict && Conflict} +
{edit && startDrag(e, b)} onClick={(e) => e.stopPropagation()} title="Sleep naar ander tijdslot">⠿} {b.activiteit_pictogram && } @@ -3217,10 +3236,15 @@ export function PeriodeRoosterPage() { {t.start_tijd?.slice(0, 5)} {t.naam} {groepenZichtbaar.map((g) => { const cellblk = blokkenVan(t.id, g.id); + const accent = klasAccent(g.naam); return ( {cellblk.map((b) => ( -
+
+
+ {g.naam} + {conflictInfo.blokIds.has(b.id) && Conflict} +
{b.activiteit_icoon || vakIcoon(b.activiteit_naam)} {b.activiteit_naam} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 98d405f..0ba3409 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -230,9 +230,9 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .indeling-kop { font-weight: 600; margin-bottom: 2px; } @media (max-width: 700px) { .indeling-kolommen { grid-template-columns: 1fr; } } -.blok-splitsing { position: relative; border: 1px solid #bfdbfe; border-radius: 8px; background: linear-gradient(180deg, #eff6ff 0, #f8fbff 42px, #fff 100%); padding: 8px; margin-bottom: 8px; } -.split-header { display: flex; align-items: center; gap: 8px; border: 1px solid #bfdbfe; border-radius: 7px; background: #fff; padding: 6px 8px; margin-bottom: 12px; } -.split-icon { width: 24px; height: 24px; display: inline-grid; place-items: center; border-radius: 6px; background: var(--brand); color: #fff; font-weight: 800; flex: none; } +.blok-splitsing { position: relative; border: 1px solid #cbd5e1; border-radius: 8px; background: #f8fafc; padding: 8px; margin-bottom: 8px; box-shadow: inset 0 1px 0 rgba(255,255,255,.75); } +.split-header { display: flex; align-items: center; gap: 8px; border: 1px solid #cbd5e1; border-left: 5px solid var(--brand); border-radius: 7px; background: #fff; padding: 6px 8px; margin-bottom: 10px; } +.split-icon { width: 24px; height: 24px; display: inline-grid; place-items: center; border-radius: 6px; background: #0f172a; color: #fff; font-weight: 800; flex: none; } .split-title { display: flex; flex-direction: column; gap: 1px; min-width: 0; line-height: 1.15; flex: 1; } .split-title strong { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .split-title span { font-size: 11px; color: var(--muted); } @@ -263,13 +263,17 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; /* 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; min-height: 82px; height: 82px; display: flex; flex-direction: column; 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; overflow: hidden; } +.vak-kaart { position: relative; min-height: 96px; height: 96px; display: flex; flex-direction: column; border: 1px solid #cbd5e1; border-left: 0; border-radius: 8px; background: #fff; padding: 0 8px 8px; cursor: default; box-shadow: 0 1px 2px rgba(15,23,42,.08); touch-action: none; overflow: hidden; } .vak-kaart.klikbaar { cursor: pointer; } -.vak-kaart.klikbaar:hover, .vak-kaart.open { box-shadow: 0 0 0 2px var(--brand-soft); } +.vak-kaart.klikbaar:hover, .vak-kaart.open { box-shadow: 0 0 0 2px var(--brand-soft), 0 2px 6px rgba(15,23,42,.10); } .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: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.vk-klasband { display: flex; align-items: center; gap: 6px; min-height: 24px; margin: 0 -8px 7px; padding: 4px 8px; background: color-mix(in srgb, var(--klas-kleur) 14%, #fff); border-bottom: 1px solid color-mix(in srgb, var(--klas-kleur) 38%, #dbeafe); box-shadow: inset 5px 0 0 var(--klas-kleur); } +.vk-klasnaam { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; font-weight: 900; color: #0f172a; text-transform: uppercase; letter-spacing: .03em; } +.vk-subnaam { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; font-weight: 700; color: #475569; } +.vk-conflict-badge { margin-left: auto; flex: none; border-radius: 999px; background: #dc2626; color: #fff; padding: 1px 7px; font-size: 10px; font-weight: 900; text-transform: uppercase; } +.vk-kop { display: flex; align-items: center; gap: 5px; min-height: 24px; } +.vk-naam { min-width: 0; flex: 1; font-size: 13px; font-weight: 850; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #111827; } .vk-meta { display: flex; flex-wrap: wrap; gap: 3px 5px; margin-top: 5px; overflow: hidden; } .vk-tag { display: inline-flex; align-items: center; gap: 3px; background: var(--bg); color: var(--muted); border-radius: 999px; padding: 1px 6px; font-size: 10px; line-height: 1.5; max-width: 100%; } .vk-opmerking { margin-top: auto; padding-top: 4px; color: #475569; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } @@ -596,21 +600,21 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .wm-filterbar .wm-zoek { flex: 1 1 260px; } .wm-filterbar .wm-zoek input { width: 100%; } .wm-filtercheck { min-height: 38px; margin: 0; align-self: flex-end; } -.wm-cel { padding: 7px; min-width: 170px; height: 96px; } +.wm-cel { padding: 7px; min-width: 180px; height: 112px; } .wm-cel.focus { background-image: linear-gradient(180deg, rgba(37,99,235,.04), rgba(37,99,235,.015)); } -.wm-vak { min-height: 70px; height: 70px; display: flex; flex-direction: column; border: 1px solid var(--line); border-left: 4px solid var(--brand); border-radius: 7px; background: #fff; padding: 6px 7px; margin-bottom: 5px; overflow: hidden; } +.wm-vak { position: relative; min-height: 88px; height: 88px; display: flex; flex-direction: column; border: 1px solid #cbd5e1; border-left: 0; border-radius: 8px; background: #fff; padding: 0 7px 7px; margin-bottom: 5px; overflow: hidden; box-shadow: 0 1px 1px rgba(15,23,42,.06); } +.wm-klasband { display: flex; align-items: center; gap: 6px; min-height: 22px; margin: 0 -7px 6px; padding: 4px 7px; background: color-mix(in srgb, var(--klas-kleur) 14%, #fff); border-bottom: 1px solid color-mix(in srgb, var(--klas-kleur) 38%, #dbeafe); box-shadow: inset 5px 0 0 var(--klas-kleur); } +.wm-klasband span { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #0f172a; font-size: 10px; font-weight: 900; text-transform: uppercase; letter-spacing: .03em; } +.wm-klasband strong { flex: none; border-radius: 999px; background: #dc2626; color: #fff; padding: 1px 6px; font-size: 9px; text-transform: uppercase; } .wm-vak-kop { display: flex; align-items: center; gap: 4px; } -.wm-vak-naam { flex: 1; min-width: 0; font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; } +.wm-vak-naam { flex: 1; min-width: 0; font-size: 12px; font-weight: 850; overflow: hidden; text-overflow: ellipsis; color: #111827; } .wm-vak-meta { color: var(--muted); font-size: 11px; margin-top: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.wm-vak.in-conflict { - outline: 0; - box-shadow: inset 0 0 0 2px #ef4444, 0 1px 0 rgba(31,41,55,.03); -} +.wm-vak.in-conflict { border-color: #dc2626; background: #fff7f7; outline: 3px dashed #dc2626; outline-offset: -5px; box-shadow: 0 0 0 2px #fff, 0 0 0 5px rgba(220,38,38,.28); } .wm-add { width: 100%; border: 1px dashed var(--line); background: transparent; color: var(--muted); border-radius: 7px; padding: 4px; cursor: pointer; font: inherit; font-size: 13px; opacity: .6; } .wm-cel:hover .wm-add { opacity: 1; } .wm-add:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); } /* Vak volledig in de vakkleur (kleur + leesbare tekstkleur via CSS-variabelen) */ -.vak-kaart.kleur-vlak { background: var(--vk-kleur); color: var(--vk-tekst); } +.vak-kaart.kleur-vlak { background: color-mix(in srgb, var(--vk-kleur) 18%, #fff); color: #111827; } .vak-kaart.kleur-vlak .vk-naam { color: inherit; } .print-only { display: none; } .print-kop { display: flex; align-items: center; gap: 12px; margin: 0 0 8px; } @@ -635,7 +639,7 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .scope-persoon { max-width: 320px; } .scope-aantal { white-space: nowrap; } .rooster-edit .rooster-grid { grid-template-columns: repeat(5, minmax(210px, 1fr)); } -.rooster-view.details-compact .vak-kaart { min-height: 56px; height: 56px; padding-top: 7px; padding-bottom: 7px; } +.rooster-view.details-compact .vak-kaart { min-height: 72px; height: 72px; padding-bottom: 7px; } .rooster-view.details-compact .blok-splitsing { background: #fff; border-color: var(--line); } .rooster-view.details-compact .split-header { background: #fafbff; margin-bottom: 6px; } .details-compact .split-kolommen { gap: 6px; } @@ -644,7 +648,7 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .details-compact .split-title span { display: none; } .detail-compact .vk-meta, .detail-compact .rb-stage, .detail-compact .vk-opmerking { display: none; } .detail-normaal .vk-opmerking { display: none; } -.detail-uitgebreid .vak-kaart { min-height: 104px; height: 104px; } +.detail-uitgebreid .vak-kaart { min-height: 116px; height: 116px; } .detail-keuze .seg { padding: 7px 9px; font-size: 12px; } .rooster-edit .vak-kaart { background: #fff; } .rooster-edit .slot-add { opacity: .35; padding: 4px; } @@ -677,6 +681,8 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .legenda-swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; border: 1px solid rgba(0,0,0,.15); -webkit-print-color-adjust: exact; print-color-adjust: exact; } .vak-kaart.kleur-vlak .rb-greep, .vak-kaart.kleur-vlak .icon-btn { color: inherit; opacity: .85; } .vak-kaart.kleur-vlak .rb-status, .vak-kaart.kleur-vlak .rb-verv { color: inherit; } +.wm-vak.kleur-vlak { background: color-mix(in srgb, var(--vk-kleur) 18%, #fff) !important; color: #111827 !important; } +.wm-vak.kleur-vlak.in-conflict { background: #fff7f7 !important; color: #111827 !important; } .wm-vak.kleur-vlak .wm-vak-naam { color: inherit; } .wm-vak.kleur-vlak .wm-vak-meta, .wm-vak.kleur-vlak .muted { color: inherit; opacity: .85; } .wm-vak.kleur-vlak .icon-btn { color: inherit; opacity: .85; } @@ -718,6 +724,9 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px; .rooster-blok.in-conflict, .split-vak.in-conflict, .vak-kaart.in-conflict { - outline: 0; - box-shadow: inset 0 0 0 2px #ef4444, 0 1px 0 rgba(31,41,55,.03); + border-color: #dc2626; + background: #fff7f7; + outline: 3px dashed #dc2626; + outline-offset: -5px; + box-shadow: 0 0 0 2px #fff, 0 0 0 5px rgba(220,38,38,.28); }