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;
|
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;
|
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;
|
border:2px solid var(--blue); border-radius:10px; padding:9px 10px;
|
||||||
font:inherit; font-size:15px; outline:none; width:180px;
|
font:inherit; font-size:15px; outline:none; width:180px;
|
||||||
}
|
}
|
||||||
|
|
@ -591,6 +591,10 @@
|
||||||
width:40px; height:40px; cursor:pointer; font-size:15px; flex:none;
|
width:40px; height:40px; cursor:pointer; font-size:15px; flex:none;
|
||||||
}
|
}
|
||||||
.ed-theme-del:hover{background:var(--red); color:#fff;}
|
.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-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-stars{color:#d9a400; font-size:14px; min-width:34px; text-align:right;}
|
||||||
.lg-instr{
|
.lg-instr{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
/* version — shown until /api/version resolves (or if the fetch fails, e.g. offline).
|
/* 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. */
|
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(){
|
(function(){
|
||||||
const tag = document.getElementById("verTag");
|
const tag = document.getElementById("verTag");
|
||||||
tag.textContent = "v"+VERSION;
|
tag.textContent = "v"+VERSION;
|
||||||
|
|
@ -53,6 +53,7 @@ const I18N = {
|
||||||
myWords:"Mijn woorden", manage:"Thema's en woorden beheren", addWord:"+ Toevoegen",
|
myWords:"Mijn woorden", manage:"Thema's en woorden beheren", addWord:"+ Toevoegen",
|
||||||
pickPic:"Kies een plaatje",
|
pickPic:"Kies een plaatje",
|
||||||
newTheme:"Nieuw thema", themeNamePh:"naam van het thema…", delTheme:"Thema verwijderen",
|
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 —",
|
numWords:"Woorden per spel", all:"Alle", noThemes:"— nog geen thema's —",
|
||||||
muteAll:"Alle geluiden aan/uit", sndWidget:"Geluid van deze widget aan/uit",
|
muteAll:"Alle geluiden aan/uit", sndWidget:"Geluid van deze widget aan/uit",
|
||||||
catTaal:"Taal", catRekenen:"Rekenen", catClass:"Feest & klas", catTools:"Hulpmiddelen", catMedia:"Media",
|
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",
|
myWords:"My words", manage:"Manage themes and words", addWord:"+ Add",
|
||||||
pickPic:"Choose a picture",
|
pickPic:"Choose a picture",
|
||||||
newTheme:"New theme", themeNamePh:"name of the theme…", delTheme:"Delete theme",
|
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 —",
|
numWords:"Words per game", all:"All", noThemes:"— no themes yet —",
|
||||||
muteAll:"All sounds on/off", sndWidget:"This widget's sound on/off",
|
muteAll:"All sounds on/off", sndWidget:"This widget's sound on/off",
|
||||||
catTaal:"Language", catRekenen:"Maths", catClass:"Celebration & class", catTools:"Tools", catMedia:"Media",
|
catTaal:"Language", catRekenen:"Maths", catClass:"Celebration & class", catTools:"Tools", catMedia:"Media",
|
||||||
|
|
|
||||||
|
|
@ -104,11 +104,26 @@ function fillWordSourceSel(sel, card){
|
||||||
const og = document.createElement("option");
|
const og = document.createElement("option");
|
||||||
og.value = "g"; og.textContent = T("cardGeneral");
|
og.value = "g"; og.textContent = T("cardGeneral");
|
||||||
sel.appendChild(og);
|
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)=>{
|
THEMES[LANG].forEach((th,i)=>{
|
||||||
if(!th.words.length) return;
|
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");
|
const o = document.createElement("option");
|
||||||
o.value = "t"+i; o.textContent = "★ "+th.name;
|
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)=>{
|
anchorSources().forEach((a,i)=>{
|
||||||
const o = document.createElement("option");
|
const o = document.createElement("option");
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,10 @@ function mountAnchor(root, initState, opts){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const name = "⚓ " + reg.name;
|
const name = "⚓ " + reg.name;
|
||||||
if(idx < 0) list.push({ id: S.themeId, name, words: withPic.slice() });
|
/* vaste map "⚓" zodat ankerthema's gegroepeerd staan in de editor- en
|
||||||
else{ list[idx].name = name; list[idx].words = withPic.slice(); }
|
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){
|
function syncSource(quiet){
|
||||||
const center = S.cells["0,0"];
|
const center = S.cells["0,0"];
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ function mountLetterGame(root, initState, opts){
|
||||||
<select class="ed-theme-sel"></select>
|
<select class="ed-theme-sel"></select>
|
||||||
<button class="tbtn ed-theme-add">+</button>
|
<button class="tbtn ed-theme-add">+</button>
|
||||||
<input type="text" class="ed-theme-name" maxlength="16" style="display:none;">
|
<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>
|
<button class="ed-theme-del">🗑</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="lg-ed-form">
|
<div class="lg-ed-form">
|
||||||
|
|
@ -300,7 +302,8 @@ function mountLetterGame(root, initState, opts){
|
||||||
edFile = el(".ed-p-upload input"), edPSearch = el(".ed-psearch"),
|
edFile = el(".ed-p-upload input"), edPSearch = el(".ed-psearch"),
|
||||||
edPGrid = el(".ed-pgrid"), edStatus = el(".ed-status"),
|
edPGrid = el(".ed-pgrid"), edStatus = el(".ed-status"),
|
||||||
edThemeSel = el(".ed-theme-sel"), edThemeAdd = el(".ed-theme-add"),
|
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";
|
let edPic = "", edTab = "emoji", edCat = 0, edTheme = "g";
|
||||||
|
|
||||||
/* ---- word target: the general card or one of the themes ---- */
|
/* ---- word target: the general card or one of the themes ---- */
|
||||||
|
|
@ -312,18 +315,37 @@ function mountLetterGame(root, initState, opts){
|
||||||
og.value = "g";
|
og.value = "g";
|
||||||
og.textContent = `${T("cardGeneral")} (${generalList().length})`;
|
og.textContent = `${T("cardGeneral")} (${generalList().length})`;
|
||||||
edThemeSel.appendChild(og);
|
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)=>{
|
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");
|
const o = document.createElement("option");
|
||||||
o.value = i; o.textContent = `★ ${th.name} (${th.words.length})`;
|
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;
|
edThemeSel.value = edTheme;
|
||||||
edThemeAdd.title = T("newTheme");
|
edThemeAdd.title = T("newTheme");
|
||||||
edThemeDel.title = T("delTheme");
|
edThemeDel.title = T("delTheme");
|
||||||
|
edThemeMv.title = T("themeFolder");
|
||||||
edThemeName.placeholder = T("themeNamePh");
|
edThemeName.placeholder = T("themeNamePh");
|
||||||
|
edThemeFolder.placeholder = T("themeFolderPh");
|
||||||
|
edThemeMv.style.display = edTheme === "g" ? "none" : "";
|
||||||
}
|
}
|
||||||
edThemeSel.addEventListener("change", ()=>{
|
edThemeSel.addEventListener("change", ()=>{
|
||||||
edTheme = edThemeSel.value==="g" ? "g" : +edThemeSel.value;
|
edTheme = edThemeSel.value==="g" ? "g" : +edThemeSel.value;
|
||||||
|
edThemeMv.style.display = edTheme === "g" ? "none" : "";
|
||||||
renderEdList();
|
renderEdList();
|
||||||
});
|
});
|
||||||
edThemeAdd.addEventListener("click", ()=>{
|
edThemeAdd.addEventListener("click", ()=>{
|
||||||
|
|
@ -359,6 +381,34 @@ function mountLetterGame(root, initState, opts){
|
||||||
renderThemeSel(); renderEdList();
|
renderThemeSel(); renderEdList();
|
||||||
document.dispatchEvent(new CustomEvent("wordschange"));
|
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){
|
function selectPic(p, btn){
|
||||||
edPic = p; setPic(edPrev, p);
|
edPic = p; setPic(edPrev, p);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue