teach/public/js/app.js
Ramon 4b54ea4a12
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
v0.3.00-beta: nieuw ontwerp \"teachus.today\" - minimalistisch, nieuw logo, licht+donker
- Nieuw logo: low-poly uil als SVG (transparant, vlakke merk-kleuren) + woordmerk
  \"teachus.today\" in de menubalk; op kleine schermen alleen de uil. Ook favicon
  en inlogscherm gebruiken het nieuwe logo.
- Nieuwe huisstijl afgeleid van het logo: teal als primaire actiekleur, navy inkt,
  Quicksand-font (zelf gehost, ~28 KB), dunne lijnen, vlakke minimale chrome-laag;
  het glas-effect blijft alleen op de bord-laag (widgets/HUD).
- Token-systeem herschreven: semantische kleuren (--surface/--line/--accent/...),
  radius-/schaduwschaal en één control-hoogte (--control-h) zodat alle vakken
  (inputs, selects, knoppen) in elke rij even hoog zijn; op aanraakschermen
  groeit alles mee naar 44px. Galerij-tegels hebben nu gelijke hoogtes.
- Modern tabsysteem: underline-tabs die overlopen in hun paneel (geen gele
  file-folder-tabs en omrande panelen meer); kleine keuzegroepen (taal, niveaus,
  timer, chips) delen één segmented-control-stijl.
- Donker thema: schakelbaar (licht/donker/auto volgt het OS), alle panelen,
  bordpatronen en widgets doen mee; hoog contrast wint altijd van donker.
- Nieuw tabblad Instellingen -> Weergave: thema, hoog contrast (verhuisd uit de
  menubalk), taal NL/EN (verhuisd uit de menubalk), menubalk-positie
  (boven/links/rechts), animaties aan/uit en glas-effect aan/uit - allemaal
  apparaat-gebonden en ook als gast bereikbaar via het inlogscherm.
- Menubalk: rustiger (transparante knoppen, hairline i.p.v. schaduw) en
  verplaatsbaar naar links of rechts als verticale kolom; bord, leerling-
  weergave en zwevende knoppen schuiven mee.
- Taalkeuze wordt nu onthouden (localStorage).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuxHJtk5aHe2pA3xwCLEAk
2026-07-14 09:59:13 +02:00

94 lines
No EOL
4.1 KiB
JavaScript

/* teach - start: beeldgrootte, contrast, sessie-herstel */
/* =========================================================
init
==========================================================*/
/* display size: scale the whole app up for pupils who need it (device setting) */
let ZOOM = 100;
const btnZoomIn = document.getElementById("btnZoomIn");
const btnZoomOut = document.getElementById("btnZoomOut");
const zoomPct = document.getElementById("zoomPct");
function setZoom(z){
ZOOM = Math.max(100, Math.min(200, Math.round(z/10)*10));
document.body.style.zoom = ZOOM/100;
zoomPct.textContent = ZOOM+"%";
zoomPct.classList.toggle("on", ZOOM!==100);
btnZoomIn.title = btnZoomOut.title = zoomPct.title = T("zoomUI");
btnZoomIn.disabled = ZOOM>=200;
btnZoomOut.disabled = ZOOM<=100;
try{ localStorage.setItem("teach.zoom", ZOOM); }catch(e){}
}
btnZoomIn.addEventListener("click", ()=>setZoom(ZOOM+10));
btnZoomOut.addEventListener("click", ()=>setZoom(ZOOM-10));
zoomPct.addEventListener("click", ()=>setZoom(100)); /* tap the % to reset */
document.addEventListener("langchange", ()=>{ btnZoomIn.title = btnZoomOut.title = zoomPct.title = T("zoomUI"); });
try{ const z = +localStorage.getItem("teach.zoom"); if(z>100) setZoom(z); else setZoom(100); }catch(e){ setZoom(100); }
/* weergave-instellingen (Instellingen → Weergave): apparaat-gebonden voorkeuren.
Elke seg-groep: knopjes met data-v, keuze in localStorage, body-class toepassen. */
function initSeg(id, key, def, apply){
const seg = document.getElementById(id);
let val = def;
try{ val = localStorage.getItem(key) || def; }catch(e){}
if(![...seg.querySelectorAll("button")].some(b=>b.dataset.v===val)) val = def;
const set = v=>{
seg.querySelectorAll("button").forEach(b=>b.classList.toggle("active", b.dataset.v===v));
apply(v);
try{ localStorage.setItem(key, v); }catch(e){}
};
seg.querySelectorAll("button").forEach(b=>b.addEventListener("click", ()=>set(b.dataset.v)));
set(val);
}
/* thema: licht / donker / automatisch (volgt het OS) */
const darkMq = window.matchMedia("(prefers-color-scheme: dark)");
const applyTheme = v=>{
document.body.classList.toggle("dark", v==="dark" || (v==="auto" && darkMq.matches));
};
initSeg("segTheme", "teach.theme", "light", applyTheme);
darkMq.addEventListener("change", ()=>{
try{ if((localStorage.getItem("teach.theme")||"light")==="auto") applyTheme("auto"); }catch(e){}
});
/* hoog contrast (voorheen de 👁-knop in de menubalk; zelfde localStorage-sleutel) */
(function(){
let init = "off";
try{ if(localStorage.getItem("teach.hc")==="1") init = "on"; }catch(e){}
const seg = document.getElementById("segHC");
const set = v=>{
seg.querySelectorAll("button").forEach(b=>b.classList.toggle("active", b.dataset.v===v));
document.body.classList.toggle("hc", v==="on");
try{ localStorage.setItem("teach.hc", v==="on" ? "1" : ""); }catch(e){}
};
seg.querySelectorAll("button").forEach(b=>b.addEventListener("click", ()=>set(b.dataset.v)));
set(init);
})();
/* menubalk-positie: boven / links / rechts */
initSeg("segTbar", "teach.tbar", "top", v=>{
document.body.classList.toggle("tb-left", v==="left");
document.body.classList.toggle("tb-right", v==="right");
});
/* minder beweging: standaard uit als het OS erom vraagt */
const motionDef = window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "off" : "on";
initSeg("segMotion", "teach.motion", motionDef, v=>document.body.classList.toggle("no-motion", v==="off"));
/* glas-effect (transparantie/blur van widgets en balken) */
initSeg("segGlass", "teach.glass", "on", v=>document.body.classList.toggle("no-glass", v==="off"));
/* taalkeuze onthouden (de schakelaar staat nu onder Weergave) */
try{
const l = localStorage.getItem("teach.lang");
if(l && I18N[l]) LANG = l;
}catch(e){}
applyI18n();
updateEmptyHint();
/* sessie herstellen: geldig servertoken? dan opnieuw inloggen zonder wachtwoord */
(async function(){
updateBoardsUI();
if(!TOKEN) return;
try{
const me = await api("/auth/me");
currentUser = me.user;
updateUserUI();
await hydrateFromServer();
}catch(e){
resetToGuest();
}
})();