All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
- Nieuwe architectuur: één sectieregister (settings.js) als enige bron van waarheid; secties melden zich aan met rol-zichtbaarheid, activate() en zoekgegevens - de schil kent het beheer niet van binnen - Nieuwe indeling: navigatie links (gegroepeerd Persoonlijk / School / Systeem), inhoud rechts met sectiekop + toelichting; zakelijk en rustig, responsief op smalle schermen - Alles doorzoekbaar: één zoekbalk vindt secties, instellingen (trefwoorden, o.a. wachtwoord/thema/taal) én data - gebruikers, klassen en scholen op naam; klik navigeert en filtert de gebruikerslijst direct op de treffer - Per rol alleen de essentie: gast alleen Weergave; leerling en ouder Account + Weergave; groepsleiding + Gebruikers/Toewijzingen/Voortgang; schoolbeheerder ook Klassen; systeemmanager ook Systeem en Opslag - Thuiskinderen (leerling zonder school) krijgen nu zoals ontworpen het volledige whiteboard met eigen opslag en reservekopieën; schoolleerlingen blijven beperkt tot de toewijzing - Oude dubbele tabbalk en #adminTabsSlot verwijderd; beheerdata laadt één keer per bezoek en wordt tussen secties hergebruikt - 28 Playwright-checks over zes rollen (navigatie, zoeken, filteren, thuiskind-whiteboard) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
171 lines
7.5 KiB
JavaScript
171 lines
7.5 KiB
JavaScript
/* teach - instellingen-schil: één sectieregister als enige bron van waarheid.
|
|
Elke sectie meldt zich aan met zichtbaarheid per rol, een activate() en
|
|
zoekgegevens; de schil bouwt daar de navigatie (gegroepeerd: Persoonlijk /
|
|
School / Systeem), de sectiekop en de zoekfunctie uit op. Zo bepaalt de rol
|
|
van de ingelogde gebruiker vanzelf wat er te zien is: een gast alleen
|
|
Weergave, een leerling/ouder Account + Weergave, staf ook de beheerdelen
|
|
(admin.js registreert die zelf - de schil kent het beheer niet van binnen).
|
|
De zoekbalk zoekt door sectienamen, instelling-trefwoorden én data
|
|
(gebruikers/klassen/scholen via searchItems van de secties). */
|
|
"use strict";
|
|
const ST_SECTIONS = [];
|
|
function registerSettingsSection(sec){ ST_SECTIONS.push(sec); }
|
|
|
|
(function(){
|
|
const wrap = document.getElementById("settingsWrap");
|
|
const nav = document.getElementById("stNav");
|
|
const content = document.getElementById("stContent");
|
|
const secHead = document.getElementById("stSecHead");
|
|
const searchInp = document.getElementById("stSearch");
|
|
const resultsEl = document.getElementById("stSearchResults");
|
|
let activeSection = null;
|
|
|
|
const el = (tag, cls, text)=>{
|
|
const e = document.createElement(tag);
|
|
if(cls) e.className = cls;
|
|
if(text != null) e.textContent = text;
|
|
return e;
|
|
};
|
|
const visibleSections = ()=>
|
|
ST_SECTIONS.filter(s=>s.visible()).sort((a,b)=>(a.order||99)-(b.order||99));
|
|
|
|
/* ---- ingebouwde secties: Account en Weergave ------------------------------ */
|
|
registerSettingsSection({
|
|
id:"account", icon:"👤", group:"personal", order:1,
|
|
label:()=>T("stAccount"), sub:()=>T("stAccountSub"),
|
|
visible:()=>!!currentUser,
|
|
activate(){ showDomSection("account"); loadBackups(); },
|
|
keywords:()=>[T("stPassword"), T("stBackups"), T("stSession"), T("logout"),
|
|
"wachtwoord","password","reservekopie","backup","herstel","restore",
|
|
"uitloggen","logout","sessie","session","naam","name"],
|
|
});
|
|
registerSettingsSection({
|
|
id:"view", icon:"🎨", group:"personal", order:2,
|
|
label:()=>T("stView"), sub:()=>T("stViewSub"),
|
|
visible:()=>true,
|
|
activate(){ showDomSection("view"); },
|
|
keywords:()=>[T("vwTheme"), T("vwContrast"), T("vwLang"), T("vwTbar"), T("vwMotion"), T("vwGlass"),
|
|
"thema","theme","donker","dark","licht","light","contrast","taal","language",
|
|
"menubalk","toolbar","animaties","animations","glas","glass"],
|
|
});
|
|
|
|
/* de drie DOM-secties (account/view/admin-host); beheer-secties delen de
|
|
admin-host, admin.js wisselt daarbinnen zelf van paneel */
|
|
function showDomSection(id){
|
|
resultsEl.style.display = "none";
|
|
content.querySelectorAll(".st-section").forEach(s=>{
|
|
s.style.display = s.dataset.section===id ? "" : "none";
|
|
});
|
|
}
|
|
window.showAdminHost = ()=>showDomSection("admin");
|
|
|
|
const GROUPS = [["personal","stGroupPersonal"], ["school","stGroupSchool"], ["system","stGroupSystem"]];
|
|
function buildNav(){
|
|
nav.innerHTML = "";
|
|
const secs = visibleSections();
|
|
GROUPS.forEach(([g, key])=>{
|
|
const inGroup = secs.filter(s=>s.group===g);
|
|
if(!inGroup.length) return;
|
|
/* groepskoppen pas als er echt iets te groeperen valt (staf); een
|
|
gast/leerling met 1-2 secties krijgt een kale, rustige lijst */
|
|
if(secs.length > 3) nav.appendChild(el("div","st-nav-group", T(key)));
|
|
inGroup.forEach(s=>{
|
|
const b = el("button","st-nav-btn");
|
|
b.type = "button";
|
|
b.dataset.section = s.id;
|
|
b.appendChild(el("span","st-nav-ico", s.icon));
|
|
b.appendChild(el("span","st-nav-lbl", s.label()));
|
|
b.addEventListener("click", ()=>goSection(s.id));
|
|
nav.appendChild(b);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function goSection(id, payload){
|
|
const s = ST_SECTIONS.find(x=>x.id===id && x.visible());
|
|
if(!s) return;
|
|
activeSection = id;
|
|
searchInp.value = "";
|
|
nav.querySelectorAll(".st-nav-btn").forEach(b=>b.classList.toggle("active", b.dataset.section===id));
|
|
secHead.innerHTML = "";
|
|
secHead.appendChild(el("div","st-sec-title", s.icon + " " + s.label()));
|
|
if(s.sub) secHead.appendChild(el("div","st-sec-sub", s.sub()));
|
|
content.scrollTop = 0;
|
|
await s.activate(payload);
|
|
}
|
|
window.goSettingsSection = goSection;
|
|
|
|
/* ---- zoeken ---------------------------------------------------------------
|
|
drie lagen per zichtbare sectie: (1) sectienaam, (2) trefwoorden van de
|
|
instellingen erin, (3) live data (searchItems: gebruikers/klassen/scholen).
|
|
Resultaten vervangen de inhoud; een klik navigeert (en filtert waar kan). */
|
|
function doSearch(){
|
|
const q = searchInp.value.trim().toLowerCase();
|
|
if(!q){
|
|
if(activeSection) goSection(activeSection);
|
|
return;
|
|
}
|
|
nav.querySelectorAll(".st-nav-btn").forEach(b=>b.classList.remove("active"));
|
|
secHead.innerHTML = "";
|
|
resultsEl.innerHTML = "";
|
|
content.querySelectorAll(".st-section").forEach(s=>{ s.style.display = "none"; });
|
|
let total = 0;
|
|
visibleSections().forEach(s=>{
|
|
const hits = [];
|
|
if(s.label().toLowerCase().includes(q)){
|
|
hits.push({ icon:s.icon, label:s.label(), sub:T("stOpenSection"), go:()=>goSection(s.id) });
|
|
}else{
|
|
const kw = (s.keywords ? s.keywords() : []).find(k=>String(k).toLowerCase().includes(q));
|
|
if(kw) hits.push({ icon:s.icon, label:String(kw), sub:s.label(), go:()=>goSection(s.id) });
|
|
}
|
|
if(s.searchItems) hits.push(...s.searchItems(q));
|
|
if(!hits.length) return;
|
|
total += hits.length;
|
|
resultsEl.appendChild(el("div","st-nav-group", s.label()));
|
|
hits.slice(0, 8).forEach(hit=>{
|
|
const row = el("button","st-result");
|
|
row.type = "button";
|
|
row.appendChild(el("span","st-nav-ico", hit.icon || s.icon));
|
|
row.appendChild(el("span","st-result-lbl", hit.label));
|
|
if(hit.sub) row.appendChild(el("span","st-result-sub", hit.sub));
|
|
row.addEventListener("click", ()=>hit.go());
|
|
resultsEl.appendChild(row);
|
|
});
|
|
});
|
|
if(!total) resultsEl.appendChild(el("div","guestnote", T("stNoResults")));
|
|
resultsEl.style.display = "";
|
|
}
|
|
searchInp.addEventListener("input", doSearch);
|
|
searchInp.addEventListener("keydown", e=>{
|
|
e.stopPropagation();
|
|
if(e.key==="Escape"){ searchInp.value = ""; doSearch(); }
|
|
if(e.key==="Enter"){ const first = resultsEl.querySelector(".st-result"); if(first) first.click(); }
|
|
});
|
|
|
|
/* ---- openen ---------------------------------------------------------------- */
|
|
window.openSettings = function(section){
|
|
const msg = document.getElementById("settingsMsg");
|
|
msg.textContent = ""; msg.classList.remove("ok");
|
|
searchInp.value = "";
|
|
searchInp.placeholder = T("stSearchPh");
|
|
buildNav();
|
|
goSection(section || (currentUser ? "account" : "view"));
|
|
/* beheerdata alvast op de achtergrond laden zodat zoeken op namen van
|
|
gebruikers/klassen/scholen meteen wat oplevert (admin.js bewaakt zelf
|
|
dat er maar één keer geladen wordt) */
|
|
if(currentUser && can("admin.access") && window.adminPrefetch) window.adminPrefetch();
|
|
wrap.classList.add("open");
|
|
};
|
|
document.addEventListener("langchange", ()=>{
|
|
searchInp.placeholder = T("stSearchPh");
|
|
if(wrap.classList.contains("open")){ buildNav(); if(activeSection) goSection(activeSection); }
|
|
});
|
|
document.addEventListener("userchange", ()=>{
|
|
if(wrap.classList.contains("open")){
|
|
buildNav();
|
|
const secs = visibleSections();
|
|
if(!secs.some(s=>s.id===activeSection)) goSection(secs[0] ? secs[0].id : "view");
|
|
else goSection(activeSection);
|
|
}
|
|
});
|
|
})();
|