diff --git a/VERSION b/VERSION index f11c412..c8b0afe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.34-beta +0.3.35-beta diff --git a/public/css/teach.css b/public/css/teach.css index 870c31a..51c6726 100644 --- a/public/css/teach.css +++ b/public/css/teach.css @@ -1164,13 +1164,27 @@ } .am-edit:hover{opacity:1; background:var(--surface-3);} .am-edit.on{opacity:1; background:var(--accent-soft);} +/* uniforme maat: álle knoppen en velden in het beheer op controlhoogte, + zodat formulieren en actieknoppen in elke rij gelijk uitlijnen */ +#adminModal .tbtn{ + min-height:var(--control-h); height:var(--control-h); + padding:0 14px; font-size:14px; +} /* één interactiesysteem: mini-label boven elk veld/select/knopgroep */ -.am-field{display:flex; flex-direction:column; gap:3px;} +.am-field{display:flex; flex-direction:column; gap:3px; min-width:0;} .am-field-lbl{ font-size:10.5px; font-weight:800; color:var(--muted); text-transform:uppercase; letter-spacing:.4px; } +/* de rij-flexregels van .am-inp (flex-basis 0/100%) gelden binnen de + kolom-flex van het label verticaal en drukten het veld plat - binnenin + een veldlabel dus altijd de vaste controlhoogte, breedte via het label */ +.am-field > .am-inp, .am-field > .am-sel, .am-field > .am-pw, .am-field > .am-inline, +.am-field > .am-classes, .am-field > .am-actions{flex:none; width:100%;} +.am-add .am-field{flex:1 1 100%;} +.am-row-tools .am-field{flex:0 1 auto; min-width:150px;} .am-inline{display:flex; gap:6px; align-items:center;} +.am-inline > .am-inp, .am-inline > .am-pw{flex:1 1 auto; min-width:0;} /* gevaarlijke acties: afwijkende kleur + tweede klik als bevestiging */ .am-btn.am-danger{background:var(--red-soft); color:var(--red); font-weight:800;} .am-btn.am-danger.armed{background:var(--red); color:#fff;} diff --git a/public/js/admin.js b/public/js/admin.js index a2eaad3..e7f52c2 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -419,21 +419,40 @@ return box; } - /* systeem: nieuwe school + systeemmanagers beheren. Dit tabblad is waar een - super zaken regelt die niet aan één school vastzitten; de schoolkiezer- - contextbalk wordt hier juist verborgen (zie switchAdminTab), want niets - op dit tabblad hangt van een gekozen school af. Een school aanmaken is - bewust een twee-staps-actie: de knop wordt pas actief bij een echte naam - en vraagt daarna een bevestigende tweede klik (typefout-bescherming). */ + /* systeem: overzicht van alle scholen + nieuwe school + systeemmanagers. + De schoolkiezer-contextbalk is hier verborgen (zie switchAdminTab), want + 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. */ function renderScholenPanel(panel){ - panel.appendChild(h("div","am-h3", T("amNewSchool"))); - panel.appendChild(h("div","guestnote", T("amNewSchoolDesc"))); - const bar = h("div","am-add"); + const list = h("div","am-list"); + SCHOOLS.forEach(s=>{ + const row = h("div","am-row"); + row.appendChild(h("span","am-name", s.name)); + const acts = h("div","am-actions"); + acts.appendChild(dangerBtn("🗑 " + T("amDelete"), "amDeleteSchoolWarn", async ()=>{ + try{ + await api("/admin/schools/"+s.id, {method:"DELETE"}); + if(String(selSchool)===String(s.id)) selSchool = ""; + reload(); + }catch(e){ msg(e.message); } + })); + row.appendChild(acts); + list.appendChild(row); + }); + panel.appendChild(list); + + const wrap = h("div","am-add-wrap"); + const toggle = h("button","tbtn ghost", T("amNewSchool")); + toggle.type = "button"; + wrap.appendChild(toggle); + const f = h("div","am-add"); + f.style.display = "none"; const inp = h("input","am-inp"); inp.placeholder = T("amSchoolNamePh"); inp.maxLength = 80; inp.addEventListener("keydown", ev=>ev.stopPropagation()); - bar.appendChild(field("amFieldName", inp)); + f.appendChild(field("amFieldName", inp)); const add = h("button","tbtn", T("amNewSchool")); add.type = "button"; add.disabled = true; @@ -456,16 +475,19 @@ reload(); }catch(e){ msg(e.message); } }); - bar.appendChild(add); - panel.appendChild(bar); + f.appendChild(add); + wrap.appendChild(f); + toggle.addEventListener("click", ()=>{ + toggle.style.display = "none"; + f.style.display = "flex"; + inp.focus(); + }); + panel.appendChild(wrap); /* systeemmanagers horen niet bij één school, dus het aanmaken ervan staat hier i.p.v. tussen de school-gebonden gebruikers in de Gebruikers-tab (de lijst van bestaande supers blijft wel gewoon in Gebruikers staan) */ - if(creatableRoles().includes("super")){ - panel.appendChild(h("div","am-h3", T("roleSuper"))); - panel.appendChild(addForm("super")); - } + if(creatableRoles().includes("super")) panel.appendChild(addForm("super")); } /* klassen (admin/super binnen een school) */ diff --git a/public/js/core.js b/public/js/core.js index be8ad40..73f6810 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.3.34-beta"; +const VERSION = "0.3.35-beta"; (function(){ const tag = document.getElementById("verTag"); tag.textContent = "v"+VERSION; @@ -184,14 +184,14 @@ const I18N = { amPickSchoolHint:"Kies hierboven eerst een school (🏫).", amPickSchool:"Kies een school", amPupils:"Leerlingen", amPupilOne:"Leerling", amEdit:"Bewerken", amSure:"weet je het zeker?", amDelete:"verwijder", - amFieldRole:"Functie", amFieldExtraRoles:"Extra functies", amFieldClass:"Klas", + amFieldName:"Naam", amFieldRole:"Functie", amFieldExtraRoles:"Extra functies", amFieldClass:"Klas", amFieldPw:"Wachtwoord", amFieldActions:"Acties", amPwTypePh:"typ een wachtwoord…", amNewPwWarn:"Maakt een nieuw wachtwoord aan. Het oude wachtwoord werkt daarna niet meer en de gebruiker wordt overal uitgelogd.", 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.", amResultPw:"Nieuw wachtwoord", amResultCode:"Nieuwe koppelcode", - amNewSchoolDesc:"De schoolnaam verschijnt op het inlogscherm voor alle gebruikers van die school. Kies de definitieve naam - hernoemen kan later niet via dit scherm.", amSchoolNamePh:"naam van de school…", amNewSchoolConfirm:"Aanmaken:", + amDeleteSchoolWarn:"Verwijdert deze school met alle klassen en gebruikers. Dit kan niet ongedaan worden gemaakt.", amClassNamePh:"naam van de klas…", amDeleteClassWarn:"Verwijdert deze klas; leerlingen blijven bestaan maar staan daarna zonder klas.", amNewSchool:"+ School", amNewClass:"+ Klas", amNewTeacher:"+ Groepsleiding", @@ -380,14 +380,14 @@ const I18N = { amPickSchoolHint:"First pick a school above (🏫).", amPickSchool:"Pick a school", amPupils:"Pupils", amPupilOne:"Pupil", amEdit:"Edit", amSure:"are you sure?", amDelete:"delete", - amFieldRole:"Role", amFieldExtraRoles:"Extra roles", amFieldClass:"Class", + amFieldName:"Name", amFieldRole:"Role", amFieldExtraRoles:"Extra roles", amFieldClass:"Class", amFieldPw:"Password", amFieldActions:"Actions", amPwTypePh:"type a password…", amNewPwWarn:"Generates a new password. The old one stops working and the user is signed out everywhere.", 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.", amResultPw:"New password", amResultCode:"New link code", - amNewSchoolDesc:"The school name appears on the login screen for all users of that school. Pick the final name - it cannot be renamed from this screen later.", amSchoolNamePh:"name of the school…", amNewSchoolConfirm:"Create:", + amDeleteSchoolWarn:"Deletes this school with all its classes and users. This cannot be undone.", amClassNamePh:"name of the class…", amDeleteClassWarn:"Deletes this class; pupils remain but end up without a class.", amNewSchool:"+ School", amNewClass:"+ Class", amNewTeacher:"+ Group leader",