teach/public/js/widgets/compliments.js
Ramon 9920fd3855
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
feat: vier sociaal-emotionele widgets, waaronder een geluidsmeter (v0.4.21-beta)
- Geluidsmeter: meet het klasgeluid live via de microfoon in een verticale
  meter (rustig/pratend/te luid). Twee aanpasbare streefniveaus ("Rustig
  tot" / "Te luid vanaf") laten de leerkracht de meter afstemmen op het
  eigen lokaal en apparaat. Microfoon staat standaard uit en start alleen
  na een expliciete klik; er wordt niets opgenomen of verstuurd, alles
  blijft lokaal in de browser. Stopt de microfoonstream vanzelf zodra de
  widget van het bord verdwijnt, ook als "Stop" niet eerst is ingedrukt.
- Gevoelszones: individuele check-in met vier zones (blauw/groen/geel/
  rood, Zones of Regulation-stijl) - elke zone geeft een korte uitleg én
  een concrete tip om jezelf te helpen. Anders dan de bestaande
  Gevoelsmeter (mood.js), die een anonieme klaspoll is.
- Ademhalingsoefening: een groeiende/krimpende cirkel begeleidt rustig
  ademhalen in drie instelbare tempo's (4-4, 4-7-8, box breathing),
  met rondjesteller.
- Complimentenmachine: trekt een willekeurig compliment uit twintig
  kindvriendelijke complimenten, met dezelfde spin-en-onthul-animatie als
  de namenkiezer.
- Alle vier volledig tweetalig (nl/en), toegevoegd aan de mobiele-dekking-
  test, en geverifieerd in de browser inclusief een echte (fake) micro-
  foonstream voor de geluidsmeter.
2026-07-19 00:44:39 +02:00

66 lines
3.3 KiB
JavaScript

/* widget: Complimentenmachine */
/* =========================================================
Trek een willekeurig compliment - zelfde spin-en-onthul-mechaniek als
de namenkiezer (names.js)
==========================================================*/
const COMPLIMENTS = Object.freeze([
{ nl:"Jij bent een fijne klasgenoot!", en:"You're a great classmate!" },
{ nl:"Wat knap dat je dat zelf hebt uitgezocht!", en:"Great job figuring that out yourself!" },
{ nl:"Jij luistert altijd goed naar anderen.", en:"You're always a great listener." },
{ nl:"Je hebt vandaag hard gewerkt, goed gedaan!", en:"You worked hard today, well done!" },
{ nl:"Jij deelt graag met anderen.", en:"You love sharing with others." },
{ nl:"Wat fijn dat jij er bent!", en:"We're so glad you're here!" },
{ nl:"Jij bent heel behulpzaam.", en:"You're very helpful." },
{ nl:"Je hebt een mooie glimlach.", en:"You have a lovely smile." },
{ nl:"Jij geeft nooit op, dat is knap!", en:"You never give up, that's impressive!" },
{ nl:"Jij bent een echte teamspeler.", en:"You're a real team player." },
{ nl:"Wat een goed idee had jij daar!", en:"That was a great idea you had!" },
{ nl:"Jij maakt anderen graag blij.", en:"You love making others happy." },
{ nl:"Je hebt heel goed je best gedaan.", en:"You tried really hard." },
{ nl:"Jij bent creatief en origineel.", en:"You're creative and original." },
{ nl:"Jij zegt altijd eerlijk wat je denkt.", en:"You always speak your mind honestly." },
{ nl:"Jij bent een fijne vriend(in).", en:"You're a great friend." },
{ nl:"Wat kun jij goed samenwerken!", en:"You're so good at working together!" },
{ nl:"Jij maakt de klas een fijnere plek.", en:"You make our class a nicer place." },
{ nl:"Jij durft dingen te proberen, goed zo!", en:"You're brave enough to try new things!" },
{ nl:"Jij bent trots op jezelf, en dat mag!", en:"You're proud of yourself, and that's great!" },
]);
function mountCompliments(root, initState){
let current = null, spinning = false;
root.innerHTML = `
<div class="cpl">
<p class="play-mission cpl-mission"></p>
<div class="cpl-card"><span class="cpl-icon">💝</span><p class="cpl-text"></p></div>
<button class="tbtn cpl-draw"></button>
</div>`;
const card = root.querySelector(".cpl-card"), text = root.querySelector(".cpl-text"), drawBtn = root.querySelector(".cpl-draw");
function pickRandom(){ return COMPLIMENTS[Math.floor(Math.random() * COMPLIMENTS.length)]; }
function draw(){
if(spinning) return;
spinning = true;
card.classList.remove("show");
let n = 0;
const iv = setInterval(()=>{
text.textContent = pickRandom()[LANG];
tone(500 + Math.random() * 200, 0.03, 0, "square", 0.04);
if(++n >= 10){
clearInterval(iv);
current = pickRandom();
text.textContent = current[LANG];
card.classList.add("show");
confetti(card);
sndWin();
spinning = false;
}
}, 70);
}
drawBtn.addEventListener("click", draw);
function labels(){
root.querySelector(".cpl-mission").textContent = T("wg_compliments_d");
drawBtn.textContent = "💝 " + T("complimentsDraw");
if(current) text.textContent = current[LANG];
}
document.addEventListener("langchange", labels);
labels();
return { getState: ()=>({}) };
}