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
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:
parent
b4eee9f78f
commit
15618348dc
6 changed files with 77 additions and 19 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.3.90-beta
|
0.3.91-beta
|
||||||
|
|
|
||||||
|
|
@ -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-role{order:3; flex-basis:100%; margin-left:0;}
|
||||||
#settingsModal .am-card-sub .am-edit{margin-left:auto;}
|
#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;}
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,8 @@
|
||||||
<div class="am-role" id="helloRole"></div>
|
<div class="am-role" id="helloRole"></div>
|
||||||
</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 class="am-reset" id="ownPwBlock">
|
||||||
<div id="settingsMsg" class="formMsg"></div>
|
<div id="settingsMsg" class="formMsg"></div>
|
||||||
<div class="lrow">
|
<div class="lrow">
|
||||||
|
|
@ -220,6 +221,7 @@
|
||||||
<button class="tbtn ghost" id="btnOwnPw" data-i18n="pwChange"></button>
|
<button class="tbtn ghost" id="btnOwnPw" data-i18n="pwChange"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="am-h3" id="backupsHead" data-i18n="stBackups"></div>
|
<div class="am-h3" id="backupsHead" data-i18n="stBackups"></div>
|
||||||
<div class="am-reset" id="backupsBlock">
|
<div class="am-reset" id="backupsBlock">
|
||||||
|
|
|
||||||
|
|
@ -1095,14 +1095,28 @@
|
||||||
panel.appendChild(pupilSel);
|
panel.appendChild(pupilSel);
|
||||||
const eventsHolder = h("div","am-list");
|
const eventsHolder = h("div","am-list");
|
||||||
panel.appendChild(eventsHolder);
|
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 ()=>{
|
pupilSel.addEventListener("change", async ()=>{
|
||||||
eventsHolder.innerHTML = "";
|
eventsHolder.innerHTML = "";
|
||||||
|
moreBtn.style.display = "none";
|
||||||
if(!pupilSel.value) return;
|
if(!pupilSel.value) return;
|
||||||
let events = [];
|
let events = [];
|
||||||
try{ events = (await api("/progress/pupil/"+pupilSel.value)).events || []; }
|
try{ events = (await api("/progress/pupil/"+pupilSel.value)).events || []; }
|
||||||
catch(e){ msg(e.message); return; }
|
catch(e){ msg(e.message); return; }
|
||||||
if(!events.length){ eventsHolder.appendChild(h("div","guestnote", T("amProgressEmpty"))); 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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,32 @@ let CMS = {};
|
||||||
}
|
}
|
||||||
document.addEventListener("langchange", ()=>{ renderAnnouncement(); renderWelcome(); });
|
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) ----------------- */
|
/* ---- Inhoud-sectie in Instellingen (alleen systeemmanager) ----------------- */
|
||||||
const host = cmsEl("div", "st-section");
|
const host = cmsEl("div", "st-section");
|
||||||
host.dataset.section = "inhoud";
|
host.dataset.section = "inhoud";
|
||||||
|
|
@ -102,8 +128,7 @@ let CMS = {};
|
||||||
host.innerHTML = "";
|
host.innerHTML = "";
|
||||||
|
|
||||||
/* welkomstwoord */
|
/* 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 wNl = langArea("cmsNl", CMS.welcome && CMS.welcome.nl);
|
||||||
const wEn = langArea("cmsEn", CMS.welcome && CMS.welcome.en);
|
const wEn = langArea("cmsEn", CMS.welcome && CMS.welcome.en);
|
||||||
const wSave = cmsEl("button", "am-btn", T("save"));
|
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));
|
wSave.addEventListener("click", ()=>save("welcome", { nl: wNl._ta.value.trim(), en: wEn._ta.value.trim() }, wMsg));
|
||||||
const wBlock = cmsEl("div", "am-reset cms-block");
|
const wBlock = cmsEl("div", "am-reset cms-block");
|
||||||
[wNl, wEn, wSave, wMsg].forEach(n=>wBlock.appendChild(n));
|
[wNl, wEn, wSave, wMsg].forEach(n=>wBlock.appendChild(n));
|
||||||
host.appendChild(wBlock);
|
host.appendChild(cmsCard("welcome", "cmsWelcomeH", b=>b.appendChild(wBlock)));
|
||||||
|
|
||||||
/* update-melding */
|
/* update-melding */
|
||||||
host.appendChild(cmsEl("div", "am-h3", T("cmsAnnounceH")));
|
const a = CMS.announcement || {};
|
||||||
const a = CMS.announcement || {};
|
|
||||||
const aMsg = cmsEl("div", "formMsg");
|
const aMsg = cmsEl("div", "formMsg");
|
||||||
const activeLbl = cmsEl("label", "cms-check");
|
const activeLbl = cmsEl("label", "cms-check");
|
||||||
const active = document.createElement("input");
|
const active = document.createElement("input");
|
||||||
|
|
@ -142,11 +166,10 @@ let CMS = {};
|
||||||
aRow.appendChild(activeLbl);
|
aRow.appendChild(activeLbl);
|
||||||
aRow.appendChild(level);
|
aRow.appendChild(level);
|
||||||
[aRow, aNl, aEn, aSave, aMsg].forEach(n=>aBlock.appendChild(n));
|
[aRow, aNl, aEn, aSave, aMsg].forEach(n=>aBlock.appendChild(n));
|
||||||
host.appendChild(aBlock);
|
host.appendChild(cmsCard("announcement", "cmsAnnounceH", b=>b.appendChild(aBlock)));
|
||||||
|
|
||||||
/* widget-uitleg */
|
/* 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 gMsg = cmsEl("div", "formMsg");
|
||||||
const pick = document.createElement("select");
|
const pick = document.createElement("select");
|
||||||
pick.className = "am-sel";
|
pick.className = "am-sel";
|
||||||
|
|
@ -180,11 +203,10 @@ let CMS = {};
|
||||||
gBlock.appendChild(pick);
|
gBlock.appendChild(pick);
|
||||||
gBlock.appendChild(editor);
|
gBlock.appendChild(editor);
|
||||||
gBlock.appendChild(gMsg);
|
gBlock.appendChild(gMsg);
|
||||||
host.appendChild(gBlock);
|
host.appendChild(cmsCard("widgets", "cmsWidgetH", b=>b.appendChild(gBlock)));
|
||||||
|
|
||||||
/* systeembrede inhoud: ankerdiagrammen/borden en afbeeldingen */
|
/* 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")));
|
sBlock.appendChild(cmsEl("div", "guestnote", T("cmsShortcutsHint")));
|
||||||
const shared = cmsEl("button", "tbtn ghost", T("cmsOpenShared"));
|
const shared = cmsEl("button", "tbtn ghost", T("cmsOpenShared"));
|
||||||
shared.type = "button";
|
shared.type = "button";
|
||||||
|
|
@ -202,7 +224,7 @@ let CMS = {};
|
||||||
sRow.appendChild(shared);
|
sRow.appendChild(shared);
|
||||||
sRow.appendChild(imgs);
|
sRow.appendChild(imgs);
|
||||||
sBlock.appendChild(sRow);
|
sBlock.appendChild(sRow);
|
||||||
host.appendChild(sBlock);
|
host.appendChild(cmsCard("shortcuts", "cmsShortcutsH", b=>b.appendChild(sBlock)));
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSettingsSection({
|
registerSettingsSection({
|
||||||
|
|
|
||||||
|
|
@ -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.90-beta";
|
const VERSION = "0.3.91-beta";
|
||||||
(function(){
|
(function(){
|
||||||
const tag = document.getElementById("verTag");
|
const tag = document.getElementById("verTag");
|
||||||
tag.textContent = "v"+VERSION;
|
tag.textContent = "v"+VERSION;
|
||||||
|
|
@ -279,7 +279,7 @@ const I18N = {
|
||||||
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", amStatusActive:"actief",
|
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.",
|
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",
|
||||||
|
|
@ -574,7 +574,7 @@ const I18N = {
|
||||||
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", amStatusActive:"active",
|
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.",
|
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",
|
||||||
|
|
@ -857,7 +857,7 @@ function updateUserUI(){
|
||||||
document.getElementById("helloName").textContent = currentUser.displayName;
|
document.getElementById("helloName").textContent = currentUser.displayName;
|
||||||
const roles = [currentUser.role, ...(currentUser.extraRoles||[])];
|
const roles = [currentUser.role, ...(currentUser.extraRoles||[])];
|
||||||
document.getElementById("helloRole").textContent = roles.map(r=>T(roleKey(r))).join(" + ");
|
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" */
|
/* 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,"<")}</option>`).join("");
|
list.map(x=>`<option value="${x.id}">${x.name.replace(/</g,"<")}</option>`).join("");
|
||||||
}catch(e){ sel.innerHTML = `<option value="">${T("schoolSel")}</option>`; }
|
}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);
|
/* openSettings() zelf woont in settings.js (sectieregister + zoeken);
|
||||||
de knoppen hieronder roepen hem via window aan */
|
de knoppen hieronder roepen hem via window aan */
|
||||||
/* reservekopieën (Instellingen → Account): automatisch bewaarde eerdere
|
/* reservekopieën (Instellingen → Account): automatisch bewaarde eerdere
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue