diff --git a/VERSION b/VERSION index 93d4818..f038ebe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.12-beta +0.4.13-beta diff --git a/public/css/teach.css b/public/css/teach.css index 7a9e367..9c4d293 100644 --- a/public/css/teach.css +++ b/public/css/teach.css @@ -1271,11 +1271,13 @@ sectie, dus niet boven de allereerste kop van de pagina) */ .am-section{margin-bottom:14px;} .am-section + .am-h3{margin-top:22px; padding-top:16px; border-top:1px solid var(--line);} -/* Scholen is de enige sectie die niet zelf al een omkaderde lijst heeft - (Gebruikers heeft dat via .am-list) - een eigen paneel bindt de losse - schoolkaarten samen tot één zichtbaar geheel i.p.v. rijen die zomaar - overlopen in de sectie erna */ -.am-panel{background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius); padding:10px;} +/* hiërarchie via inspringing, niet via een andere kleur per niveau: alles + wat bij een klas hoort (Groepsleiding/Leerlingen, hun rijen en +-knoppen) + krijgt dezelfde lichte inspringing i.p.v. een eigen kadertje - dat hield + eerder te veel verschillende "boxstijlen" tegelijk in beeld. Specificiteit + moet #settingsModal .am-row's eigen margin:0 kunnen verslaan, ongeacht + bestandsvolgorde. */ +#settingsModal .am-list .am-indent{margin-left:18px;} .am-msg{ min-height:20px; font-size:13.5px; font-weight:700; color:var(--green); margin:4px 0; display:flex; align-items:center; gap:8px; flex-wrap:wrap; @@ -1328,10 +1330,10 @@ /* Systeem-tab: schoolrij duidelijk zwaarder dan de beheerder-subrijen */ .am-row-school{background:var(--accent-soft);} .am-row-school > .am-name{font-size:15px;} -/* klasrij (naam + klasbeheer) onderscheidt zich van de Groepsleiding/ - Leerlingen-rijen eronder - zelfde "kop, geen lid"-taal als .am-row-school */ -.am-classhead{background:var(--accent-soft); border-left:3px solid var(--accent);} -.am-classhead > .am-name{font-size:15px;} +/* klasrij (naam + klasbeheer): bewust géén eigen kleur/kader - alleen de + naam iets zwaarder, zodat klas/school/gebruiker-rijen overal dezelfde + visuele taal spreken en de hiërarchie via .am-indent hieronder loopt */ +.am-classhead > .am-name{font-size:15px; font-weight:700;} .am-row-sub{ margin-left:22px; background:var(--surface); border-left:3px solid var(--line); border-radius:var(--radius-s); diff --git a/public/js/admin.js b/public/js/admin.js index 132b17b..b84a5a1 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -30,6 +30,7 @@ database en kunnen dus samenvallen (klas 3 én gebruiker 3) - een gedeelde Set zou dan per ongeluk de verkeerde bewerktools open/dicht klappen */ const openClassTools = new Set(); + const openSchoolTools = new Set(); /* zelfde reden als hierboven */ /* welke rollen de ingelogde gebruiker mag aanmaken: unie over hoofdrol + extra rollen */ const creatableRoles = () => @@ -523,6 +524,29 @@ return tools; } + /* herbruikbaar "Bewerken"-knopje dat een tools-blok in-/uitklapt, gekoppeld + aan een gegeven Set + id. Gebruikers, klassen en scholen hebben elk hun + eigen Set (openRows/openClassTools/openSchoolTools) - hun id's zijn losse + reeksen in de database en kunnen samenvallen, dus nooit delen. Eén + gedeelde implementatie zorgt dat elke "Bewerken"-rij er overal identiek + uitziet en hetzelfde gedraagt, i.p.v. drie keer bijna-hetzelfde stukje + code met kleine, ongemerkt geslopen verschillen. */ + function editToggle(tools, set, id){ + const btn = h("button","am-edit", T("amEdit")); + btn.type = "button"; + const sync = ()=>{ + const open = set.has(id); + tools.style.display = open ? "" : "none"; + btn.classList.toggle("on", open); + }; + btn.addEventListener("click", ()=>{ + if(set.has(id)) set.delete(id); else set.add(id); + sync(); + }); + sync(); + return btn; + } + /* inline-variant voor het Systeem-tabblad (schoolbeheerder-subrijen): naam + rol met een "Bewerken"-tekstknop die het formulier uitklapt */ function userRow(u, opts){ @@ -542,19 +566,7 @@ const badge = resultBadge(u); if(badge) tools.appendChild(badge); tools.appendChild(userTools(u)); - const edit = h("button","am-edit", T("amEdit")); - edit.type = "button"; - const sync = ()=>{ - const open = openRows.has(u.id); - tools.style.display = open ? "" : "none"; - edit.classList.toggle("on", open); - }; - edit.addEventListener("click", ()=>{ - if(openRows.has(u.id)) openRows.delete(u.id); else openRows.add(u.id); - sync(); - }); - sync(); - row.appendChild(edit); + row.appendChild(editToggle(tools, openRows, u.id)); row.appendChild(tools); return row; } @@ -562,8 +574,10 @@ /* klasrij (naam + "Bewerken") binnen de gebruikerslijst: klasbeheer (verplaatsen naar een andere school, wachtwoorden resetten, verwijderen) staat zo letterlijk bij de klasleden eronder, i.p.v. in een los - klassenpaneel. Zelfde opzet als userRow() hierboven, met een eigen - openClassTools-Set (zie daar voor waarom). */ + klassenpaneel. Bewust een gewone rij (geen eigen kleur/kader) - alleen de + naam is iets zwaarder (zie css), zodat klas/school/gebruiker-rijen overal + dezelfde visuele taal spreken en de hiërarchie via inspringing loopt + i.p.v. via steeds een andere kleur per niveau. */ function classHeadRow(c, otherSchools, canManage){ const row = h("div","am-row am-classhead"); const pupilCount = USERS.filter(u=>u.role==="pupil" && Number(u.classId)===Number(c.id)).length; @@ -596,19 +610,7 @@ catch(e){ msg(e.message); } })); tools.appendChild(field("amFieldActions", acts)); - const edit = h("button","am-edit", T("amEdit")); - edit.type = "button"; - const sync = ()=>{ - const open = openClassTools.has(c.id); - tools.style.display = open ? "" : "none"; - edit.classList.toggle("on", open); - }; - edit.addEventListener("click", ()=>{ - if(openClassTools.has(c.id)) openClassTools.delete(c.id); else openClassTools.add(c.id); - sync(); - }); - sync(); - row.appendChild(edit); + row.appendChild(editToggle(tools, openClassTools, c.id)); row.appendChild(tools); return row; } @@ -897,11 +899,20 @@ niets op dit tabblad hangt van een gekozen school af. Toevoegen zit achter een bewuste extra stap (+-knop klapt het formulier uit, zoals bij gebruikers) en bevestigt daarna nog met de naam erin. */ + /* Scholen als platte rijenlijst - zelfde .am-list/.am-row-taal als de + klassen/gebruikers-boom eronder, i.p.v. een eigen kaartenstijl. De + beheerders van een school staan al in Gebruikers (gegroepeerd bij "alle + scholen"); ze hier óók als inklapbare subrijen tonen was een tweede, + overbodige plek voor dezelfde informatie en droeg bij aan het rommelige + gevoel van te veel verschillende niveaus. */ function renderScholenPanel(panel){ + const list = h("div","am-list"); SCHOOLS.forEach(s=>{ const admins = SYS_ADMINS.filter(a=>Number(a.schoolId)===Number(s.id)); - /* bewerk-gereedschap van de school zelf (hernoemen/verwijderen) */ - const tools = h("div","am-tools"); + const row = h("div","am-row"); + row.appendChild(h("span","am-name", s.name)); + row.appendChild(h("span","am-role", `${admins.length} ${(admins.length===1 ? T("amAdminOne") : T("amAdmins")).toLowerCase()}`)); + const tools = h("div","am-row-tools"); const nameInp = h("input","am-inp"); nameInp.value = s.name; nameInp.maxLength = 80; @@ -922,16 +933,9 @@ }catch(e){ msg(e.message); } })); tools.appendChild(field("amFieldActions", acts)); - /* één kader om de school en haar beheerders; beheerders standaard - ingeklapt achter de teller, als compacte subrijen */ - panel.appendChild(groupCard({ - icon:"🏫", - title:s.name, - summary:`${admins.length} ${(admins.length===1 ? T("amAdminOne") : T("amAdmins")).toLowerCase()}`, - key:"schooladmins:"+s.id, - edit:{ key:"school:"+s.id, tools }, - subs: admins.map(a=>userRow(a, { sub:true, compact:true })), - })); + row.appendChild(editToggle(tools, openSchoolTools, s.id)); + row.appendChild(tools); + list.appendChild(row); }); const wrap = h("div","am-add-wrap"); @@ -975,7 +979,8 @@ f.style.display = "flex"; inp.focus(); }); - panel.appendChild(wrap); + list.appendChild(wrap); + panel.appendChild(list); } /* Klassenbeheer zit niet meer in een los paneel: klasrij (classHeadRow) + @@ -1322,9 +1327,9 @@ const list = h("div","am-list am-userlist"); /* inklapbare groepskop; standaard dicht tenzij defaultOpen (dan onthoudt closedGroups een bewuste dichtklap). Zoeken kijkt door alle groepen heen. */ - const group = (key, label, us, defaultOpen)=>{ + const group = (key, label, us, defaultOpen, indent)=>{ if(defaultOpen && !closedGroups.has(key)) openGroups.add(key); - const g = h("div","am-group am-group-toggle"); + const g = h("div","am-group am-group-toggle" + (indent ? " am-indent" : "")); g.dataset.collapsible = "1"; g.dataset.gkey = key; const sync = ()=>{ g.textContent = `${openGroups.has(key) ? "▾" : "▸"} ${label} (${us.length})`; }; @@ -1336,7 +1341,11 @@ applyUserFilter(panel); }); list.appendChild(g); - us.forEach(u=>list.appendChild(userCells(u))); + us.forEach(u=>{ + const row = userCells(u); + if(indent) row.classList.add("am-indent"); + list.appendChild(row); + }); }; if(currentUser.role==="super" && !selSchool){ @@ -1377,11 +1386,19 @@ CLASSES.forEach(c=>{ list.appendChild(classHeadRow(c, otherSchools, canManageClasses)); const staff = USERS.filter(u=>u.role==="teacher" && (u.classIds||[]).some(id=>Number(id)===Number(c.id))); - if(staff.length || creatableRoles().includes("teacher")) group("classteachers:"+c.id, T("roleTeacher"), staff, true); - if(creatableRoles().includes("teacher")) list.appendChild(addForm("teacher", c.id)); + if(staff.length || creatableRoles().includes("teacher")) group("classteachers:"+c.id, T("roleTeacher"), staff, true, true); + if(creatableRoles().includes("teacher")){ + const w = addForm("teacher", c.id); + w.classList.add("am-indent"); + list.appendChild(w); + } const us = pupils.filter(u=>u.classId===c.id); - if(us.length || creatableRoles().includes("pupil")) group("class:"+c.id, T("amPupils"), us, true); - if(creatableRoles().includes("pupil")) list.appendChild(addForm("pupil", c.id)); + if(us.length || creatableRoles().includes("pupil")) group("class:"+c.id, T("amPupils"), us, true, true); + if(creatableRoles().includes("pupil")){ + const w = addForm("pupil", c.id); + w.classList.add("am-indent"); + list.appendChild(w); + } }); if(canManageClasses){ const f = h("div","am-add"); @@ -1460,11 +1477,7 @@ klassen hebben dus geen eigen kop/paneel meer hier. */ if(currentUser.role==="super" && !selSchool){ panel.appendChild(h("h3","am-h3", T("amSchools"))); - /* eigen kader om de hele Scholen-sectie: zonder dit oogt de lijst als - losse rijen die zomaar overlopen in de Gebruikers-sectie eronder - - met dezelfde schoolnaam soms letterlijk twee keer vlak onder elkaar - (als kaart hier, als groepskop daar) */ - const sub = h("div","am-section am-panel"); + const sub = h("div","am-section"); renderScholenPanel(sub); panel.appendChild(sub); } diff --git a/public/js/core.js b/public/js/core.js index 7f5dfea..0a1d2b4 100644 --- a/public/js/core.js +++ b/public/js/core.js @@ -2,7 +2,7 @@ "use strict"; /* version — shown until /api/version resolves (or if the fetch fails, e.g. offline). Kept in sync by hand with the VERSION file at the repo root on every release. */ -const VERSION = "0.4.12-beta"; +const VERSION = "0.4.13-beta"; (function(){ const tag = document.getElementById("verTag"); tag.textContent = "v"+VERSION;