Versienummering en Widget Ankerwoorden toegevoegd
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
This commit is contained in:
parent
3a77442abc
commit
334b0f8e14
1 changed files with 202 additions and 77 deletions
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>teach</title>
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%233b7dd8'/%3E%3Ctext x='32' y='46' font-size='40' font-weight='900' font-family='Arial Rounded MT Bold,Arial,sans-serif' text-anchor='middle' fill='%23fff'%3Et%3C/text%3E%3Ccircle cx='47' cy='17' r='7' fill='%23f7c948'/%3E%3C/svg%3E">
|
||||
<style>
|
||||
:root{
|
||||
--bg:#eef3f8; --panel:#ffffff; --ink:#26344a; --muted:#7b8aa3;
|
||||
|
|
@ -41,6 +42,8 @@
|
|||
.logo .l4{color:var(--blue); transform:rotate(5deg) translateY(-1px);}
|
||||
.logo .l5{color:var(--purple); transform:rotate(-4deg);}
|
||||
.logo .crayon{font-size:24px; margin-left:6px; transform:rotate(10deg);}
|
||||
#verTag{font-size:10.5px; font-weight:700; color:var(--muted); align-self:flex-end; margin-left:4px; transform:none;}
|
||||
#verTag.beta{color:#fff; background:var(--orange); padding:1px 7px; border-radius:8px;}
|
||||
.logo:hover span:not(.crayon){animation:bounce .5s;}
|
||||
.logo .l2{animation-delay:.05s;} .logo .l3{animation-delay:.1s;}
|
||||
.logo .l4{animation-delay:.15s;} .logo .l5{animation-delay:.2s;}
|
||||
|
|
@ -132,10 +135,11 @@
|
|||
}
|
||||
.bs-name span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
|
||||
.bs-x{
|
||||
border:none; background:#fbe3e1; color:var(--red); border-radius:6px;
|
||||
min-width:20px; height:20px; font-size:10px; font-weight:900; cursor:pointer; flex:none;
|
||||
border:none; background:#fbe3e1; color:var(--red); border-radius:7px;
|
||||
min-width:26px; height:24px; font-size:11px; font-weight:900; cursor:pointer; flex:none;
|
||||
}
|
||||
.bs-x.arm{background:var(--red); color:#fff;}
|
||||
.bs-x:hover{background:var(--red); color:#fff;}
|
||||
.bs-x.arm{background:var(--red); color:#fff; animation:pop .3s;}
|
||||
.bs-new{
|
||||
display:flex; align-items:center; justify-content:center; font-size:30px;
|
||||
color:#fff; background:var(--green); border-color:var(--green);
|
||||
|
|
@ -834,6 +838,26 @@
|
|||
.bl-msg.win{color:var(--green);}
|
||||
.bl-msg.lose{color:var(--red);}
|
||||
.bl-kbd button:disabled{cursor:default;}
|
||||
/* =========== Anchor words widget =========== */
|
||||
.an{flex:1; min-height:0; display:flex; flex-direction:column;}
|
||||
.an-hint{
|
||||
flex:none; font-size:11.5px; font-weight:700; color:var(--muted);
|
||||
padding:6px 10px; background:#f7fafd; border-bottom:1px solid #e3eaf3;
|
||||
}
|
||||
.an-stage{flex:1; min-height:0; position:relative; overflow:hidden; background:#fff; cursor:grab; touch-action:none;}
|
||||
.an-stage:active{cursor:grabbing;}
|
||||
.an-layer{position:absolute; inset:0;}
|
||||
.an-cell{
|
||||
position:absolute; width:128px; height:56px; border-radius:12px; border:2px dashed #dbe4f0;
|
||||
display:flex; align-items:center; justify-content:center; font-weight:800; font-size:15px;
|
||||
color:var(--ink); padding:2px 8px; overflow:hidden; text-align:center; cursor:pointer;
|
||||
}
|
||||
.an-cell:hover{border-color:#b6c6dc;}
|
||||
.an-cell.filled{border-style:solid; background:#fff; box-shadow:0 3px 8px rgba(30,50,90,.12);}
|
||||
.an-cell.root{border:2.5px solid #d9a400; background:#fff8dd;}
|
||||
.an-cell.root.filled{background:var(--yellow); font-size:16px;}
|
||||
.an-cell input{width:100%; border:none; outline:none; font:inherit; text-align:center; background:transparent;}
|
||||
body.hc .an-cell{border-color:#555; color:#000;}
|
||||
/* =========== Dice widget =========== */
|
||||
.dc{flex:1; min-height:0; display:flex; flex-direction:column; gap:10px; padding:12px; align-items:center;}
|
||||
.dc-row{flex:1; display:flex; gap:14px; align-items:center; justify-content:center; flex-wrap:wrap; cursor:pointer;}
|
||||
|
|
@ -927,6 +951,7 @@
|
|||
<div class="logo" title="teach">
|
||||
<span class="l1">t</span><span class="l2">e</span><span class="l3">a</span><span class="l4">c</span><span class="l5">h</span>
|
||||
<span class="crayon">🖍️</span>
|
||||
<span id="verTag"></span>
|
||||
</div>
|
||||
<button class="tbtn ghost" id="btnMute">🔊</button>
|
||||
<button class="tbtn ghost" id="btnHC">👁</button>
|
||||
|
|
@ -1004,6 +1029,23 @@
|
|||
|
||||
<script>
|
||||
"use strict";
|
||||
/* version — bump on every change (form 0.0.00) */
|
||||
const VERSION = "0.1.00";
|
||||
(function(){
|
||||
const tag = document.getElementById("verTag");
|
||||
tag.textContent = "v"+VERSION;
|
||||
/* dev branch deploys report a dev-… build via /api/version → mark as beta;
|
||||
main/release builds show only the version number */
|
||||
fetch("/api/version")
|
||||
.then(r=>r.ok ? r.json() : null)
|
||||
.then(v=>{
|
||||
if(v && typeof v.version==="string" && v.version.startsWith("dev")){
|
||||
tag.textContent = "v"+VERSION+" · beta";
|
||||
tag.classList.add("beta");
|
||||
}
|
||||
})
|
||||
.catch(()=>{});
|
||||
})();
|
||||
/* =========================================================
|
||||
i18n
|
||||
==========================================================*/
|
||||
|
|
@ -1051,6 +1093,7 @@ const I18N = {
|
|||
toolHand:"Handje: verplaatsen en bedienen",
|
||||
boardsNav:"Borden en mappen", newBoard:"+ Bord", newFolder:"+ Map",
|
||||
folderPh:"naam nieuwe map…", boardName:"Bord", folderName:"Map",
|
||||
delBoard:"Bord verwijderen (2× tikken)",
|
||||
renameTip:"Dubbelklik op een bord om het te hernoemen",
|
||||
hudMin:"Menu inklappen/uitklappen", hudOrient:"Horizontaal of verticaal",
|
||||
wFull:"Maximaliseren", wUnfull:"Terugzetten",
|
||||
|
|
@ -1066,6 +1109,8 @@ const I18N = {
|
|||
wg_hak:"Hakken & plakken", wg_hak_d:"Woorden in klanken hakken en weer plakken, met voorlezen.",
|
||||
hakChop:"✂️ Hak", hakGlue:"🔗 Plak", hakSay:"🔊 Lees voor",
|
||||
wg_ball:"Ballonnenwoord", wg_ball_d:"Raad het woord letter voor letter voordat de ballonnen knappen.",
|
||||
wg_anchor:"Ankerwoorden", wg_anchor_d:"Onbeperkt woordraster rond een thema: elk woord hoort bij de woorden eromheen.",
|
||||
anchorPh:"thema…", anchorHint:"Tik op een vak en typ · sleep de achtergrond om te schuiven",
|
||||
ballWin:"Geraden! 🎉", ballLose:"Helaas! Het woord was:",
|
||||
bgDots:"Stippen", toolRuler:"Liniaal", toolGeo:"Geodriehoek", toolLens:"Vergrootglas",
|
||||
wg_mind:"Mindmap", wg_mind_d:"Woordweb, spin of boomdiagram om samen ideeën te ordenen.",
|
||||
|
|
@ -1144,6 +1189,7 @@ const I18N = {
|
|||
toolHand:"Hand: move and interact",
|
||||
boardsNav:"Boards and folders", newBoard:"+ Board", newFolder:"+ Folder",
|
||||
folderPh:"name of new folder…", boardName:"Board", folderName:"Folder",
|
||||
delBoard:"Delete board (tap twice)",
|
||||
renameTip:"Double-click a board to rename it",
|
||||
hudMin:"Collapse/expand menu", hudOrient:"Horizontal or vertical",
|
||||
wFull:"Maximize", wUnfull:"Restore",
|
||||
|
|
@ -1159,6 +1205,8 @@ const I18N = {
|
|||
wg_hak:"Chop & blend", wg_hak_d:"Chop words into sounds and blend them back, with read-aloud.",
|
||||
hakChop:"✂️ Chop", hakGlue:"🔗 Blend", hakSay:"🔊 Read aloud",
|
||||
wg_ball:"Balloon word", wg_ball_d:"Guess the word letter by letter before the balloons pop.",
|
||||
wg_anchor:"Anchor words", wg_anchor_d:"Unlimited word grid around a theme: every word relates to its neighbours.",
|
||||
anchorPh:"theme…", anchorHint:"Tap a cell and type · drag the background to pan",
|
||||
ballWin:"You got it! 🎉", ballLose:"Oh no! The word was:",
|
||||
bgDots:"Dots", toolRuler:"Ruler", toolGeo:"Set square", toolLens:"Magnifier",
|
||||
wg_mind:"Mind map", wg_mind_d:"Word web, spider or tree diagram to organise ideas together.",
|
||||
|
|
@ -1347,6 +1395,7 @@ const REGISTRY = [
|
|||
{ id:"flits", cat:"taal", icon:"⚡", w:520, h:430, minW:400, minH:330, mount:mountFlits },
|
||||
{ id:"hak", cat:"taal", icon:"✂️", w:540, h:440, minW:420, minH:340, mount:mountHak },
|
||||
{ id:"ball", cat:"taal", icon:"🎈", w:620, h:560, minW:480, minH:440, mount:mountBall },
|
||||
{ id:"anchor", cat:"taal", icon:"⚓", w:680, h:500, minW:440, minH:340, mount:mountAnchor },
|
||||
{ id:"madd", cat:"rekenen", icon:"➕", w:460, h:620, minW:380, minH:520, mount:(r,s)=>mountMath(r,s,"add") },
|
||||
{ id:"msub", cat:"rekenen", icon:"➖", w:460, h:620, minW:380, minH:520, mount:(r,s)=>mountMath(r,s,"sub") },
|
||||
{ id:"mmul", cat:"rekenen", icon:"✖️", w:460, h:620, minW:380, minH:520, mount:(r,s)=>mountMath(r,s,"mul") },
|
||||
|
|
@ -2027,14 +2076,13 @@ fab.addEventListener("click", ()=>{
|
|||
fabMenu.classList.toggle("open");
|
||||
const open = fabMenu.classList.contains("open");
|
||||
fab.classList.toggle("open", open);
|
||||
document.getElementById("fabArc").classList.toggle("hide", open);
|
||||
if(open) document.getElementById("boardStrip").classList.remove("open");
|
||||
});
|
||||
document.addEventListener("pointerdown", e=>{
|
||||
if(!fabMenu.classList.contains("open")) return;
|
||||
if(e.target.closest("#fab") || e.target.closest("#fabmenu")) return;
|
||||
fabMenu.classList.remove("open");
|
||||
fab.classList.remove("open");
|
||||
document.getElementById("fabArc").classList.remove("hide");
|
||||
});
|
||||
fabMenu.querySelector('[data-f="widgets"]').addEventListener("click", ()=>{
|
||||
fabMenu.classList.remove("open"); fab.classList.remove("open");
|
||||
|
|
@ -2264,11 +2312,13 @@ function renderStrip(){
|
|||
const x = document.createElement("button");
|
||||
x.className = "bs-x"; x.textContent = "✕";
|
||||
x.title = T("delBoard");
|
||||
x.addEventListener("pointerdown", ev=>ev.stopPropagation());
|
||||
x.addEventListener("click", ev=>{
|
||||
ev.stopPropagation();
|
||||
if(!x.dataset.arm){ /* first click arms, second click deletes */
|
||||
x.dataset.arm = "1"; x.classList.add("arm"); x.textContent = "?";
|
||||
setTimeout(()=>{ x.dataset.arm=""; x.classList.remove("arm"); x.textContent="✕"; }, 2000);
|
||||
clearTimeout(stripTimer); /* keep the strip open while confirming */
|
||||
x.dataset.arm = "1"; x.classList.add("arm"); x.textContent = "✓?";
|
||||
setTimeout(()=>{ x.dataset.arm=""; x.classList.remove("arm"); x.textContent="✕"; }, 3000);
|
||||
return;
|
||||
}
|
||||
const fo = BS.folders[it.fi];
|
||||
|
|
@ -2485,6 +2535,38 @@ function setPic(el, pic){
|
|||
else el.textContent = pic;
|
||||
}
|
||||
|
||||
/* ---- shared word source (built-in cards + own themes) for all word widgets ---- */
|
||||
function normWordSource(card){
|
||||
if(typeof card==="string" && card.startsWith("t")){
|
||||
const th = THEMES[LANG][+card.slice(1)];
|
||||
if(th && th.words.length) return card;
|
||||
return 0;
|
||||
}
|
||||
if(typeof card!=="number" || card >= WORDS[LANG].length || card < 0) return 0;
|
||||
return card;
|
||||
}
|
||||
function wordSourceList(card){
|
||||
card = normWordSource(card);
|
||||
if(typeof card==="string") return THEMES[LANG][+card.slice(1)].words;
|
||||
return WORDS[LANG][card];
|
||||
}
|
||||
function fillWordSourceSel(sel, card){
|
||||
sel.innerHTML = "";
|
||||
WORDS[LANG].forEach((_,i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = i; o.textContent = `${T("card")} ${i+1}`;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
THEMES[LANG].forEach((th,i)=>{
|
||||
if(!th.words.length) return;
|
||||
const o = document.createElement("option");
|
||||
o.value = "t"+i; o.textContent = "★ "+th.name;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
sel.value = String(normWordSource(card));
|
||||
if(sel.selectedIndex < 0) sel.selectedIndex = 0;
|
||||
}
|
||||
|
||||
/* emoji palette (grouped) */
|
||||
const splitEmoji = s => {
|
||||
const out = [];
|
||||
|
|
@ -3915,29 +3997,9 @@ function mountFlits(root, initState){
|
|||
const srcSel = el(".fl-src"), durSel = el(".fl-dur"),
|
||||
wordEl = el(".fl-word"), picEl = el(".fl-pic"), cntEl = el(".fl-cnt");
|
||||
|
||||
function list(){
|
||||
if(typeof S.card==="string" && S.card.startsWith("t")){
|
||||
const th = THEMES[LANG][+S.card.slice(1)];
|
||||
if(th && th.words.length) return th.words;
|
||||
S.card = 0;
|
||||
}
|
||||
if(typeof S.card==="number" && S.card >= WORDS[LANG].length) S.card = 0;
|
||||
return WORDS[LANG][S.card];
|
||||
}
|
||||
function list(){ S.card = normWordSource(S.card); return wordSourceList(S.card); }
|
||||
function buildSrc(){
|
||||
srcSel.innerHTML = "";
|
||||
WORDS[LANG].forEach((_,i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = i; o.textContent = `${T("card")} ${i+1}`;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
THEMES[LANG].forEach((th,i)=>{
|
||||
if(!th.words.length) return;
|
||||
const o = document.createElement("option");
|
||||
o.value = "t"+i; o.textContent = th.name;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
srcSel.value = S.card;
|
||||
fillWordSourceSel(srcSel, S.card);
|
||||
durSel.innerHTML = "";
|
||||
[0.5,1,2,3,5].forEach(d=>{
|
||||
const o = document.createElement("option");
|
||||
|
|
@ -4024,30 +4086,8 @@ function mountHak(root, initState){
|
|||
const srcSel = el(".hk-src"), wordEl = el(".hk-word"),
|
||||
picEl = el(".hk-pic"), cntEl = el(".hk-cnt");
|
||||
|
||||
function list(){
|
||||
if(typeof S.card==="string" && S.card.startsWith("t")){
|
||||
const th = THEMES[LANG][+S.card.slice(1)];
|
||||
if(th && th.words.length) return th.words;
|
||||
S.card = 0;
|
||||
}
|
||||
if(typeof S.card==="number" && S.card >= WORDS[LANG].length) S.card = 0;
|
||||
return WORDS[LANG][S.card];
|
||||
}
|
||||
function buildSrc(){
|
||||
srcSel.innerHTML = "";
|
||||
WORDS[LANG].forEach((_,i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = i; o.textContent = `${T("card")} ${i+1}`;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
THEMES[LANG].forEach((th,i)=>{
|
||||
if(!th.words.length) return;
|
||||
const o = document.createElement("option");
|
||||
o.value = "t"+i; o.textContent = th.name;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
srcSel.value = S.card;
|
||||
}
|
||||
function list(){ S.card = normWordSource(S.card); return wordSourceList(S.card); }
|
||||
function buildSrc(){ fillWordSourceSel(srcSel, S.card); }
|
||||
function cur(){ return list()[S.order[S.idx]]; }
|
||||
function newRound(){ S.order = shuffle(list().map((_,i)=>i)); S.idx = 0; }
|
||||
function display(){
|
||||
|
|
@ -4110,6 +4150,113 @@ function mountHak(root, initState){
|
|||
return { getState: ()=>({card:S.card}) };
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
Anchor words — unlimited word grid around a theme
|
||||
==========================================================*/
|
||||
function mountAnchor(root, initState){
|
||||
const CW = 128, CH = 56, G = 10;
|
||||
const S = { cells:{}, pan:{x:0, y:0} };
|
||||
if(initState){
|
||||
S.cells = initState.cells || {};
|
||||
S.pan = initState.pan || {x:0, y:0};
|
||||
}
|
||||
root.innerHTML = `
|
||||
<div class="an">
|
||||
<div class="an-hint"></div>
|
||||
<div class="an-stage"><div class="an-layer"></div></div>
|
||||
</div>`;
|
||||
const stage = root.querySelector(".an-stage"),
|
||||
layer = root.querySelector(".an-layer"),
|
||||
hint = root.querySelector(".an-hint");
|
||||
const ringColor = r => r===0 ? "#d9a400" : ["#3fae6a","#3b7dd8","#9b59b6","#f28c38"][r-1] || "#8fa1b8";
|
||||
const key = (x,y)=>x+","+y;
|
||||
function applyPan(){ layer.style.transform = `translate(${-S.pan.x}px,${-S.pan.y}px)`; }
|
||||
function render(){
|
||||
layer.innerHTML = "";
|
||||
const w = stage.offsetWidth, h = stage.offsetHeight;
|
||||
if(w < 2) return;
|
||||
const cx = w/2, cy = h/2;
|
||||
const x0 = Math.floor((S.pan.x - cx - CW)/(CW+G)), x1 = Math.ceil((S.pan.x + w - cx + CW)/(CW+G));
|
||||
const y0 = Math.floor((S.pan.y - cy - CH)/(CH+G)), y1 = Math.ceil((S.pan.y + h - cy + CH)/(CH+G));
|
||||
for(let gx=x0; gx<=x1; gx++){
|
||||
for(let gy=y0; gy<=y1; gy++){
|
||||
const c = document.createElement("div");
|
||||
const word = S.cells[key(gx,gy)];
|
||||
const ring = Math.max(Math.abs(gx), Math.abs(gy));
|
||||
c.className = "an-cell" + (word ? " filled" : "") + (ring===0 ? " root" : "");
|
||||
c.style.left = (cx + gx*(CW+G) - CW/2)+"px";
|
||||
c.style.top = (cy + gy*(CH+G) - CH/2)+"px";
|
||||
if(word){
|
||||
c.textContent = word;
|
||||
if(ring>0) c.style.borderColor = ringColor(ring);
|
||||
}
|
||||
c.dataset.gx = gx; c.dataset.gy = gy;
|
||||
layer.appendChild(c);
|
||||
}
|
||||
}
|
||||
applyPan();
|
||||
hint.textContent = T("anchorHint");
|
||||
}
|
||||
/* pan by dragging, click (without moving) to type */
|
||||
let pd = null;
|
||||
stage.addEventListener("pointerdown", e=>{
|
||||
if(e.target.tagName==="INPUT") return;
|
||||
if(e.pointerType==="mouse" && e.button!==0) return;
|
||||
e.preventDefault();
|
||||
stage.setPointerCapture(e.pointerId);
|
||||
const sc = stage.getBoundingClientRect().width / stage.offsetWidth;
|
||||
pd = { x:e.clientX/sc, y:e.clientY/sc, px:S.pan.x, py:S.pan.y,
|
||||
moved:false, target:e.target.closest(".an-cell"), sc };
|
||||
});
|
||||
stage.addEventListener("pointermove", e=>{
|
||||
if(!pd) return;
|
||||
const dx = e.clientX/pd.sc - pd.x, dy = e.clientY/pd.sc - pd.y;
|
||||
if(Math.abs(dx) > 6 || Math.abs(dy) > 6) pd.moved = true;
|
||||
if(pd.moved){ S.pan.x = pd.px - dx; S.pan.y = pd.py - dy; applyPan(); }
|
||||
});
|
||||
stage.addEventListener("pointerup", ()=>{
|
||||
if(!pd) return;
|
||||
const {moved, target} = pd;
|
||||
pd = null;
|
||||
if(moved){ render(); return; }
|
||||
if(target) editCell(target);
|
||||
});
|
||||
stage.addEventListener("pointercancel", ()=>{
|
||||
const moved = pd && pd.moved;
|
||||
pd = null;
|
||||
if(moved) render();
|
||||
});
|
||||
function editCell(cell){
|
||||
if(cell.querySelector("input")) return;
|
||||
const gx = +cell.dataset.gx, gy = +cell.dataset.gy, k = key(gx,gy);
|
||||
const inp = document.createElement("input");
|
||||
inp.maxLength = 24;
|
||||
inp.value = S.cells[k] || "";
|
||||
if(gx===0 && gy===0) inp.placeholder = T("anchorPh");
|
||||
cell.textContent = "";
|
||||
cell.appendChild(inp);
|
||||
setTimeout(()=>{ inp.focus(); inp.select(); }, 0);
|
||||
let done = false;
|
||||
const commit = ()=>{
|
||||
if(done) return; done = true;
|
||||
const v = inp.value.trim();
|
||||
if(v) S.cells[k] = v; else delete S.cells[k];
|
||||
render();
|
||||
};
|
||||
inp.addEventListener("keydown", ev=>{
|
||||
ev.stopPropagation();
|
||||
if(ev.key==="Enter") commit();
|
||||
if(ev.key==="Escape"){ done = true; render(); }
|
||||
});
|
||||
inp.addEventListener("blur", commit);
|
||||
inp.addEventListener("pointerdown", ev=>ev.stopPropagation());
|
||||
}
|
||||
new ResizeObserver(render).observe(stage);
|
||||
document.addEventListener("langchange", render);
|
||||
render();
|
||||
return { getState: ()=>({ cells:S.cells, pan:S.pan }) };
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
Balloon word widget — guess before the balloons pop
|
||||
==========================================================*/
|
||||
|
|
@ -4139,30 +4286,8 @@ function mountBall(root, initState){
|
|||
nextBtn = el(".bl-next"), kbdEl = el(".bl-kbd"),
|
||||
scoreEl = el(".bl-score"), sndBtn = el(".lg-snd");
|
||||
|
||||
function list(){
|
||||
if(typeof S.card==="string" && S.card.startsWith("t")){
|
||||
const th = THEMES[LANG][+S.card.slice(1)];
|
||||
if(th && th.words.length) return th.words;
|
||||
S.card = 0;
|
||||
}
|
||||
if(typeof S.card==="number" && S.card >= WORDS[LANG].length) S.card = 0;
|
||||
return WORDS[LANG][S.card];
|
||||
}
|
||||
function buildSrc(){
|
||||
srcSel.innerHTML = "";
|
||||
WORDS[LANG].forEach((_,i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = i; o.textContent = `${T("card")} ${i+1}`;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
THEMES[LANG].forEach((th,i)=>{
|
||||
if(!th.words.length) return;
|
||||
const o = document.createElement("option");
|
||||
o.value = "t"+i; o.textContent = th.name;
|
||||
srcSel.appendChild(o);
|
||||
});
|
||||
srcSel.value = S.card;
|
||||
}
|
||||
function list(){ S.card = normWordSource(S.card); return wordSourceList(S.card); }
|
||||
function buildSrc(){ fillWordSourceSel(srcSel, S.card); }
|
||||
"abcdefghijklmnopqrstuvwxyz".split("").forEach(l=>{
|
||||
const b = document.createElement("button");
|
||||
b.textContent = l; b.dataset.l = l;
|
||||
|
|
|
|||
Loading…
Reference in a new issue