Voeg thematische kleurplaten en creatieve niveaus toe (v0.4.65-beta) #3

Open
bes-r wants to merge 207 commits from bes-r/kleurplaten-v0-4-65 into main AGit
4 changed files with 51 additions and 50 deletions
Showing only changes of commit 08618ba0b3 - Show all commits

View file

@ -1 +1 @@
0.3.88-beta 0.3.89-beta

View file

@ -2017,7 +2017,7 @@ body.hc #settingsModal .am-inp, body.hc #settingsModal .am-sel{border-color:#000
#settingsModal .am-card:has(.am-card-subs[style*="none"]):not(:has(.am-card-tools:not([style*="none"]))) .am-card-head{border-bottom:none;} #settingsModal .am-card:has(.am-card-subs[style*="none"]):not(:has(.am-card-tools:not([style*="none"]))) .am-card-head{border-bottom:none;}
#settingsModal .am-ico{filter:grayscale(1); opacity:.55; font-size:13px; flex:none;} #settingsModal .am-ico{filter:grayscale(1); opacity:.55; font-size:13px; flex:none;}
#settingsModal .am-card-title{font-weight:650; font-size:13.5px; flex:1; min-width:80px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;} #settingsModal .am-card-title{font-weight:650; font-size:13.5px; flex:1; min-width:80px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#settingsModal .am-card-sum{margin-left:auto; flex:none; font-size:12px; color:var(--muted);} #settingsModal .am-card-sum{margin-left:auto; flex:0 1 auto; min-width:0; font-size:12px; color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
#settingsModal .am-card-toggle{cursor:pointer; user-select:none; padding:4px 6px; border-radius:5px;} #settingsModal .am-card-toggle{cursor:pointer; user-select:none; padding:4px 6px; border-radius:5px;}
#settingsModal .am-card-toggle:hover{background:var(--surface-3); color:var(--ink);} #settingsModal .am-card-toggle:hover{background:var(--surface-3); color:var(--ink);}
#settingsModal .am-card-tools{padding:10px 12px; border-bottom:1px solid var(--line); display:flex; flex-wrap:wrap; gap:10px;} #settingsModal .am-card-tools{padding:10px 12px; border-bottom:1px solid var(--line); display:flex; flex-wrap:wrap; gap:10px;}

View file

@ -478,9 +478,18 @@
/* 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){
const row = h("div","am-row" + (opts && opts.sub ? " am-row-sub" : "")); const compact = !!(opts && opts.compact);
const row = h("div","am-row" + (opts && opts.sub ? " am-row-sub" : "") + (compact ? " am-card-sub" : ""));
row.appendChild(h("span","am-name", u.displayName + (u.displayName!==u.username ? ` (${u.username})` : ""))); row.appendChild(h("span","am-name", u.displayName + (u.displayName!==u.username ? ` (${u.username})` : "")));
row.appendChild(h("span","am-role", T(roleKey(u.role)) + (u.pending ? ` · ${T("amPending")}` : ""))); if(compact){
/* compacte kaart-subrij: status als glyph met uitleg-title i.p.v. tekst */
row.appendChild(h("span","am-role", T(roleKey(u.role))));
const glyph = h("span","am-glyph" + (u.pending ? "" : " ok"), u.pending ? "○" : "●");
glyph.title = u.pending ? T("amPending") : T("amStatusActive");
row.appendChild(glyph);
}else{
row.appendChild(h("span","am-role", T(roleKey(u.role)) + (u.pending ? ` · ${T("amPending")}` : "")));
}
const tools = h("div","am-row-tools"); const tools = h("div","am-row-tools");
const badge = resultBadge(u); const badge = resultBadge(u);
if(badge) tools.appendChild(badge); if(badge) tools.appendChild(badge);
@ -754,16 +763,10 @@
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. */
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));
const row = h("div","am-row am-row-school"); /* bewerk-gereedschap van de school zelf (hernoemen/verwijderen) */
row.appendChild(h("span","am-name", s.name)); const tools = h("div","am-tools");
row.appendChild(h("span","am-role",
`${admins.length} ${(admins.length===1 ? T("amAdminOne") : T("amAdmins")).toLowerCase()}`));
/* zelfde -systeem als bij gebruikers: hernoemen en verwijderen
zitten achter het gereedschapsblok, de rij zelf blijft rustig */
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;
@ -784,27 +787,17 @@
}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")); /* één kader om de school en haar beheerders; beheerders standaard
edit.type = "button"; ingeklapt achter de teller, als compacte subrijen */
const key = "school:"+s.id; panel.appendChild(groupCard({
const sync = ()=>{ icon:"🏫",
const open = openRows.has(key); title:s.name,
tools.style.display = open ? "" : "none"; summary:`${admins.length} ${(admins.length===1 ? T("amAdminOne") : T("amAdmins")).toLowerCase()}`,
edit.classList.toggle("on", open); key:"schooladmins:"+s.id,
}; edit:{ key:"school:"+s.id, tools },
edit.addEventListener("click", ()=>{ subs: admins.map(a=>userRow(a, { sub:true, compact:true })),
if(openRows.has(key)) openRows.delete(key); else openRows.add(key); }));
sync();
});
sync();
row.appendChild(edit);
row.appendChild(tools);
list.appendChild(row);
/* de schoolbeheerders van deze school, duidelijk onderscheiden van de
schoolrij (ingesprongen) maar met hetzelfde bewerk-gereedschap */
admins.forEach(a=>list.appendChild(userRow(a, { sub:true })));
}); });
panel.appendChild(list);
const wrap = h("div","am-add-wrap"); const wrap = h("div","am-add-wrap");
const toggle = h("button","tbtn ghost", T("amNewSchool")); const toggle = h("button","tbtn ghost", T("amNewSchool"));
@ -864,12 +857,9 @@
const canResetPw = can("schools.resetPasswords"); const canResetPw = can("schools.resetPasswords");
/* klassen als volwaardige rijen (zelfde maat als de gebruikersvakken), /* klassen als volwaardige rijen (zelfde maat als de gebruikersvakken),
met de gevaarlijke acties als aparte, bevestigde knoppen */ met de gevaarlijke acties als aparte, bevestigde knoppen */
const list = h("div","am-list");
CLASSES.forEach(c=>{ CLASSES.forEach(c=>{
const row = h("div","am-row");
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;
row.appendChild(h("span","am-name", c.name)); let edit = null;
row.appendChild(h("span","am-role", `${pupilCount} ${(pupilCount===1 ? T("amPupilOne") : T("amPupils")).toLowerCase()}`));
if(canResetPw){ if(canResetPw){
const acts = h("div","am-actions"); const acts = h("div","am-actions");
acts.appendChild(dangerBtn(T("amResetClass"), "amConfirmReset", async ()=>{ acts.appendChild(dangerBtn(T("amResetClass"), "amConfirmReset", async ()=>{
@ -884,11 +874,16 @@
try{ await api("/admin/classes/"+c.id, {method:"DELETE"}); reload(); } try{ await api("/admin/classes/"+c.id, {method:"DELETE"}); reload(); }
catch(e){ msg(e.message); } catch(e){ msg(e.message); }
})); }));
row.appendChild(acts); const tools = h("div","am-tools");
tools.appendChild(field("amFieldActions", acts));
edit = { key:"klas:"+c.id, tools };
} }
list.appendChild(row); panel.appendChild(groupCard({
title:c.name,
summary:`${pupilCount} ${(pupilCount===1 ? T("amPupilOne") : T("amPupils")).toLowerCase()}`,
edit,
}));
}); });
panel.appendChild(list);
if(canResetPw){ if(canResetPw){
const f = h("div","am-add"); const f = h("div","am-add");
const inp = h("input","am-inp"); const inp = h("input","am-inp");
@ -947,8 +942,6 @@
return s; return s;
} }
function assignmentRow(target, boardOptions, current){ function assignmentRow(target, boardOptions, current){
const row = h("div","am-row");
row.appendChild(h("span","am-name", target.label));
const sel = h("select","am-sel"); const sel = h("select","am-sel");
sel.appendChild(new Option(T("amNoAssignment"), "")); sel.appendChild(new Option(T("amNoAssignment"), ""));
boardOptions.forEach(b=>sel.appendChild(new Option(b.label, b.id))); boardOptions.forEach(b=>sel.appendChild(new Option(b.label, b.id)));
@ -971,10 +964,6 @@
sel.addEventListener("change", syncWidgetSel); sel.addEventListener("change", syncWidgetSel);
widgetSel.addEventListener("change", syncModeSel); widgetSel.addEventListener("change", syncModeSel);
const info = h("span","am-code", describeCurrent(current)); const info = h("span","am-code", describeCurrent(current));
row.appendChild(sel);
row.appendChild(widgetSel);
row.appendChild(modeSel);
row.appendChild(info);
syncWidgetSel(); syncWidgetSel();
const apply = h("button","am-btn", T("amAssign")); const apply = h("button","am-btn", T("amAssign"));
apply.type = "button"; apply.type = "button";
@ -994,8 +983,20 @@
} }
}catch(e){ msg(e.message); } }catch(e){ msg(e.message); }
}); });
row.appendChild(apply); /* kop toont compact de huidige stand; de keuzes klappen uit via Bewerken */
return row; const tools = h("div","am-tools");
const inline = h("div","am-inline");
inline.appendChild(sel);
inline.appendChild(widgetSel);
inline.appendChild(modeSel);
inline.appendChild(apply);
tools.appendChild(inline);
tools.appendChild(info);
return groupCard({
title: target.label,
summary: describeCurrent(current) || T("amNoAssignment"),
edit: { key: "assign:"+target.type+":"+target.id, tools },
});
} }
/* vult een <select> met leerlingen gegroepeerd per klas (optgroup), gedeeld /* vult een <select> met leerlingen gegroepeerd per klas (optgroup), gedeeld

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.3.88-beta"; const VERSION = "0.3.89-beta";
(function(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;
@ -278,7 +278,7 @@ const I18N = {
amNewCodeWarn:"Maakt een nieuwe koppelcode aan. Het huidige wachtwoord vervalt direct; de gebruiker moet opnieuw activeren.", amNewCodeWarn:"Maakt een nieuwe koppelcode aan. Het huidige wachtwoord vervalt direct; de gebruiker moet opnieuw activeren.",
amDeleteWarn:"Verwijdert dit account definitief, inclusief borden en woorden.", amDeleteWarn:"Verwijdert dit account definitief, inclusief borden en woorden.",
amResultPw:"Nieuw wachtwoord", amResultCode:"Nieuwe koppelcode", amResultPw:"Nieuw wachtwoord", amResultCode:"Nieuwe koppelcode",
amColStatus:"Status", amNeverLoggedIn:"nog niet ingelogd", amFieldSchool:"School", amColStatus:"Status", amNeverLoggedIn:"nog niet ingelogd", amFieldSchool:"School", amStatusActive:"actief",
amDetailEmpty:"Selecteer links een gebruiker om te bewerken, of maak een nieuwe aan.", amDetailEmpty:"Selecteer links een gebruiker om te bewerken, of maak een nieuwe aan.",
amNewUser:"Nieuwe gebruiker", amRequestOne:"Aanmelding", amReqNew:"nieuw", amNewUser:"Nieuwe gebruiker", amRequestOne:"Aanmelding", amReqNew:"nieuw",
amParents:"Ouders", amParents:"Ouders",
@ -572,7 +572,7 @@ const I18N = {
amNewCodeWarn:"Generates a new link code. The current password stops working immediately; the user must re-activate.", amNewCodeWarn:"Generates a new link code. The current password stops working immediately; the user must re-activate.",
amDeleteWarn:"Deletes this account permanently, including boards and words.", amDeleteWarn:"Deletes this account permanently, including boards and words.",
amResultPw:"New password", amResultCode:"New link code", amResultPw:"New password", amResultCode:"New link code",
amColStatus:"Status", amNeverLoggedIn:"not signed in yet", amFieldSchool:"School", amColStatus:"Status", amNeverLoggedIn:"not signed in yet", amFieldSchool:"School", amStatusActive:"active",
amDetailEmpty:"Select a user on the left to edit, or create a new one.", amDetailEmpty:"Select a user on the left to edit, or create a new one.",
amNewUser:"New user", amRequestOne:"Enrolment", amReqNew:"new", amNewUser:"New user", amRequestOne:"Enrolment", amReqNew:"new",
amParents:"Parents", amParents:"Parents",