style: alle menu's nagelopen - alles verborgen tot erom gevraagd wordt (v0.3.91-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s

- Voortgang: tijdlijn toont 30 regels per keer met een "meer tonen (n)"-knop i.p.v. 200 regels ineens
- Inhoud: de vier blokken (welkomstwoord, melding, widget-uitleg, systeembrede inhoud) zijn inklapbare groepskaarten - alleen het welkomstwoord staat standaard open; open-status overleeft her-renders
- Account: de drie wachtwoordvelden verschijnen pas na een klik op de kop "Wachtwoord"
- Daarmee volgt elke sectie hetzelfde principe: compacte koppen met samenvatting, detail pas op verzoek, verwante items in één kader
- Geverifieerd in headless Chromium (9 nieuwe checks) + volledige regressie van de vier bestaande suites (56 checks)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
This commit is contained in:
Ramon 2026-07-17 14:35:24 +02:00
parent b4eee9f78f
commit 15618348dc
6 changed files with 77 additions and 19 deletions

View file

@ -1 +1 @@
0.3.90-beta
0.3.91-beta

View file

@ -2043,3 +2043,14 @@ body.hc #settingsModal .am-inp, body.hc #settingsModal .am-sel{border-color:#000
#settingsModal .am-card-sub .am-role{order:3; flex-basis:100%; margin-left:0;}
#settingsModal .am-card-sub .am-edit{margin-left:auto;}
}
/* ---- inklapbare koppen: wachtwoordblok (Account) en Inhoud-kaarten ---- */
#settingsModal .am-h3-toggle{cursor:pointer; user-select:none;}
#settingsModal .am-h3-toggle::after{content:" ▸";}
#settingsModal .am-h3-toggle.open::after{content:" ▾";}
#settingsModal .am-h3-toggle:hover{color:var(--ink);}
#settingsModal #ownPwBlock{display:none;}
#settingsModal #ownPwBlock.open{display:flex;}
#settingsModal .am-card-head.am-card-toggle{cursor:pointer;}
#settingsModal .cms-card-body{padding:10px 12px;}
#settingsModal .cms-card-body .am-reset{border:none; padding:0; background:transparent;}

View file

@ -205,7 +205,8 @@
<div class="am-role" id="helloRole"></div>
</div>
<div class="am-h3" data-i18n="stPassword"></div>
<div id="pwSection">
<div class="am-h3 am-h3-toggle" id="pwToggleHead" data-i18n="stPassword"></div>
<div class="am-reset" id="ownPwBlock">
<div id="settingsMsg" class="formMsg"></div>
<div class="lrow">
@ -220,6 +221,7 @@
<button class="tbtn ghost" id="btnOwnPw" data-i18n="pwChange"></button>
</div>
</div>
</div>
<div class="am-h3" id="backupsHead" data-i18n="stBackups"></div>
<div class="am-reset" id="backupsBlock">

View file

@ -1095,14 +1095,28 @@
panel.appendChild(pupilSel);
const eventsHolder = h("div","am-list");
panel.appendChild(eventsHolder);
const moreBtn = h("button","am-btn", T("amShowMore"));
moreBtn.type = "button";
moreBtn.style.display = "none";
panel.appendChild(moreBtn);
pupilSel.addEventListener("change", async ()=>{
eventsHolder.innerHTML = "";
moreBtn.style.display = "none";
if(!pupilSel.value) return;
let events = [];
try{ events = (await api("/progress/pupil/"+pupilSel.value)).events || []; }
catch(e){ msg(e.message); return; }
if(!events.length){ eventsHolder.appendChild(h("div","guestnote", T("amProgressEmpty"))); return; }
events.forEach(ev=>eventsHolder.appendChild(progressRow(ev)));
/* in porties van 30: de tijdlijn kan 200 regels lang zijn */
let shown = 0;
const showMore = ()=>{
events.slice(shown, shown+30).forEach(ev=>eventsHolder.appendChild(progressRow(ev)));
shown = Math.min(shown+30, events.length);
moreBtn.style.display = shown < events.length ? "" : "none";
moreBtn.textContent = `${T("amShowMore")} (${events.length - shown})`;
};
moreBtn.onclick = showMore;
showMore();
});
}

View file

@ -65,6 +65,32 @@ let CMS = {};
}
document.addEventListener("langchange", ()=>{ renderAnnouncement(); renderWelcome(); });
/* welke Inhoud-blokken openstaan (welkom standaard); overleeft re-renders */
const cmsOpen = new Set(["welcome"]);
function cmsCard(key, titleKey, build){
const card = cmsEl("div", "am-card");
const head = cmsEl("div", "am-card-head am-card-toggle");
const title = cmsEl("span", "am-card-title", T(titleKey));
const arrow = cmsEl("span", "am-card-sum");
head.appendChild(title);
head.appendChild(arrow);
const body = cmsEl("div", "cms-card-body");
build(body);
const sync = ()=>{
const open = cmsOpen.has(key);
arrow.textContent = open ? "▾" : "▸";
body.style.display = open ? "" : "none";
};
head.addEventListener("click", ()=>{
if(cmsOpen.has(key)) cmsOpen.delete(key); else cmsOpen.add(key);
sync();
});
sync();
card.appendChild(head);
card.appendChild(body);
return card;
}
/* ---- Inhoud-sectie in Instellingen (alleen systeemmanager) ----------------- */
const host = cmsEl("div", "st-section");
host.dataset.section = "inhoud";
@ -102,8 +128,7 @@ let CMS = {};
host.innerHTML = "";
/* welkomstwoord */
host.appendChild(cmsEl("div", "am-h3", T("cmsWelcomeH")));
const wMsg = cmsEl("div", "formMsg");
const wMsg = cmsEl("div", "formMsg");
const wNl = langArea("cmsNl", CMS.welcome && CMS.welcome.nl);
const wEn = langArea("cmsEn", CMS.welcome && CMS.welcome.en);
const wSave = cmsEl("button", "am-btn", T("save"));
@ -111,11 +136,10 @@ let CMS = {};
wSave.addEventListener("click", ()=>save("welcome", { nl: wNl._ta.value.trim(), en: wEn._ta.value.trim() }, wMsg));
const wBlock = cmsEl("div", "am-reset cms-block");
[wNl, wEn, wSave, wMsg].forEach(n=>wBlock.appendChild(n));
host.appendChild(wBlock);
host.appendChild(cmsCard("welcome", "cmsWelcomeH", b=>b.appendChild(wBlock)));
/* update-melding */
host.appendChild(cmsEl("div", "am-h3", T("cmsAnnounceH")));
const a = CMS.announcement || {};
const a = CMS.announcement || {};
const aMsg = cmsEl("div", "formMsg");
const activeLbl = cmsEl("label", "cms-check");
const active = document.createElement("input");
@ -142,11 +166,10 @@ let CMS = {};
aRow.appendChild(activeLbl);
aRow.appendChild(level);
[aRow, aNl, aEn, aSave, aMsg].forEach(n=>aBlock.appendChild(n));
host.appendChild(aBlock);
host.appendChild(cmsCard("announcement", "cmsAnnounceH", b=>b.appendChild(aBlock)));
/* widget-uitleg */
host.appendChild(cmsEl("div", "am-h3", T("cmsWidgetH")));
const gBlock = cmsEl("div", "am-reset cms-block");
const gBlock = cmsEl("div", "am-reset cms-block");
const gMsg = cmsEl("div", "formMsg");
const pick = document.createElement("select");
pick.className = "am-sel";
@ -180,11 +203,10 @@ let CMS = {};
gBlock.appendChild(pick);
gBlock.appendChild(editor);
gBlock.appendChild(gMsg);
host.appendChild(gBlock);
host.appendChild(cmsCard("widgets", "cmsWidgetH", b=>b.appendChild(gBlock)));
/* systeembrede inhoud: ankerdiagrammen/borden en afbeeldingen */
host.appendChild(cmsEl("div", "am-h3", T("cmsShortcutsH")));
const sBlock = cmsEl("div", "am-reset cms-block");
const sBlock = cmsEl("div", "am-reset cms-block");
sBlock.appendChild(cmsEl("div", "guestnote", T("cmsShortcutsHint")));
const shared = cmsEl("button", "tbtn ghost", T("cmsOpenShared"));
shared.type = "button";
@ -202,7 +224,7 @@ let CMS = {};
sRow.appendChild(shared);
sRow.appendChild(imgs);
sBlock.appendChild(sRow);
host.appendChild(sBlock);
host.appendChild(cmsCard("shortcuts", "cmsShortcutsH", b=>b.appendChild(sBlock)));
}
registerSettingsSection({

View file

@ -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.90-beta";
const VERSION = "0.3.91-beta";
(function(){
const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION;
@ -279,7 +279,7 @@ const I18N = {
amDeleteWarn:"Verwijdert dit account definitief, inclusief borden en woorden.",
amResultPw:"Nieuw wachtwoord", amResultCode:"Nieuwe koppelcode",
amColStatus:"Status", amNeverLoggedIn:"nog niet ingelogd", amFieldSchool:"School", amStatusActive:"actief",
amNoSchool:"— geen school —", amNoSchoolGroup:"Zonder school",
amNoSchool:"— geen school —", amNoSchoolGroup:"Zonder school", amShowMore:"meer tonen",
amDetailEmpty:"Selecteer links een gebruiker om te bewerken, of maak een nieuwe aan.",
amNewUser:"Nieuwe gebruiker", amRequestOne:"Aanmelding", amReqNew:"nieuw",
amParents:"Ouders",
@ -574,7 +574,7 @@ const I18N = {
amDeleteWarn:"Deletes this account permanently, including boards and words.",
amResultPw:"New password", amResultCode:"New link code",
amColStatus:"Status", amNeverLoggedIn:"not signed in yet", amFieldSchool:"School", amStatusActive:"active",
amNoSchool:"— no school —", amNoSchoolGroup:"No school",
amNoSchool:"— no school —", amNoSchoolGroup:"No school", amShowMore:"show more",
amDetailEmpty:"Select a user on the left to edit, or create a new one.",
amNewUser:"New user", amRequestOne:"Enrolment", amReqNew:"new",
amParents:"Parents",
@ -857,7 +857,7 @@ function updateUserUI(){
document.getElementById("helloName").textContent = currentUser.displayName;
const roles = [currentUser.role, ...(currentUser.extraRoles||[])];
document.getElementById("helloRole").textContent = roles.map(r=>T(roleKey(r))).join(" + ");
document.getElementById("ownPwBlock").style.display = can("password.own.change") ? "flex" : "none";
document.getElementById("pwSection").style.display = can("password.own.change") ? "" : "none";
}
}
/* login-modal tabs: "inloggen" / "koppelcode activeren" / "ouderaccount maken" */
@ -878,6 +878,15 @@ async function loadSchools(){
list.map(x=>`<option value="${x.id}">${x.name.replace(/</g,"&lt;")}</option>`).join("");
}catch(e){ sel.innerHTML = `<option value="">${T("schoolSel")}</option>`; }
}
/* wachtwoordvelden pas op verzoek: de kop "Wachtwoord" klapt het blok uit */
{
const pwHead = document.getElementById("pwToggleHead");
const pwBlock = document.getElementById("ownPwBlock");
pwHead.addEventListener("click", ()=>{
pwBlock.classList.toggle("open");
pwHead.classList.toggle("open");
});
}
/* openSettings() zelf woont in settings.js (sectieregister + zoeken);
de knoppen hieronder roepen hem via window aan */
/* reservekopieën (Instellingen Account): automatisch bewaarde eerdere