Verbeter grafische kwaliteit van kleurplaten (v0.4.67-beta) #5
3 changed files with 107 additions and 10 deletions
|
|
@ -5,6 +5,8 @@
|
|||
--yellow:#f7c948; --purple:#9b59b6; --orange:#f28c38;
|
||||
--wood:#f6e7c9; --wood-d:#e8d2a4;
|
||||
--radius:16px; --shadow:0 10px 30px rgba(30,50,90,.18);
|
||||
/* minimale tikzones voor touch (WCAG/iOS-richtlijn) */
|
||||
--tap:44px; --tap-sm:36px;
|
||||
}
|
||||
*{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
|
||||
*::-webkit-scrollbar{width:8px; height:8px;}
|
||||
|
|
@ -310,7 +312,7 @@
|
|||
backdrop-filter:blur(14px) saturate(1.15); -webkit-backdrop-filter:blur(14px) saturate(1.15);
|
||||
box-shadow:0 4px 14px rgba(30,50,90,.08); border:1px solid rgba(255,255,255,.6);
|
||||
display:flex; flex-direction:column;
|
||||
min-width:280px; min-height:200px; resize:both; overflow:hidden;
|
||||
min-width:280px; min-height:200px; resize:none; overflow:hidden;
|
||||
transition:background .2s, box-shadow .2s, border-color .2s;
|
||||
}
|
||||
.widget:hover,.widget:focus-within{
|
||||
|
|
@ -321,6 +323,17 @@
|
|||
.widget .wmin,.widget .wclose{opacity:.4; transition:opacity .15s;}
|
||||
.widget:hover .wmin,.widget:hover .wclose,
|
||||
.widget:focus-within .wmin,.widget:focus-within .wclose{opacity:1;}
|
||||
/* eigen, groter aanraakbare resize-greep i.p.v. de piepkleine native
|
||||
browser-grip (die met resize:none hierboven is uitgeschakeld) */
|
||||
.widget-rs{
|
||||
position:absolute; right:4px; bottom:4px; width:34px; height:34px;
|
||||
border-radius:50%; background:var(--blue); border:3px solid #fff;
|
||||
cursor:nwse-resize; box-shadow:0 2px 6px rgba(0,0,0,.3); touch-action:none;
|
||||
opacity:0; transition:opacity .15s; z-index:2;
|
||||
}
|
||||
.widget:hover .widget-rs,.widget:focus-within .widget-rs{opacity:.6;}
|
||||
.widget-rs:hover,.widget-rs:active{opacity:1 !important;}
|
||||
.widget.bare .widget-rs,.widget[data-max="1"] .widget-rs{display:none;}
|
||||
/* unified floating bar: pen palette + dock, draggable, combined when both active */
|
||||
#hud{
|
||||
position:fixed; left:50%; bottom:16px; transform:translateX(-50%); z-index:5500;
|
||||
|
|
@ -758,6 +771,7 @@
|
|||
body.hc .widget{background:#fff; border:2.5px solid #000; box-shadow:0 4px 14px rgba(0,0,0,.35); backdrop-filter:none;}
|
||||
body.hc .widget:hover,.body.hc .widget:focus-within{background:#fff;}
|
||||
body.hc .widget .wmin,body.hc .widget .wclose{opacity:1;}
|
||||
body.hc .widget-rs{opacity:1; border:3px solid #000;}
|
||||
body.hc .widget-head{background:#f2f2f2; border-bottom:2px solid #000;}
|
||||
body.hc .slot{border-color:#000; background:#fff;}
|
||||
body.hc .slot .ghost{color:#666;}
|
||||
|
|
@ -987,6 +1001,7 @@
|
|||
font-size:13px; width:110px; outline:none;
|
||||
}
|
||||
.am-code{font-size:12.5px; font-weight:800; color:var(--orange);}
|
||||
.am-actions{display:flex; align-items:center; gap:8px; flex-wrap:wrap;}
|
||||
.am-btn{
|
||||
border:none; background:#e8eef6; border-radius:8px; padding:6px 10px;
|
||||
font:inherit; font-weight:800; font-size:12px; cursor:pointer; color:var(--ink);
|
||||
|
|
@ -1022,3 +1037,48 @@
|
|||
.am-reset-pw{font-weight:800; font-family:monospace; font-size:13px; color:var(--green);}
|
||||
body.hc .am-row,body.hc .am-chip{border:1.5px solid #000; background:#fff;}
|
||||
body.hc .am-reset,body.hc .am-reset-row{border:1.5px solid #000; background:#fff;}
|
||||
|
||||
/* ============================================================
|
||||
Mobiel & tablet: responsieve aanpassingen. Alles hieronder is
|
||||
additief - de bovenstaande desktopstijl blijft de standaard.
|
||||
============================================================ */
|
||||
|
||||
/* ---------- tablet (≤1024px) ---------- */
|
||||
@media (max-width:1024px){
|
||||
/* #boardsPanel had een vaste 300px-breedte die op smallere
|
||||
schermen overflowt; #boardStrip deed dit al goed. */
|
||||
#boardsPanel{width:min(300px, calc(100vw - 32px));}
|
||||
}
|
||||
|
||||
/* ---------- telefoon (≤600px) ---------- */
|
||||
@media (max-width:600px){
|
||||
#toolbar{padding:0 8px; gap:6px;}
|
||||
.logo{font-size:22px;}
|
||||
.logo .crayon{font-size:18px; margin-left:4px;}
|
||||
#verTag{display:none;}
|
||||
.tbtn{padding:8px 10px; font-size:13px;}
|
||||
#boardsPanel{top:60px; max-height:min(66vh,480px);}
|
||||
|
||||
/* beheerpaneel: dichte rijen worden gestapeld i.p.v. verdrukt */
|
||||
.am-row{flex-direction:column; align-items:stretch;}
|
||||
.am-row .am-pw{width:100%;}
|
||||
.am-row .am-actions{display:flex; flex-direction:row; justify-content:flex-end; gap:6px;}
|
||||
.am-reset-row{flex-direction:column; align-items:stretch;}
|
||||
.am-add .am-inp{flex:1 1 100%;}
|
||||
}
|
||||
|
||||
/* ---------- aanraakschermen (los van breedte) ---------- */
|
||||
@media (pointer:coarse){
|
||||
.tbtn{min-height:var(--tap-sm);}
|
||||
#langToggle button{min-height:var(--tap-sm);}
|
||||
.hud-btn{width:var(--tap-sm); height:var(--tap-sm); font-size:15px;}
|
||||
#penbar .wp-group button{width:var(--tap-sm); height:var(--tap-sm);}
|
||||
#hud.vert{width:104px;}
|
||||
#hud.vert #penbar .wp-group{grid-template-columns:repeat(2,36px);}
|
||||
.am-btn,.am-copy{min-height:var(--tap-sm); padding:8px 12px;}
|
||||
.am-del{width:var(--tap-sm); height:var(--tap-sm);}
|
||||
.am-chip{padding:7px 14px;}
|
||||
.am-chipx{padding:4px;}
|
||||
/* geen hover op aanraakschermen: de greep moet altijd zichtbaar zijn */
|
||||
.widget-rs{opacity:.7; width:38px; height:38px;}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@
|
|||
|
||||
function userRow(u){
|
||||
const row = h("div","am-row");
|
||||
/* actieknoppen (kopieer/genereer/verwijder) samen in één groep, zodat
|
||||
ze op smalle schermen als blok rechts blijven staan i.p.v. los
|
||||
tussen de andere rij-elementen te wrappen */
|
||||
const actions = h("div","am-actions");
|
||||
row.appendChild(h("span","am-name", u.displayName + (u.displayName!==u.username ? ` (${u.username})` : "")));
|
||||
row.appendChild(h("span","am-role", T(roleKey(u.role))));
|
||||
if(u.role==="pupil"){
|
||||
|
|
@ -106,7 +110,7 @@
|
|||
pwCopy.type = "button";
|
||||
pwCopy.title = T("amCopy");
|
||||
pwCopy.addEventListener("click", e=>{ e.preventDefault(); if(pw.value) copyText(pwCopy, pw.value); });
|
||||
row.appendChild(pwCopy);
|
||||
actions.appendChild(pwCopy);
|
||||
if(u.everLoggedIn){
|
||||
const gen = h("button","am-btn","🎲");
|
||||
gen.title = T("amGenerate");
|
||||
|
|
@ -118,7 +122,7 @@
|
|||
msg(`${T("amPwSet")} ${password}`, password);
|
||||
}catch(e){ msg(e.message); }
|
||||
});
|
||||
row.appendChild(gen);
|
||||
actions.appendChild(gen);
|
||||
}
|
||||
}else{
|
||||
if(u.pending && u.linkCode){
|
||||
|
|
@ -135,7 +139,7 @@
|
|||
msg(`${T("amCreated")} ${r.linkCode}`, r.linkCode);
|
||||
}catch(e){ msg(e.message); }
|
||||
});
|
||||
row.appendChild(nc);
|
||||
actions.appendChild(nc);
|
||||
/* direct een nieuw wachtwoord zetten, zonder de koppelcode-activatie */
|
||||
const np = h("button","am-btn", T("amNewPw"));
|
||||
np.addEventListener("click", async ()=>{
|
||||
|
|
@ -145,7 +149,7 @@
|
|||
msg(`${T("amPwSet")} ${r.password}`, r.password);
|
||||
}catch(e){ msg(e.message); }
|
||||
});
|
||||
row.appendChild(np);
|
||||
actions.appendChild(np);
|
||||
}
|
||||
}
|
||||
if(u.id !== currentUser.id){
|
||||
|
|
@ -156,8 +160,9 @@
|
|||
try{ await api("/admin/users/"+u.id, {method:"DELETE"}); reload(); }
|
||||
catch(e){ msg(e.message); }
|
||||
});
|
||||
row.appendChild(del);
|
||||
actions.appendChild(del);
|
||||
}
|
||||
if(actions.childNodes.length) row.appendChild(actions);
|
||||
return row;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,15 +28,26 @@ const REGISTRY = [
|
|||
];
|
||||
const WIDGET_CATS = [["taal","catTaal"],["rekenen","catRekenen"],["tools","catTools"],["media","catMedia"]];
|
||||
|
||||
/* houdt een (opgeslagen of standaard) widgetgrootte binnen het bord - zonder
|
||||
dit passen desktop-formaten (tot 760px breed) niet op een telefoon/tablet */
|
||||
function clampWidgetSize(w, h, def){
|
||||
const fw = Math.max(def.minW || 240, Math.min(w, board.clientWidth));
|
||||
const fh = Math.max(def.minH || 180, Math.min(h, board.clientHeight));
|
||||
return { w: fw, h: fh };
|
||||
}
|
||||
|
||||
function makeWidget(def, saved){
|
||||
const win = document.createElement("div");
|
||||
win.className = "widget";
|
||||
win.style.width = (saved && saved.w ? saved.w : def.w)+"px";
|
||||
win.style.height = (saved && saved.h ? saved.h : def.h)+"px";
|
||||
const size = clampWidgetSize(saved && saved.w ? saved.w : def.w, saved && saved.h ? saved.h : def.h, def);
|
||||
win.style.width = size.w+"px";
|
||||
win.style.height = size.h+"px";
|
||||
if(def.minW) win.style.minWidth = def.minW+"px";
|
||||
if(def.minH) win.style.minHeight = def.minH+"px";
|
||||
win.style.left = (saved && saved.x!=null ? saved.x : 40 + (widgetCount*36)%240) + "px";
|
||||
win.style.top = (saved && saved.y!=null ? saved.y : 30 + (widgetCount*30)%160) + "px";
|
||||
const cx = saved && saved.x!=null ? saved.x : 40 + (widgetCount*36)%240;
|
||||
const cy = saved && saved.y!=null ? saved.y : 30 + (widgetCount*30)%160;
|
||||
win.style.left = Math.max(0, Math.min(cx, board.clientWidth - size.w - 8)) + "px";
|
||||
win.style.top = Math.max(0, Math.min(cy, board.clientHeight - size.h - 8)) + "px";
|
||||
win.style.zIndex = ++zTop;
|
||||
widgetCount++;
|
||||
if(saved && saved.bare){ win.classList.add("bare"); win.dataset.bare = "1"; }
|
||||
|
|
@ -61,6 +72,27 @@ function makeWidget(def, saved){
|
|||
body.className = "widget-body";
|
||||
win.appendChild(head); win.appendChild(body);
|
||||
|
||||
/* eigen resize-greep (touch-vriendelijk, vervangt de native browser-grip) */
|
||||
const rs = document.createElement("div");
|
||||
rs.className = "widget-rs";
|
||||
rs.addEventListener("pointerdown", e=>{
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
win.style.zIndex = ++zTop;
|
||||
const zf = VZ();
|
||||
const sw = win.offsetWidth, sh = win.offsetHeight, sx = e.clientX, sy = e.clientY;
|
||||
const mv = ev=>{
|
||||
const maxW = board.clientWidth - win.offsetLeft - 8;
|
||||
const maxH = board.clientHeight - win.offsetTop - 8;
|
||||
let nw = sw + (ev.clientX - sx)/zf, nh = sh + (ev.clientY - sy)/zf;
|
||||
nw = Math.max(def.minW || 240, Math.min(nw, maxW));
|
||||
nh = Math.max(def.minH || 180, Math.min(nh, maxH));
|
||||
win.style.width = nw+"px"; win.style.height = nh+"px";
|
||||
};
|
||||
const up = ()=>{ document.removeEventListener("pointermove",mv); document.removeEventListener("pointerup",up); };
|
||||
document.addEventListener("pointermove",mv); document.addEventListener("pointerup",up);
|
||||
});
|
||||
win.appendChild(rs);
|
||||
|
||||
let pill = null;
|
||||
function setMin(m){
|
||||
if(m && !pill){
|
||||
|
|
|
|||
Loading…
Reference in a new issue