Verbeter anatomie en plaatsing van avataraccessoires (v0.4.46-beta) #1
6 changed files with 81 additions and 8 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
0.3.20-beta
|
||||
0.3.21-beta
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@
|
|||
flex:1; min-width:0; border:1px solid var(--line); border-radius:10px; padding:9px 10px;
|
||||
font:inherit; font-weight:700; font-size:15px; outline:none; background:var(--surface); cursor:pointer;
|
||||
}
|
||||
.ed-theme-name{
|
||||
.ed-theme-name, .ed-theme-folder{
|
||||
border:2px solid var(--blue); border-radius:10px; padding:9px 10px;
|
||||
font:inherit; font-size:15px; outline:none; width:180px;
|
||||
}
|
||||
|
|
@ -591,6 +591,10 @@
|
|||
width:40px; height:40px; cursor:pointer; font-size:15px; flex:none;
|
||||
}
|
||||
.ed-theme-del:hover{background:var(--red); color:#fff;}
|
||||
.ed-theme-mv{
|
||||
border:none; background:var(--surface-2, #eef); color:var(--ink); border-radius:10px;
|
||||
width:40px; height:40px; cursor:pointer; font-size:15px; flex:none;
|
||||
}
|
||||
.lg-progress{margin-left:auto; font-size:13.5px; font-weight:700; color:var(--muted); display:flex; align-items:center; gap:8px; white-space:nowrap;}
|
||||
.lg-stars{color:#d9a400; font-size:14px; min-width:34px; text-align:right;}
|
||||
.lg-instr{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"use strict";
|
||||
/* version — shown until /api/version resolves (or if the fetch fails, e.g. offline).
|
||||
Kept in sync by hand with the VERSION file at the repo root on every release. */
|
||||
const VERSION = "0.3.20-beta";
|
||||
const VERSION = "0.3.21-beta";
|
||||
(function(){
|
||||
const tag = document.getElementById("verTag");
|
||||
tag.textContent = "v"+VERSION;
|
||||
|
|
@ -53,6 +53,7 @@ const I18N = {
|
|||
myWords:"Mijn woorden", manage:"Thema's en woorden beheren", addWord:"+ Toevoegen",
|
||||
pickPic:"Kies een plaatje",
|
||||
newTheme:"Nieuw thema", themeNamePh:"naam van het thema…", delTheme:"Thema verwijderen",
|
||||
themeFolder:"Thema in een map zetten", themeFolderPh:"mapnaam (leeg = geen map)…",
|
||||
numWords:"Woorden per spel", all:"Alle", noThemes:"— nog geen thema's —",
|
||||
muteAll:"Alle geluiden aan/uit", sndWidget:"Geluid van deze widget aan/uit",
|
||||
catTaal:"Taal", catRekenen:"Rekenen", catClass:"Feest & klas", catTools:"Hulpmiddelen", catMedia:"Media",
|
||||
|
|
@ -220,6 +221,7 @@ const I18N = {
|
|||
myWords:"My words", manage:"Manage themes and words", addWord:"+ Add",
|
||||
pickPic:"Choose a picture",
|
||||
newTheme:"New theme", themeNamePh:"name of the theme…", delTheme:"Delete theme",
|
||||
themeFolder:"Put theme in a folder", themeFolderPh:"folder name (empty = no folder)…",
|
||||
numWords:"Words per game", all:"All", noThemes:"— no themes yet —",
|
||||
muteAll:"All sounds on/off", sndWidget:"This widget's sound on/off",
|
||||
catTaal:"Language", catRekenen:"Maths", catClass:"Celebration & class", catTools:"Tools", catMedia:"Media",
|
||||
|
|
|
|||
|
|
@ -104,11 +104,26 @@ function fillWordSourceSel(sel, card){
|
|||
const og = document.createElement("option");
|
||||
og.value = "g"; og.textContent = T("cardGeneral");
|
||||
sel.appendChild(og);
|
||||
/* thema's zonder map bovenaan, daarna per map gegroepeerd (optgroup) -
|
||||
zelfde indeling als de theme-dropdown in de woorden-editor */
|
||||
const groups = new Map();
|
||||
THEMES[LANG].forEach((th,i)=>{
|
||||
if(!th.words.length) return;
|
||||
const f = th.folder || "";
|
||||
if(!groups.has(f)) groups.set(f, []);
|
||||
groups.get(f).push([th, i]);
|
||||
});
|
||||
const addOpt = (parent, th, i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = "t"+i; o.textContent = "★ "+th.name;
|
||||
sel.appendChild(o);
|
||||
parent.appendChild(o);
|
||||
};
|
||||
(groups.get("") || []).forEach(([th,i])=>addOpt(sel, th, i));
|
||||
[...groups.keys()].filter(f=>f).sort().forEach(f=>{
|
||||
const grp = document.createElement("optgroup");
|
||||
grp.label = "📁 " + f;
|
||||
groups.get(f).forEach(([th,i])=>addOpt(grp, th, i));
|
||||
sel.appendChild(grp);
|
||||
});
|
||||
anchorSources().forEach((a,i)=>{
|
||||
const o = document.createElement("option");
|
||||
|
|
|
|||
|
|
@ -65,8 +65,10 @@ function mountAnchor(root, initState, opts){
|
|||
return;
|
||||
}
|
||||
const name = "⚓ " + reg.name;
|
||||
if(idx < 0) list.push({ id: S.themeId, name, words: withPic.slice() });
|
||||
else{ list[idx].name = name; list[idx].words = withPic.slice(); }
|
||||
/* vaste map "⚓" zodat ankerthema's gegroepeerd staan in de editor- en
|
||||
widget-dropdowns (zie de optgroup-weergave in letters.js/data.js) */
|
||||
if(idx < 0) list.push({ id: S.themeId, name, folder: "⚓", words: withPic.slice() });
|
||||
else{ list[idx].name = name; list[idx].folder = "⚓"; list[idx].words = withPic.slice(); }
|
||||
}
|
||||
function syncSource(quiet){
|
||||
const center = S.cells["0,0"];
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ function mountLetterGame(root, initState, opts){
|
|||
<select class="ed-theme-sel"></select>
|
||||
<button class="tbtn ed-theme-add">+</button>
|
||||
<input type="text" class="ed-theme-name" maxlength="16" style="display:none;">
|
||||
<button class="ed-theme-mv">📁</button>
|
||||
<input type="text" class="ed-theme-folder" maxlength="16" style="display:none;">
|
||||
<button class="ed-theme-del">🗑</button>
|
||||
</div>
|
||||
<div class="lg-ed-form">
|
||||
|
|
@ -300,7 +302,8 @@ function mountLetterGame(root, initState, opts){
|
|||
edFile = el(".ed-p-upload input"), edPSearch = el(".ed-psearch"),
|
||||
edPGrid = el(".ed-pgrid"), edStatus = el(".ed-status"),
|
||||
edThemeSel = el(".ed-theme-sel"), edThemeAdd = el(".ed-theme-add"),
|
||||
edThemeName = el(".ed-theme-name"), edThemeDel = el(".ed-theme-del");
|
||||
edThemeName = el(".ed-theme-name"), edThemeDel = el(".ed-theme-del"),
|
||||
edThemeMv = el(".ed-theme-mv"), edThemeFolder = el(".ed-theme-folder");
|
||||
let edPic = "", edTab = "emoji", edCat = 0, edTheme = "g";
|
||||
|
||||
/* ---- word target: the general card or one of the themes ---- */
|
||||
|
|
@ -312,18 +315,37 @@ function mountLetterGame(root, initState, opts){
|
|||
og.value = "g";
|
||||
og.textContent = `${T("cardGeneral")} (${generalList().length})`;
|
||||
edThemeSel.appendChild(og);
|
||||
/* thema's zonder map bovenaan, daarna per map gegroepeerd - zelfde
|
||||
indeling als fillWordSourceSel (data.js) in de widget-dropdowns */
|
||||
const groups = new Map();
|
||||
list.forEach((th,i)=>{
|
||||
const f = th.folder || "";
|
||||
if(!groups.has(f)) groups.set(f, []);
|
||||
groups.get(f).push([th, i]);
|
||||
});
|
||||
const addOpt = (parent, th, i)=>{
|
||||
const o = document.createElement("option");
|
||||
o.value = i; o.textContent = `★ ${th.name} (${th.words.length})`;
|
||||
edThemeSel.appendChild(o);
|
||||
parent.appendChild(o);
|
||||
};
|
||||
(groups.get("") || []).forEach(([th,i])=>addOpt(edThemeSel, th, i));
|
||||
[...groups.keys()].filter(f=>f).sort().forEach(f=>{
|
||||
const grp = document.createElement("optgroup");
|
||||
grp.label = "📁 " + f;
|
||||
groups.get(f).forEach(([th,i])=>addOpt(grp, th, i));
|
||||
edThemeSel.appendChild(grp);
|
||||
});
|
||||
edThemeSel.value = edTheme;
|
||||
edThemeAdd.title = T("newTheme");
|
||||
edThemeDel.title = T("delTheme");
|
||||
edThemeMv.title = T("themeFolder");
|
||||
edThemeName.placeholder = T("themeNamePh");
|
||||
edThemeFolder.placeholder = T("themeFolderPh");
|
||||
edThemeMv.style.display = edTheme === "g" ? "none" : "";
|
||||
}
|
||||
edThemeSel.addEventListener("change", ()=>{
|
||||
edTheme = edThemeSel.value==="g" ? "g" : +edThemeSel.value;
|
||||
edThemeMv.style.display = edTheme === "g" ? "none" : "";
|
||||
renderEdList();
|
||||
});
|
||||
edThemeAdd.addEventListener("click", ()=>{
|
||||
|
|
@ -359,6 +381,34 @@ function mountLetterGame(root, initState, opts){
|
|||
renderThemeSel(); renderEdList();
|
||||
document.dispatchEvent(new CustomEvent("wordschange"));
|
||||
});
|
||||
/* thema in een map zetten (of eruit halen met een leeg veld): 📁 toont een
|
||||
inline invoer, voorgevuld met de huidige map van het gekozen thema */
|
||||
edThemeMv.addEventListener("click", ()=>{
|
||||
if(edTheme==="g") return;
|
||||
edThemeFolder.style.display = "block";
|
||||
edThemeFolder.value = THEMES[S.lang][edTheme].folder || "";
|
||||
edThemeFolder.focus();
|
||||
});
|
||||
let folderDone = false;
|
||||
function commitFolder(){
|
||||
if(folderDone) return; folderDone = true;
|
||||
if(edTheme !== "g" && THEMES[S.lang][edTheme]){
|
||||
const f = edThemeFolder.value.trim();
|
||||
const th = THEMES[S.lang][edTheme];
|
||||
if(f) th.folder = f; else delete th.folder;
|
||||
persistWords();
|
||||
renderThemeSel();
|
||||
document.dispatchEvent(new CustomEvent("wordschange"));
|
||||
}
|
||||
edThemeFolder.style.display = "none";
|
||||
setTimeout(()=>{ folderDone = false; }, 100);
|
||||
}
|
||||
edThemeFolder.addEventListener("keydown", ev=>{
|
||||
ev.stopPropagation();
|
||||
if(ev.key==="Enter") commitFolder();
|
||||
if(ev.key==="Escape"){ folderDone=true; edThemeFolder.style.display="none"; setTimeout(()=>{folderDone=false;},100); }
|
||||
});
|
||||
edThemeFolder.addEventListener("blur", commitFolder);
|
||||
|
||||
function selectPic(p, btn){
|
||||
edPic = p; setPic(edPrev, p);
|
||||
|
|
|
|||
Loading…
Reference in a new issue