rooster-scope compacter + verbeterde weekscroll (weeknr+datumreeks) + icoon-tabbalken

This commit is contained in:
bes-r 2026-06-18 22:32:56 +02:00
parent 168c71d2fb
commit d2905dba71
2 changed files with 29 additions and 12 deletions

View file

@ -451,9 +451,9 @@ export function PersonenPage() {
<Foutmelding msg={error} />
<div className="tabbar">
<button className={!importView && modus === "leerling" ? "tab on" : "tab"} onClick={() => { kiesModus("leerling"); setImportView(false); }}>Leerling toevoegen</button>
<button className={!importView && modus === "medewerker" ? "tab on" : "tab"} onClick={() => { kiesModus("medewerker"); setImportView(false); }}>Medewerker toevoegen</button>
{wizardAan && <button className={importView ? "tab on" : "tab"} onClick={() => setImportView(true)}>📋 Bulk / CSV-import</button>}
<button className={!importView && modus === "leerling" ? "tab on" : "tab"} onClick={() => { kiesModus("leerling"); setImportView(false); }}><span className="ico">🧒</span><span className="tab-tekst">Leerling</span></button>
<button className={!importView && modus === "medewerker" ? "tab on" : "tab"} onClick={() => { kiesModus("medewerker"); setImportView(false); }}><span className="ico">🧑🏫</span><span className="tab-tekst">Medewerker</span></button>
{wizardAan && <button className={importView ? "tab on" : "tab"} onClick={() => setImportView(true)}><span className="ico">📋</span><span className="tab-tekst">Bulk / CSV-import</span></button>}
</div>
{importView ? <PersonenWizardPage /> : (<>
@ -1465,8 +1465,8 @@ export function GebruikersPage() {
<Foutmelding msg={error} />
{gegenereerd && <div className="banner ok">Tijdelijk wachtwoord: <code>{gegenereerd}</code> geef dit door aan de gebruiker; laat het daarna wijzigen.</div>}
<div className="tabbar">
<button className={view === "beheer" ? "tab on" : "tab"} onClick={() => setView("beheer")}>Beheer</button>
<button className={view === "import" ? "tab on" : "tab"} onClick={() => setView("import")}>📋 Bulk import</button>
<button className={view === "beheer" ? "tab on" : "tab"} onClick={() => setView("beheer")}><span className="ico">🔑</span><span className="tab-tekst">Beheer</span></button>
<button className={view === "import" ? "tab on" : "tab"} onClick={() => setView("import")}><span className="ico">📋</span><span className="tab-tekst">Bulk import</span></button>
</div>
{view === "import" ? <GebruikersImportWizard personen={personen} onKlaar={reload} /> : (<>
<form className="form-card" onSubmit={opslaan}>
@ -1550,6 +1550,21 @@ function Conflicten({ schooljaar }) {
function pad2(n) { return String(n).padStart(2, "0"); }
function fmtISO(d) { return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; }
function fmtDM(d) { return `${pad2(d.getDate())}-${pad2(d.getMonth() + 1)}`; }
const MAANDEN = ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"];
function isoWeeknr(d) {
const t = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
const dag = (t.getUTCDay() + 6) % 7;
t.setUTCDate(t.getUTCDate() - dag + 3);
const eersteDo = new Date(Date.UTC(t.getUTCFullYear(), 0, 4));
return 1 + Math.round(((t - eersteDo) / 86400000 - 3 + ((eersteDo.getUTCDay() + 6) % 7)) / 7);
}
function weekTitel(maandag) {
const vrij = plusDagen(maandag, 4);
const reeks = maandag.getMonth() === vrij.getMonth()
? `${maandag.getDate()}\u2013${vrij.getDate()} ${MAANDEN[vrij.getMonth()]}`
: `${maandag.getDate()} ${MAANDEN[maandag.getMonth()]} \u2013 ${vrij.getDate()} ${MAANDEN[vrij.getMonth()]}`;
return `Week ${isoWeeknr(maandag)} \u00b7 ${reeks}`;
}
function maandagVan(d) { const x = new Date(d); x.setHours(0, 0, 0, 0); const wd = (x.getDay() + 6) % 7; x.setDate(x.getDate() - wd); return x; }
function plusDagen(d, n) { const x = new Date(d); x.setDate(x.getDate() + n); return x; }
@ -2383,10 +2398,10 @@ export function RoosterScherm({ mode }) {
</label>
{schooljaar && (
<div className="week-nav">
<button className="btn" onClick={() => setMaandag(plusDagen(maandag, -7))}> vorige</button>
<button className="btn" onClick={() => setMaandag(maandagVan(new Date()))}>deze week</button>
<button className="btn" onClick={() => setMaandag(plusDagen(maandag, 7))}>volgende </button>
<span className="week-label">week van {fmtDM(maandag)}</span>
<button className="btn icon" title="Vorige week" aria-label="Vorige week" onClick={() => setMaandag(plusDagen(maandag, -7))}></button>
<span className="week-label">{weekTitel(maandag)}</span>
<button className="btn icon" title="Volgende week" aria-label="Volgende week" onClick={() => setMaandag(plusDagen(maandag, 7))}></button>
<button className="link small" title="Naar deze week" onClick={() => setMaandag(maandagVan(new Date()))}>vandaag</button>
</div>
)}
{edit && schooljaar && tab === "week" && <button className="btn primary icon-label" title="Vak toevoegen" onClick={toonForm ? sluitNieuwBlok : openNieuwBlok}>{toonForm ? "×" : ""} <span>{toonForm ? "Sluiten" : "Vak"}</span></button>}
@ -2406,7 +2421,7 @@ export function RoosterScherm({ mode }) {
<option value="personeel">Per personeel</option>
</select>
</label>
{scopeType !== "alles" && (
{(scopeType === "leerling" || scopeType === "personeel") && (
<select value={scopeId} onChange={(e) => setScopeId(e.target.value)}>
<option value=""> kies </option>
{scopeOpties.map((o) => <option key={o.id} value={o.id}>{o.naam || o.volledige_naam}</option>)}

View file

@ -152,7 +152,8 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
/* --- Fase 3: weekweergave, drag-and-drop, touch --- */
.rooster-balk { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 16px 0; }
.week-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.week-label { font-weight: 600; }
.week-label { font-weight: 700; min-width: 150px; text-align: center; }
.btn.icon { padding: 6px 12px; font-size: 18px; line-height: 1; }
.rooster-kolom.vrij { background: repeating-linear-gradient(45deg, #fafafa, #fafafa 8px, #f1f1f4 8px, #f1f1f4 16px); }
.rooster-dag .tag { display: inline-block; margin-top: 4px; }
@ -213,7 +214,8 @@ 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; }
.klas-strip { display: flex; flex-wrap: wrap; gap: 6px; flex-basis: 100%; }
.klas-strip { display: flex; flex-wrap: nowrap; gap: 6px; flex-basis: 100%; overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin; }
.klas-strip .chip { white-space: nowrap; flex: 0 0 auto; }
/* --- Blok-bewerker --- */
.blok-editor { margin-top: 8px; padding: 8px; border: 1px solid var(--line); border-radius: 8px; background: #f9fafb; cursor: default; }