Voeg 28 herkenbare kleurplaten en creatieve niveaus toe (v0.4.66-beta) #4

Open
bes-r wants to merge 207 commits from bes-r/kleurplaten-v0-4-66 into main AGit
4 changed files with 79 additions and 64 deletions
Showing only changes of commit 8580e46f4c - Show all commits

View file

@ -1 +1 @@
0.4.12-beta 0.4.13-beta

View file

@ -1271,11 +1271,13 @@
sectie, dus niet boven de allereerste kop van de pagina) */ sectie, dus niet boven de allereerste kop van de pagina) */
.am-section{margin-bottom:14px;} .am-section{margin-bottom:14px;}
.am-section + .am-h3{margin-top:22px; padding-top:16px; border-top:1px solid var(--line);} .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 /* hiërarchie via inspringing, niet via een andere kleur per niveau: alles
(Gebruikers heeft dat via .am-list) - een eigen paneel bindt de losse wat bij een klas hoort (Groepsleiding/Leerlingen, hun rijen en +-knoppen)
schoolkaarten samen tot één zichtbaar geheel i.p.v. rijen die zomaar krijgt dezelfde lichte inspringing i.p.v. een eigen kadertje - dat hield
overlopen in de sectie erna */ eerder te veel verschillende "boxstijlen" tegelijk in beeld. Specificiteit
.am-panel{background:var(--surface-2); border:1px solid var(--line); border-radius:var(--radius); padding:10px;} moet #settingsModal .am-row's eigen margin:0 kunnen verslaan, ongeacht
bestandsvolgorde. */
#settingsModal .am-list .am-indent{margin-left:18px;}
.am-msg{ .am-msg{
min-height:20px; font-size:13.5px; font-weight:700; color:var(--green); margin:4px 0; 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; display:flex; align-items:center; gap:8px; flex-wrap:wrap;
@ -1328,10 +1330,10 @@
/* Systeem-tab: schoolrij duidelijk zwaarder dan de beheerder-subrijen */ /* Systeem-tab: schoolrij duidelijk zwaarder dan de beheerder-subrijen */
.am-row-school{background:var(--accent-soft);} .am-row-school{background:var(--accent-soft);}
.am-row-school > .am-name{font-size:15px;} .am-row-school > .am-name{font-size:15px;}
/* klasrij (naam + klasbeheer) onderscheidt zich van de Groepsleiding/ /* klasrij (naam + klasbeheer): bewust géén eigen kleur/kader - alleen de
Leerlingen-rijen eronder - zelfde "kop, geen lid"-taal als .am-row-school */ naam iets zwaarder, zodat klas/school/gebruiker-rijen overal dezelfde
.am-classhead{background:var(--accent-soft); border-left:3px solid var(--accent);} visuele taal spreken en de hiërarchie via .am-indent hieronder loopt */
.am-classhead > .am-name{font-size:15px;} .am-classhead > .am-name{font-size:15px; font-weight:700;}
.am-row-sub{ .am-row-sub{
margin-left:22px; background:var(--surface); margin-left:22px; background:var(--surface);
border-left:3px solid var(--line); border-radius:var(--radius-s); border-left:3px solid var(--line); border-radius:var(--radius-s);

View file

@ -30,6 +30,7 @@
database en kunnen dus samenvallen (klas 3 én gebruiker 3) - een gedeelde database en kunnen dus samenvallen (klas 3 én gebruiker 3) - een gedeelde
Set zou dan per ongeluk de verkeerde bewerktools open/dicht klappen */ Set zou dan per ongeluk de verkeerde bewerktools open/dicht klappen */
const openClassTools = new Set(); const openClassTools = new Set();
const openSchoolTools = new Set(); /* zelfde reden als hierboven */
/* welke rollen de ingelogde gebruiker mag aanmaken: unie over hoofdrol + extra rollen */ /* welke rollen de ingelogde gebruiker mag aanmaken: unie over hoofdrol + extra rollen */
const creatableRoles = () => const creatableRoles = () =>
@ -523,6 +524,29 @@
return tools; 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): /* inline-variant voor het Systeem-tabblad (schoolbeheerder-subrijen):
naam + rol met een "Bewerken"-tekstknop die het formulier uitklapt */ naam + rol met een "Bewerken"-tekstknop die het formulier uitklapt */
function userRow(u, opts){ function userRow(u, opts){
@ -542,19 +566,7 @@
const badge = resultBadge(u); const badge = resultBadge(u);
if(badge) tools.appendChild(badge); if(badge) tools.appendChild(badge);
tools.appendChild(userTools(u)); tools.appendChild(userTools(u));
const edit = h("button","am-edit", T("amEdit")); row.appendChild(editToggle(tools, openRows, u.id));
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(tools); row.appendChild(tools);
return row; return row;
} }
@ -562,8 +574,10 @@
/* klasrij (naam + "Bewerken") binnen de gebruikerslijst: klasbeheer /* klasrij (naam + "Bewerken") binnen de gebruikerslijst: klasbeheer
(verplaatsen naar een andere school, wachtwoorden resetten, verwijderen) (verplaatsen naar een andere school, wachtwoorden resetten, verwijderen)
staat zo letterlijk bij de klasleden eronder, i.p.v. in een los staat zo letterlijk bij de klasleden eronder, i.p.v. in een los
klassenpaneel. Zelfde opzet als userRow() hierboven, met een eigen klassenpaneel. Bewust een gewone rij (geen eigen kleur/kader) - alleen de
openClassTools-Set (zie daar voor waarom). */ 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){ function classHeadRow(c, otherSchools, canManage){
const row = h("div","am-row am-classhead"); const row = h("div","am-row am-classhead");
const pupilCount = USERS.filter(u=>u.role==="pupil" && Number(u.classId)===Number(c.id)).length; const pupilCount = USERS.filter(u=>u.role==="pupil" && Number(u.classId)===Number(c.id)).length;
@ -596,19 +610,7 @@
catch(e){ msg(e.message); } catch(e){ msg(e.message); }
})); }));
tools.appendChild(field("amFieldActions", acts)); tools.appendChild(field("amFieldActions", acts));
const edit = h("button","am-edit", T("amEdit")); row.appendChild(editToggle(tools, openClassTools, c.id));
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(tools); row.appendChild(tools);
return row; return row;
} }
@ -897,11 +899,20 @@
niets op dit tabblad hangt van een gekozen school af. Toevoegen zit niets op dit tabblad hangt van een gekozen school af. Toevoegen zit
achter een bewuste extra stap (-knop klapt het formulier uit, zoals achter een bewuste extra stap (-knop klapt het formulier uit, zoals
bij gebruikers) en bevestigt daarna nog met de naam erin. */ 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){ function renderScholenPanel(panel){
const list = h("div","am-list");
SCHOOLS.forEach(s=>{ SCHOOLS.forEach(s=>{
const admins = SYS_ADMINS.filter(a=>Number(a.schoolId)===Number(s.id)); const admins = SYS_ADMINS.filter(a=>Number(a.schoolId)===Number(s.id));
/* bewerk-gereedschap van de school zelf (hernoemen/verwijderen) */ const row = h("div","am-row");
const tools = h("div","am-tools"); 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"); const nameInp = h("input","am-inp");
nameInp.value = s.name; nameInp.value = s.name;
nameInp.maxLength = 80; nameInp.maxLength = 80;
@ -922,16 +933,9 @@
}catch(e){ msg(e.message); } }catch(e){ msg(e.message); }
})); }));
tools.appendChild(field("amFieldActions", acts)); tools.appendChild(field("amFieldActions", acts));
/* één kader om de school en haar beheerders; beheerders standaard row.appendChild(editToggle(tools, openSchoolTools, s.id));
ingeklapt achter de teller, als compacte subrijen */ row.appendChild(tools);
panel.appendChild(groupCard({ list.appendChild(row);
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 })),
}));
}); });
const wrap = h("div","am-add-wrap"); const wrap = h("div","am-add-wrap");
@ -975,7 +979,8 @@
f.style.display = "flex"; f.style.display = "flex";
inp.focus(); inp.focus();
}); });
panel.appendChild(wrap); list.appendChild(wrap);
panel.appendChild(list);
} }
/* Klassenbeheer zit niet meer in een los paneel: klasrij (classHeadRow) + /* Klassenbeheer zit niet meer in een los paneel: klasrij (classHeadRow) +
@ -1322,9 +1327,9 @@
const list = h("div","am-list am-userlist"); const list = h("div","am-list am-userlist");
/* inklapbare groepskop; standaard dicht tenzij defaultOpen (dan onthoudt /* inklapbare groepskop; standaard dicht tenzij defaultOpen (dan onthoudt
closedGroups een bewuste dichtklap). Zoeken kijkt door alle groepen heen. */ 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); 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.collapsible = "1";
g.dataset.gkey = key; g.dataset.gkey = key;
const sync = ()=>{ g.textContent = `${openGroups.has(key) ? "▾" : "▸"} ${label} (${us.length})`; }; const sync = ()=>{ g.textContent = `${openGroups.has(key) ? "▾" : "▸"} ${label} (${us.length})`; };
@ -1336,7 +1341,11 @@
applyUserFilter(panel); applyUserFilter(panel);
}); });
list.appendChild(g); 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){ if(currentUser.role==="super" && !selSchool){
@ -1377,11 +1386,19 @@
CLASSES.forEach(c=>{ CLASSES.forEach(c=>{
list.appendChild(classHeadRow(c, otherSchools, canManageClasses)); list.appendChild(classHeadRow(c, otherSchools, canManageClasses));
const staff = USERS.filter(u=>u.role==="teacher" && (u.classIds||[]).some(id=>Number(id)===Number(c.id))); 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(staff.length || creatableRoles().includes("teacher")) group("classteachers:"+c.id, T("roleTeacher"), staff, true, true);
if(creatableRoles().includes("teacher")) list.appendChild(addForm("teacher", c.id)); 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); const us = pupils.filter(u=>u.classId===c.id);
if(us.length || creatableRoles().includes("pupil")) group("class:"+c.id, T("amPupils"), us, true); if(us.length || creatableRoles().includes("pupil")) group("class:"+c.id, T("amPupils"), us, true, true);
if(creatableRoles().includes("pupil")) list.appendChild(addForm("pupil", c.id)); if(creatableRoles().includes("pupil")){
const w = addForm("pupil", c.id);
w.classList.add("am-indent");
list.appendChild(w);
}
}); });
if(canManageClasses){ if(canManageClasses){
const f = h("div","am-add"); const f = h("div","am-add");
@ -1460,11 +1477,7 @@
klassen hebben dus geen eigen kop/paneel meer hier. */ klassen hebben dus geen eigen kop/paneel meer hier. */
if(currentUser.role==="super" && !selSchool){ if(currentUser.role==="super" && !selSchool){
panel.appendChild(h("h3","am-h3", T("amSchools"))); panel.appendChild(h("h3","am-h3", T("amSchools")));
/* eigen kader om de hele Scholen-sectie: zonder dit oogt de lijst als const sub = h("div","am-section");
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");
renderScholenPanel(sub); renderScholenPanel(sub);
panel.appendChild(sub); panel.appendChild(sub);
} }

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
/* version shown until /api/version resolves (or if the fetch fails, e.g. offline). /* 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. */ 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(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;