teach/public/js/widgets/birthday.js
Ramon 6e41ea1b2e
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 29s
v0.3.07-beta: voeg educatieve widgets toe
2026-07-14 13:39:57 +02:00

74 lines
4.4 KiB
JavaScript

/* widget: volledig aanpasbare verjaardagstaart */
function mountBirthday(root, initState){
const S = Object.assign({
name:"", age:8, layers:2, cake:"#f2b880", icing:"#ff78a8", plate:"#57c7d4",
decoration:"sprinkles", candles:true,
}, initState || {});
root.innerHTML = `
<div class="bd">
<div class="bd-controls">
<input class="bd-name" type="text" maxlength="30">
<label><span class="bd-age-label"></span><input class="bd-age" type="number" min="1" max="120"></label>
<label><span class="bd-layers-label"></span><input class="bd-layers" type="range" min="1" max="3"></label>
<label class="bd-color"><span class="bd-cake-label"></span><input class="bd-cake-color" type="color"></label>
<label class="bd-color"><span class="bd-icing-label"></span><input class="bd-icing-color" type="color"></label>
<label class="bd-color"><span class="bd-plate-label"></span><input class="bd-plate-color" type="color"></label>
<select class="bd-decoration">
<option value="sprinkles"></option><option value="fruit"></option><option value="stars"></option><option value="none"></option>
</select>
<label class="bd-check"><input class="bd-candles" type="checkbox"><span class="bd-candles-label"></span></label>
<button class="tbtn bd-party" type="button"></button>
</div>
<div class="bd-stage">
<div class="bd-title"></div>
<div class="bd-cake" aria-live="polite"></div>
<div class="bd-age-badge"></div>
<div class="bd-plate"></div>
</div>
</div>`;
const q=s=>root.querySelector(s), name=q('.bd-name'), age=q('.bd-age'), layers=q('.bd-layers'),
cakeColor=q('.bd-cake-color'), icingColor=q('.bd-icing-color'), plateColor=q('.bd-plate-color'), decoration=q('.bd-decoration'),
candles=q('.bd-candles'), cake=q('.bd-cake'), title=q('.bd-title'), badge=q('.bd-age-badge');
name.value=S.name; age.value=S.age; layers.value=S.layers; cakeColor.value=S.cake;
icingColor.value=S.icing; plateColor.value=S.plate; decoration.value=S.decoration; candles.checked=S.candles;
function sync(){
S.name=name.value.trim(); S.age=Math.max(1,Math.min(120,+age.value||1)); S.layers=+layers.value;
S.cake=cakeColor.value; S.icing=icingColor.value; S.plate=plateColor.value; S.decoration=decoration.value; S.candles=candles.checked;
render();
}
function render(){
cake.innerHTML="";
for(let n=S.layers;n>=1;n--){
const layer=document.createElement('div'); layer.className='bd-layer bd-layer-'+n;
layer.style.setProperty('--cake',S.cake); layer.style.setProperty('--icing',S.icing);
if(S.decoration!=="none"){
const deco=document.createElement('div'); deco.className='bd-deco '+S.decoration;
deco.textContent=S.decoration==='fruit'?'🍓 🍒 🍓':S.decoration==='stars'?'★ ✦ ★ ✦ ★':'• • • • • •';
layer.appendChild(deco);
}
if(n===S.layers && S.candles){
const row=document.createElement('div'); row.className='bd-candle-row';
const count=Math.min(S.age,20);
for(let i=0;i<count;i++){ const c=document.createElement('i'); c.className='bd-candle'; row.appendChild(c); }
layer.appendChild(row);
}
cake.appendChild(layer);
}
title.textContent=S.name ? T('birthdayFor').replace('{name}',S.name) : T('birthdayTitle');
badge.textContent=String(S.age); badge.style.background=S.icing;
q('.bd-plate').style.background=S.plate;
}
name.addEventListener('keydown',e=>e.stopPropagation());
[name,age,layers,cakeColor,icingColor,plateColor,decoration,candles].forEach(el=>el.addEventListener('input',sync));
q('.bd-party').addEventListener('click',()=>{ confetti(q('.bd-stage')); sndWin(); });
function labels(){
name.placeholder=T('birthdayName'); q('.bd-age-label').textContent=T('birthdayAge');
q('.bd-layers-label').textContent=T('birthdayLayers'); q('.bd-cake-label').textContent=T('birthdayCakeColor');
q('.bd-icing-label').textContent=T('birthdayIcing'); q('.bd-plate-label').textContent=T('birthdayPlate'); q('.bd-candles-label').textContent=T('birthdayCandles');
q('.bd-party').textContent=T('birthdayCelebrate');
const keys=['birthdaySprinkles','birthdayFruit','birthdayStars','birthdayNone'];
[...decoration.options].forEach((o,i)=>o.textContent=T(keys[i])); render();
}
document.addEventListener('langchange',labels); labels();
return { getState:()=>({...S}) };
}