Improve schedule UI clarity
This commit is contained in:
parent
c845588e5e
commit
958ace1536
3 changed files with 100 additions and 52 deletions
|
|
@ -23,6 +23,22 @@ const GROEP_ICON = { Rooster: "calendar", Organisatie: "users", Overzicht: "cloc
|
||||||
const GROEPSINDELING_PADEN = new Set(["/groepsindeling", "/structuur", "/leerplein", "/groepen", "/subgroepen"]);
|
const GROEPSINDELING_PADEN = new Set(["/groepsindeling", "/structuur", "/leerplein", "/groepen", "/subgroepen"]);
|
||||||
const GROEPSINDELING_ITEM = { label: "Groepsindeling", path: "/groepsindeling", icon: "layers", order: 24, group: "Organisatie" };
|
const GROEPSINDELING_ITEM = { label: "Groepsindeling", path: "/groepsindeling", icon: "layers", order: 24, group: "Organisatie" };
|
||||||
const normaliseerPad = (path) => (GROEPSINDELING_PADEN.has(path) ? "/groepsindeling" : path);
|
const normaliseerPad = (path) => (GROEPSINDELING_PADEN.has(path) ? "/groepsindeling" : path);
|
||||||
|
const ROLE_NAV = {
|
||||||
|
roostermaker: new Set(["/rooster", "/perioderooster", "/roostermaker", "/vervanging", "/afwezigheid", "/auto-rooster", "/vak-wizard"]),
|
||||||
|
directie: null,
|
||||||
|
zorgcoordinator: new Set(["/rooster", "/groepsindeling", "/personen", "/afwezigheid", "/stage", "/uren", "/portaal"]),
|
||||||
|
stagebegeleider: new Set(["/rooster", "/stage", "/afwezigheid", "/portaal"]),
|
||||||
|
medewerker: new Set(["/rooster", "/groepsindeling", "/afwezigheid", "/stage", "/uren", "/portaal"]),
|
||||||
|
kijker: new Set(["/rooster", "/uren", "/portaal"]),
|
||||||
|
ouder: new Set(["/portaal", "/ouderrooster"]),
|
||||||
|
leerling: new Set(["/portaal", "/leerlingrooster"]),
|
||||||
|
};
|
||||||
|
function magMenuZien(user, item) {
|
||||||
|
if (user.is_staff || user.role === "beheerder" || user.role === "directie") return true;
|
||||||
|
const allowed = ROLE_NAV[user.role];
|
||||||
|
if (!allowed) return true;
|
||||||
|
return allowed.has(normaliseerPad(item.path));
|
||||||
|
}
|
||||||
|
|
||||||
// Koppel een menu-pad aan een echt scherm. Onbekende paden tonen een
|
// Koppel een menu-pad aan een echt scherm. Onbekende paden tonen een
|
||||||
// placeholder (worden in een latere fase ingevuld).
|
// placeholder (worden in een latere fase ingevuld).
|
||||||
|
|
@ -261,16 +277,19 @@ function Shell({ user, onLogout }) {
|
||||||
if (isBeheerder) {
|
if (isBeheerder) {
|
||||||
voegToe({ label: "Modulebeheer", path: "/modules", icon: "gear", order: 9999, group: "Instellingen" });
|
voegToe({ label: "Modulebeheer", path: "/modules", icon: "gear", order: 9999, group: "Instellingen" });
|
||||||
}
|
}
|
||||||
const items = [...perPad.values()];
|
const items = [...perPad.values()].filter((item) => magMenuZien(user, item));
|
||||||
items.sort((a, b) => a.order - b.order);
|
items.sort((a, b) => a.order - b.order);
|
||||||
return {
|
return {
|
||||||
tabs: items.filter((i) => i.group !== "Instellingen"),
|
tabs: items.filter((i) => i.group !== "Instellingen"),
|
||||||
instellingenTabs: items.filter((i) => i.group === "Instellingen"),
|
instellingenTabs: items.filter((i) => i.group === "Instellingen"),
|
||||||
alleItems: items,
|
alleItems: items,
|
||||||
};
|
};
|
||||||
}, [modules, user.is_staff, user.role]);
|
}, [modules, user]);
|
||||||
|
|
||||||
const activePad = normaliseerPad(active);
|
const eerstePad = alleItems[0]?.path || "/rooster";
|
||||||
|
const activePad = normaliseerPad(
|
||||||
|
[...alleItems].some((item) => normaliseerPad(item.path) === normaliseerPad(active)) ? active : eerstePad
|
||||||
|
);
|
||||||
const Page = PAGES[activePad];
|
const Page = PAGES[activePad];
|
||||||
|
|
||||||
// Groepeer de hoofdtabs: groepen met meerdere items worden een dropdown,
|
// Groepeer de hoofdtabs: groepen met meerdere items worden een dropdown,
|
||||||
|
|
@ -391,7 +410,7 @@ function Shell({ user, onLogout }) {
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className={activePad === "/roostermaker" ? "content content-wide" : "content"}>
|
<main className={activePad === "/roostermaker" || activePad === "/rooster" ? "content content-wide" : "content"}>
|
||||||
{error && <div className="banner error">⚠ {error}</div>}
|
{error && <div className="banner error">⚠ {error}</div>}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<p>Laden…</p>
|
<p>Laden…</p>
|
||||||
|
|
|
||||||
|
|
@ -2087,6 +2087,8 @@ export function RoosterScherm({ mode }) {
|
||||||
const setWeergave = (v) => { setWeergaveState(v); try { localStorage.setItem("rw_weergave", v); } catch { /* niet beschikbaar */ } };
|
const setWeergave = (v) => { setWeergaveState(v); try { localStorage.setItem("rw_weergave", v); } catch { /* niet beschikbaar */ } };
|
||||||
const [vakkleurVlak, setVakkleurState] = useState(() => { try { return localStorage.getItem("rw_vakkleur") === "vlak"; } catch { return false; } });
|
const [vakkleurVlak, setVakkleurState] = useState(() => { try { return localStorage.getItem("rw_vakkleur") === "vlak"; } catch { return false; } });
|
||||||
const setVakkleur = (v) => { setVakkleurState(v); try { localStorage.setItem("rw_vakkleur", v ? "vlak" : "streep"); } catch { /* niet beschikbaar */ } };
|
const setVakkleur = (v) => { setVakkleurState(v); try { localStorage.setItem("rw_vakkleur", v ? "vlak" : "streep"); } catch { /* niet beschikbaar */ } };
|
||||||
|
const [detailsOpen, setDetailsOpenState] = useState(() => { try { return localStorage.getItem("rw_rooster_details") === "1"; } catch { return false; } });
|
||||||
|
const setDetailsOpen = (v) => { setDetailsOpenState(v); try { localStorage.setItem("rw_rooster_details", v ? "1" : "0"); } catch { /* niet beschikbaar */ } };
|
||||||
// Printopties
|
// Printopties
|
||||||
const [printOpen, setPrintOpen] = useState(false);
|
const [printOpen, setPrintOpen] = useState(false);
|
||||||
const [printPending, setPrintPending] = useState(false);
|
const [printPending, setPrintPending] = useState(false);
|
||||||
|
|
@ -2409,7 +2411,7 @@ export function RoosterScherm({ mode }) {
|
||||||
{edit && <button type="button" className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleOpenBlok(b); }} title="Bewerken">✎</button>}
|
{edit && <button type="button" className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleOpenBlok(b); }} title="Bewerken">✎</button>}
|
||||||
{edit && <button type="button" className="icon-btn danger rb-x" onClick={(e) => { e.stopPropagation(); verwijder(b.id); }} title="Blok verwijderen">×</button>}
|
{edit && <button type="button" className="icon-btn danger rb-x" onClick={(e) => { e.stopPropagation(); verwijder(b.id); }} title="Blok verwijderen">×</button>}
|
||||||
</div>
|
</div>
|
||||||
{(b.locatie_naam || b.lokaal_naam || b.begeleiders_namen.length > 0) && (
|
{(edit || detailsOpen) && (b.locatie_naam || b.lokaal_naam || b.begeleiders_namen.length > 0) && (
|
||||||
<div className="vk-meta">
|
<div className="vk-meta">
|
||||||
{b.locatie_naam && <span className="vk-tag t-loc">📍 {b.locatie_naam}</span>}
|
{b.locatie_naam && <span className="vk-tag t-loc">📍 {b.locatie_naam}</span>}
|
||||||
{b.lokaal_naam && <span className="vk-tag t-lok">🚪 {b.lokaal_naam}</span>}
|
{b.lokaal_naam && <span className="vk-tag t-lok">🚪 {b.lokaal_naam}</span>}
|
||||||
|
|
@ -2420,7 +2422,7 @@ export function RoosterScherm({ mode }) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{stageNoot(b)}
|
{(edit || detailsOpen) && stageNoot(b)}
|
||||||
{kal && <div className="small rb-status">Vervalt — {kal.type_label}</div>}
|
{kal && <div className="small rb-status">Vervalt — {kal.type_label}</div>}
|
||||||
{!kal && uit && uit.vervalt && <div className="small rb-status">Vervalt {uit.opmerking ? `(${uit.opmerking})` : ""}{edit && <button type="button" className="icon-btn" title="Herstellen" onClick={(e) => { e.stopPropagation(); herstel(uit.id); }}>↺</button>}</div>}
|
{!kal && uit && uit.vervalt && <div className="small rb-status">Vervalt {uit.opmerking ? `(${uit.opmerking})` : ""}{edit && <button type="button" className="icon-btn" title="Herstellen" onClick={(e) => { e.stopPropagation(); herstel(uit.id); }}>↺</button>}</div>}
|
||||||
{!kal && uit && !uit.vervalt && uit.vervanger_naam && <div className="small rb-verv">Vervanger: {uit.vervanger_naam}</div>}
|
{!kal && uit && !uit.vervalt && uit.vervanger_naam && <div className="small rb-verv">Vervanger: {uit.vervanger_naam}</div>}
|
||||||
|
|
@ -2533,7 +2535,7 @@ export function RoosterScherm({ mode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rooster-scherm">
|
<section className={"rooster-scherm " + (edit ? "rooster-edit " : "rooster-view ") + (detailsOpen ? "details-open" : "details-compact")}>
|
||||||
<div className="print-only print-kop">
|
<div className="print-only print-kop">
|
||||||
<RoosterLogo print />
|
<RoosterLogo print />
|
||||||
<div className="print-kop-tekst">
|
<div className="print-kop-tekst">
|
||||||
|
|
@ -2541,18 +2543,19 @@ export function RoosterScherm({ mode }) {
|
||||||
<span>{(schooljaren.find((j) => String(j.id) === String(schooljaar)) || {}).naam || ""}{schooljaar ? " · " : ""}{schooljaar ? weekTitel(maandag) : ""} · afgedrukt {fmtDM(new Date())}</span>
|
<span>{(schooljaren.find((j) => String(j.id) === String(schooljaar)) || {}).naam || ""}{schooljaar ? " · " : ""}{schooljaar ? weekTitel(maandag) : ""} · afgedrukt {fmtDM(new Date())}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rooster-kop">
|
<div className="rooster-kop app-page-kop">
|
||||||
|
<div>
|
||||||
<h1>{edit ? "Roostermaker" : "Rooster"}</h1>
|
<h1>{edit ? "Roostermaker" : "Rooster"}</h1>
|
||||||
|
<div className="page-subtitle no-print">
|
||||||
|
{schooljaar ? `${weekTitel(maandag)} · ${zichtbareBlokken.length} blokken zichtbaar` : "Kies een schooljaar"}
|
||||||
|
{conflictInfo.meldingen.length > 0 ? ` · ${conflictInfo.meldingen.length} conflicten` : ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<RoosterLogo />
|
<RoosterLogo />
|
||||||
</div>
|
</div>
|
||||||
<p className="muted no-print">
|
|
||||||
{edit
|
|
||||||
? "Sleep een blok naar een ander tijdslot om het te verplaatsen. Vrije dagen, afwezigheid en uitzonderingen worden meegenomen."
|
|
||||||
: "Bekijk het weekrooster. Vrije dagen, afwezigheid en uitzonderingen zijn verwerkt."}
|
|
||||||
</p>
|
|
||||||
<Foutmelding msg={error} />
|
<Foutmelding msg={error} />
|
||||||
|
|
||||||
<div className="rooster-balk no-print">
|
<div className="rooster-balk rooster-toolbar no-print">
|
||||||
<label className="veld">Schooljaar
|
<label className="veld">Schooljaar
|
||||||
<select value={schooljaar} onChange={(e) => setSchooljaar(e.target.value)}>
|
<select value={schooljaar} onChange={(e) => setSchooljaar(e.target.value)}>
|
||||||
<option value="">— kies —</option>
|
<option value="">— kies —</option>
|
||||||
|
|
@ -2571,6 +2574,7 @@ export function RoosterScherm({ mode }) {
|
||||||
<div className="weergave-opties no-print">
|
<div className="weergave-opties no-print">
|
||||||
<button type="button" className={weergave === "lijst" ? "icon-toggle on" : "icon-toggle"} aria-pressed={weergave === "lijst"} title={weergave === "kolom" ? "Dagen onder elkaar tonen" : "Dagen als kolommen tonen"} onClick={() => setWeergave(weergave === "kolom" ? "lijst" : "kolom")}>{weergave === "kolom" ? "☰" : "▦"}</button>
|
<button type="button" className={weergave === "lijst" ? "icon-toggle on" : "icon-toggle"} aria-pressed={weergave === "lijst"} title={weergave === "kolom" ? "Dagen onder elkaar tonen" : "Dagen als kolommen tonen"} onClick={() => setWeergave(weergave === "kolom" ? "lijst" : "kolom")}>{weergave === "kolom" ? "☰" : "▦"}</button>
|
||||||
<button type="button" className={vakkleurVlak ? "icon-toggle on" : "icon-toggle"} aria-pressed={vakkleurVlak} title={vakkleurVlak ? "Vakkleur als streepje tonen" : "Vak volledig in vakkleur tonen"} onClick={() => setVakkleur(!vakkleurVlak)}>🎨</button>
|
<button type="button" className={vakkleurVlak ? "icon-toggle on" : "icon-toggle"} aria-pressed={vakkleurVlak} title={vakkleurVlak ? "Vakkleur als streepje tonen" : "Vak volledig in vakkleur tonen"} onClick={() => setVakkleur(!vakkleurVlak)}>🎨</button>
|
||||||
|
<button type="button" className={detailsOpen ? "icon-toggle on" : "icon-toggle"} aria-pressed={detailsOpen} title={detailsOpen ? "Minder details tonen" : "Meer details tonen"} onClick={() => setDetailsOpen(!detailsOpen)}>ⓘ</button>
|
||||||
{printAan && <button type="button" className="icon-toggle" title="Afdrukken (met opties)" onClick={() => setPrintOpen(true)}>🖨</button>}
|
{printAan && <button type="button" className="icon-toggle" title="Afdrukken (met opties)" onClick={() => setPrintOpen(true)}>🖨</button>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -2638,9 +2642,7 @@ export function RoosterScherm({ mode }) {
|
||||||
<button className={tab === "instellingen" ? "tab on" : "tab"} title="Instellingen" onClick={() => setTab("instellingen")}><span className="ico">⚙</span><span className="tab-tekst">Instellingen</span></button>
|
<button className={tab === "instellingen" ? "tab on" : "tab"} title="Instellingen" onClick={() => setTab("instellingen")}><span className="ico">⚙</span><span className="tab-tekst">Instellingen</span></button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{edit && tab === "week" && (
|
{edit && tab === "week" && <div className="muted small no-print sneltoets-hint">N nieuw · pijltjes week · T vandaag · Esc sluiten</div>}
|
||||||
<p className="muted small no-print sneltoets-hint">Sneltoetsen: <b>N</b> nieuw blok · <b>←</b>/<b>→</b> week · <b>T</b> deze week · <b>Esc</b> sluiten</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{edit && schooljaar && tab === "week" && toonForm && (
|
{edit && schooljaar && tab === "week" && toonForm && (
|
||||||
<div className="modal-overlay no-print" onClick={sluitNieuwBlok}>
|
<div className="modal-overlay no-print" onClick={sluitNieuwBlok}>
|
||||||
|
|
@ -2770,14 +2772,19 @@ export function RoosterScherm({ mode }) {
|
||||||
<div className="rooster-dag">
|
<div className="rooster-dag">
|
||||||
{d.label} <span className="muted">{fmtDM(datum)}</span>
|
{d.label} <span className="muted">{fmtDM(datum)}</span>
|
||||||
{kal && <div className={`tag dag-${kal.type}`}>{kal.type_label}{kal.omschrijving ? `: ${kal.omschrijving}` : ""}</div>}
|
{kal && <div className={`tag dag-${kal.type}`}>{kal.type_label}{kal.omschrijving ? `: ${kal.omschrijving}` : ""}</div>}
|
||||||
{edit && (kal
|
{edit && (
|
||||||
? <button type="button" className="icon-btn no-print dag-actie" title="Weer lesdag maken" onClick={() => dagHerstel(kal.id)}>↺</button>
|
<span className="dag-acties no-print">
|
||||||
: <>
|
{kal ? (
|
||||||
<button type="button" className="icon-btn danger no-print dag-actie" title="Hele dag laten vervallen (vrije dag)" onClick={() => dagVervallen(iso)}>⊘</button>
|
<button type="button" className="icon-btn" title="Weer lesdag maken" onClick={() => dagHerstel(kal.id)}>↺</button>
|
||||||
<button type="button" className="icon-btn no-print dag-actie" title="Dag leegmaken (alleen deze dag)" onClick={() => leegDag(iso)}>🧹</button>
|
) : (
|
||||||
<button type="button" className="icon-btn no-print dag-actie" title="Eenmalig blok op deze dag toevoegen" onClick={() => openEenmalig(iso)}>➕</button>
|
<>
|
||||||
|
<button type="button" className="icon-btn danger" title="Hele dag laten vervallen" onClick={() => dagVervallen(iso)}>⊘</button>
|
||||||
|
<button type="button" className="icon-btn" title="Dag leegmaken" onClick={() => leegDag(iso)}>⌫</button>
|
||||||
|
<button type="button" className="icon-btn" title="Eenmalig blok toevoegen" onClick={() => openEenmalig(iso)}>+</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{slots.length === 0 && <div className="muted small">—</div>}
|
{slots.length === 0 && <div className="muted small">—</div>}
|
||||||
{slots.map((t) => {
|
{slots.map((t) => {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ body { margin: 0; font-family: system-ui, "Segoe UI", Roboto, sans-serif; color:
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
position: sticky; top: 0; z-index: 50;
|
position: sticky; top: 0; z-index: 50;
|
||||||
background: rgba(255,255,255,.96); backdrop-filter: blur(10px);
|
background: rgba(255,255,255,.97); backdrop-filter: blur(10px);
|
||||||
border-bottom: 1px solid var(--line);
|
border-bottom: 1px solid var(--line);
|
||||||
padding: 10px 24px 8px;
|
padding: 8px 24px 7px;
|
||||||
}
|
}
|
||||||
.topbar-main { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
|
.topbar-main { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 6px; }
|
||||||
.topbar-user { display: flex; align-items: center; gap: 10px; white-space: nowrap; }
|
.topbar-user { display: flex; align-items: center; gap: 10px; white-space: nowrap; }
|
||||||
.top-tabs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
.top-tabs { display: flex; align-items: center; gap: 4px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: thin; }
|
||||||
.top-tabs-settings { display: flex; align-items: center; gap: 6px; margin-left: auto; padding-left: 10px; border-left: 1px solid var(--line); }
|
.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) */
|
/* Instellingen als cog-menu (popover via hover of klik) */
|
||||||
|
|
@ -36,10 +36,10 @@ body { margin: 0; font-family: system-ui, "Segoe UI", Roboto, sans-serif; color:
|
||||||
.cog-item.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
|
.cog-item.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
|
||||||
.top-tab {
|
.top-tab {
|
||||||
display: inline-flex; align-items: center; gap: 8px;
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
min-height: 38px; flex: 0 0 auto;
|
min-height: 34px; flex: 0 0 auto;
|
||||||
border: 1px solid transparent; border-radius: 8px;
|
border: 1px solid transparent; border-radius: 8px;
|
||||||
background: transparent; color: var(--ink);
|
background: transparent; color: var(--ink);
|
||||||
padding: 8px 12px; font: inherit; font-size: 14px; cursor: pointer;
|
padding: 6px 10px; font: inherit; font-size: 13px; cursor: pointer;
|
||||||
}
|
}
|
||||||
.top-tab:hover { background: var(--bg); border-color: var(--line); }
|
.top-tab:hover { background: var(--bg); border-color: var(--line); }
|
||||||
.top-tab.active { background: var(--brand); color: #fff; border-color: var(--brand); font-weight: 700; }
|
.top-tab.active { background: var(--brand); color: #fff; border-color: var(--brand); font-weight: 700; }
|
||||||
|
|
@ -59,8 +59,8 @@ body { margin: 0; font-family: system-ui, "Segoe UI", Roboto, sans-serif; color:
|
||||||
.ico { width: 18px; text-align: center; }
|
.ico { width: 18px; text-align: center; }
|
||||||
.hint { margin-top: auto; font-size: 12px; color: var(--muted); padding: 12px 8px 0; }
|
.hint { margin-top: auto; font-size: 12px; color: var(--muted); padding: 12px 8px 0; }
|
||||||
|
|
||||||
.content { width: 100%; padding: 22px 24px 32px; }
|
.content { width: 100%; padding: 20px 24px 32px; }
|
||||||
.content-wide { padding-left: 18px; padding-right: 18px; }
|
.content-wide { padding: 14px 14px 28px; }
|
||||||
h1 { margin: 0 0 6px; font-size: 24px; }
|
h1 { margin: 0 0 6px; font-size: 24px; }
|
||||||
.muted { color: var(--muted); }
|
.muted { color: var(--muted); }
|
||||||
|
|
||||||
|
|
@ -147,14 +147,14 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
.tag.dag-vakantie { background: #dcfce7; color: #166534; }
|
.tag.dag-vakantie { background: #dcfce7; color: #166534; }
|
||||||
|
|
||||||
.rooster-scherm { width: 100%; }
|
.rooster-scherm { width: 100%; }
|
||||||
.rooster-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-top: 18px; width: 100%; }
|
.rooster-grid { display: grid; grid-template-columns: repeat(5, minmax(180px, 1fr)); gap: 8px; margin-top: 10px; width: 100%; }
|
||||||
/* "Dagen onder elkaar": elke dag een volledige band, tijdvakken naast elkaar; de week scrollt verticaal mee. */
|
/* "Dagen onder elkaar": elke dag een volledige band, tijdvakken naast elkaar; de week scrollt verticaal mee. */
|
||||||
.rooster-grid.lijst { display: flex; flex-direction: column; gap: 12px; }
|
.rooster-grid.lijst { display: flex; flex-direction: column; gap: 12px; }
|
||||||
.rooster-grid.lijst .rooster-kolom { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; }
|
.rooster-grid.lijst .rooster-kolom { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; }
|
||||||
.rooster-grid.lijst .rooster-dag { flex: 0 0 100%; text-align: left; padding-right: 32px; margin-bottom: 4px; }
|
.rooster-grid.lijst .rooster-dag { flex: 0 0 100%; text-align: left; padding-right: 32px; margin-bottom: 4px; }
|
||||||
.rooster-grid.lijst .slot-cel { flex: 1 1 210px; max-width: 320px; margin-bottom: 0; }
|
.rooster-grid.lijst .slot-cel { flex: 1 1 210px; max-width: 320px; margin-bottom: 0; }
|
||||||
.rooster-kolom { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 8px; min-height: 80px; }
|
.rooster-kolom { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 6px; min-height: 80px; }
|
||||||
.rooster-dag { position: relative; font-weight: 600; font-size: 13px; text-align: center; padding: 6px 32px 6px 0; border-bottom: 1px solid var(--line); margin-bottom: 8px; min-height: 36px; }
|
.rooster-dag { position: sticky; top: 92px; z-index: 3; background: var(--panel); font-weight: 700; font-size: 12px; text-align: left; padding: 5px 76px 7px 4px; border-bottom: 1px solid var(--line); margin-bottom: 6px; min-height: 34px; }
|
||||||
.rooster-blok { border: 1px solid var(--line); border-left: 4px solid var(--brand); border-radius: 8px; padding: 8px; margin-bottom: 8px; background: #fff; }
|
.rooster-blok { border: 1px solid var(--line); border-left: 4px solid var(--brand); border-radius: 8px; padding: 8px; margin-bottom: 8px; background: #fff; }
|
||||||
.rooster-blok.open { box-shadow: 0 0 0 2px var(--brand-soft); }
|
.rooster-blok.open { box-shadow: 0 0 0 2px var(--brand-soft); }
|
||||||
.rb-top { display: flex; justify-content: space-between; align-items: center; gap: 6px; }
|
.rb-top { display: flex; justify-content: space-between; align-items: center; gap: 6px; }
|
||||||
|
|
@ -163,17 +163,18 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
@media (max-width: 900px) { .rooster-grid { grid-template-columns: 1fr; } }
|
@media (max-width: 900px) { .rooster-grid { grid-template-columns: 1fr; } }
|
||||||
|
|
||||||
/* --- Fase 3: weekweergave, drag-and-drop, touch --- */
|
/* --- Fase 3: weekweergave, drag-and-drop, touch --- */
|
||||||
.rooster-balk { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 16px 0; }
|
.rooster-balk { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 10px 0; }
|
||||||
|
.rooster-toolbar { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
|
||||||
.week-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
.week-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||||
.week-label { font-weight: 700; min-width: 150px; text-align: center; }
|
.week-label { font-weight: 700; min-width: 138px; text-align: center; font-size: 13px; }
|
||||||
.btn.icon { padding: 6px 12px; font-size: 18px; line-height: 1; }
|
.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-kolom.vrij { background: repeating-linear-gradient(45deg, #fafafa, #fafafa 8px, #f1f1f4 8px, #f1f1f4 16px); }
|
||||||
.rooster-dag .tag { display: inline-block; margin-top: 4px; }
|
.rooster-dag .tag { display: inline-block; margin-top: 4px; }
|
||||||
|
|
||||||
.slot-cel { border: 1px dashed transparent; border-radius: 8px; padding: 4px; margin-bottom: 8px; transition: background .1s, border-color .1s; }
|
.slot-cel { border: 1px dashed transparent; border-radius: 7px; padding: 3px; margin-bottom: 6px; transition: background .1s, border-color .1s; }
|
||||||
.slot-cel.hover { border-color: var(--brand); background: var(--brand-soft); }
|
.slot-cel.hover { border-color: var(--brand); background: var(--brand-soft); }
|
||||||
.slot-tijd { font-size: 11px; color: var(--muted); padding: 2px 2px 4px; }
|
.slot-tijd { font-size: 10px; color: var(--muted); padding: 1px 2px 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
/* Snel een vak toevoegen direct in een tijdvak */
|
/* Snel een vak toevoegen direct in een tijdvak */
|
||||||
.slot-add { width: 100%; margin-top: 4px; border: 1px dashed var(--line); background: transparent; color: var(--muted); border-radius: 8px; padding: 5px; font: inherit; font-size: 12px; cursor: pointer; opacity: .55; transition: opacity .1s, border-color .1s, color .1s, background .1s; }
|
.slot-add { width: 100%; margin-top: 4px; border: 1px dashed var(--line); background: transparent; color: var(--muted); border-radius: 8px; padding: 5px; font: inherit; font-size: 12px; cursor: pointer; opacity: .55; transition: opacity .1s, border-color .1s, color .1s, background .1s; }
|
||||||
.slot-cel:hover .slot-add, .slot-add:focus-visible { opacity: 1; }
|
.slot-cel:hover .slot-add, .slot-add:focus-visible { opacity: 1; }
|
||||||
|
|
@ -204,7 +205,8 @@ 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); }
|
||||||
|
|
||||||
.dag-actie { position: absolute; right: 0; top: 3px; margin: 0; }
|
.dag-acties { position: absolute; right: 2px; top: 3px; display: inline-flex; gap: 2px; background: rgba(255,255,255,.88); border-radius: 6px; }
|
||||||
|
.dag-acties .icon-btn { width: 22px; height: 22px; font-size: 12px; }
|
||||||
.sneltoets-hint { margin: -4px 0 12px; }
|
.sneltoets-hint { margin: -4px 0 12px; }
|
||||||
|
|
||||||
/* --- Groepsindeling --- */
|
/* --- Groepsindeling --- */
|
||||||
|
|
@ -243,15 +245,15 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
/* Eén uniform vak-kaartje (overal gelijk) + klas-kop-container */
|
/* 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 { background: linear-gradient(180deg, #eff6ff 0, #f8fbff 40px, #fff 100%); }
|
||||||
.blok-splitsing.enkel .split-header { margin-bottom: 8px; }
|
.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 { position: relative; border: 1px solid var(--line); border-left: 4px solid var(--brand); border-radius: 7px; background: #fff; padding: 6px 7px; cursor: default; box-shadow: 0 1px 0 rgba(31,41,55,.03); touch-action: none; }
|
||||||
.vak-kaart.klikbaar { cursor: pointer; }
|
.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); }
|
||||||
.vak-kaart.vervallen { opacity: .55; }
|
.vak-kaart.vervallen { opacity: .55; }
|
||||||
.vak-kaart.vervallen .vk-naam { text-decoration: line-through; }
|
.vak-kaart.vervallen .vk-naam { text-decoration: line-through; }
|
||||||
.vk-kop { display: flex; align-items: center; gap: 5px; }
|
.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-naam { min-width: 0; flex: 1; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.vk-meta { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 5px; }
|
.vk-meta { display: flex; flex-wrap: wrap; gap: 3px 5px; 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%; }
|
.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%; }
|
||||||
@media print { .blok-splitsing.enkel { background: #fff; } }
|
@media print { .blok-splitsing.enkel { background: #fff; } }
|
||||||
.klas-strip { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }
|
.klas-strip { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }
|
||||||
|
|
||||||
|
|
@ -309,14 +311,8 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
.modal-hr { border: 0; border-top: 1px solid var(--line); margin: 16px 0 12px; }
|
.modal-hr { border: 0; border-top: 1px solid var(--line); margin: 16px 0 12px; }
|
||||||
.rooster-blok.klikbaar { cursor: pointer; }
|
.rooster-blok.klikbaar { cursor: pointer; }
|
||||||
.rooster-blok.klikbaar:hover { box-shadow: 0 0 0 2px var(--brand-soft); }
|
.rooster-blok.klikbaar:hover { box-shadow: 0 0 0 2px var(--brand-soft); }
|
||||||
.scope-balk { margin-top: -6px; flex-direction: column; align-items: stretch; gap: 10px; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; }
|
.scope-persoon { flex: 0 0 auto; min-height: 34px; }
|
||||||
.scope-rij { display: flex; align-items: center; gap: 10px; }
|
|
||||||
.scope-label { color: var(--muted); font-size: 13px; font-weight: 600; flex: 0 0 auto; width: 104px; text-align: right; white-space: nowrap; }
|
|
||||||
.klas-strip .chip { white-space: nowrap; flex: 0 0 auto; min-width: 62px; display: inline-flex; align-items: center; justify-content: center; min-height: 34px; }
|
|
||||||
.klas-strip .chip.chip-plein { min-width: 96px; }
|
|
||||||
.scope-persoon { flex: 0 0 auto; max-width: 300px; min-height: 34px; }
|
|
||||||
.scope-persoon.on { border-color: var(--brand); color: var(--brand); font-weight: 600; }
|
.scope-persoon.on { border-color: var(--brand); color: var(--brand); font-weight: 600; }
|
||||||
.scope-aantal { flex: 0 0 auto; white-space: nowrap; }
|
|
||||||
|
|
||||||
/* --- Afdrukken --- */
|
/* --- Afdrukken --- */
|
||||||
.print-knop { margin-left: auto; background: #fff; }
|
.print-knop { margin-left: auto; background: #fff; }
|
||||||
|
|
@ -593,6 +589,32 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
||||||
/* Schoollogo in de roosterweergave */
|
/* Schoollogo in de roosterweergave */
|
||||||
.rooster-kop { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
.rooster-kop { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||||
.rooster-logo { max-height: 40px; max-width: 150px; object-fit: contain; }
|
.rooster-logo { max-height: 40px; max-width: 150px; object-fit: contain; }
|
||||||
|
.app-page-kop { margin-bottom: 8px; }
|
||||||
|
.page-subtitle { color: var(--muted); font-size: 13px; margin-top: 2px; }
|
||||||
|
.rooster-scherm h1 { margin-bottom: 0; }
|
||||||
|
.rooster-scherm .veld { gap: 8px; }
|
||||||
|
.rooster-scherm select { min-width: 0; }
|
||||||
|
.scope-balk { align-items: stretch; background: transparent; border: 0; padding: 0; margin-top: 6px; }
|
||||||
|
.scope-rij { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 360px; }
|
||||||
|
.scope-label { flex: none; font-size: 11px; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
|
||||||
|
.scope-balk .klas-strip { display: flex; flex-wrap: nowrap; gap: 6px; overflow-x: auto; padding: 2px 2px 7px; scrollbar-width: thin; }
|
||||||
|
.scope-balk .chip { flex: 0 0 auto; padding: 4px 9px; font-size: 12px; }
|
||||||
|
.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 { padding-top: 7px; 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; }
|
||||||
|
.details-compact .split-vakken { gap: 5px; }
|
||||||
|
.details-compact .rb-picto { height: 18px; width: 18px; }
|
||||||
|
.details-compact .split-title span,
|
||||||
|
.details-compact .split-count { display: none; }
|
||||||
|
.rooster-edit .vak-kaart { background: #fff; }
|
||||||
|
.rooster-edit .slot-add { opacity: .35; padding: 4px; }
|
||||||
|
.rooster-edit .slot-cel:hover .slot-add { opacity: 1; }
|
||||||
|
.rooster-edit .rooster-kolom { background: #fbfcff; }
|
||||||
|
.sneltoets-hint { margin: -2px 0 8px; text-align: right; }
|
||||||
|
|
||||||
/* Huisstijl-pagina: logo-upload + voorbeeld op geruite achtergrond */
|
/* Huisstijl-pagina: logo-upload + voorbeeld op geruite achtergrond */
|
||||||
.huisstijl .logo-vak { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; margin: 10px 0; }
|
.huisstijl .logo-vak { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; margin: 10px 0; }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue