Spaces:
Running on Zero
Running on Zero
Canvas UX: draggable boxes from anywhere + click-to-edit desc; hide empty hint
Browse files
app.py
CHANGED
|
@@ -423,7 +423,9 @@ SCRIPT = r"""
|
|
| 423 |
NS.el.ratios.style.display = S.step===1?'flex':'none';
|
| 424 |
}
|
| 425 |
function renderAll(){ layoutBoard(); renderBoxes(); renderSummary(); renderTable(); renderSteps();
|
| 426 |
-
NS.el.ratioChips.forEach(c=>c.classList.toggle('sel', c.dataset.r===S.aspect));
|
|
|
|
|
|
|
| 427 |
function esc(s){return (s||'').replace(/[&<>]/g,m=>({'&':'&','<':'<','>':'>'}[m]));}
|
| 428 |
|
| 429 |
function select(e){ sel=e; NS.el.board.querySelectorAll('.box').forEach(d=>
|
|
@@ -437,9 +439,18 @@ SCRIPT = r"""
|
|
| 437 |
function wireBox(d,e){
|
| 438 |
const idEl=d.querySelector('.id'), descEl=d.querySelector('.desc');
|
| 439 |
d.addEventListener('mousedown',ev=>{
|
| 440 |
-
if(ev.target.classList.contains('h')||ev.target.classList.contains('rm')||
|
| 441 |
-
|
| 442 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
});
|
| 444 |
d.querySelectorAll('.h').forEach(h=>h.addEventListener('mousedown',ev=>{
|
| 445 |
ev.preventDefault(); ev.stopPropagation(); select(e);
|
|
|
|
| 423 |
NS.el.ratios.style.display = S.step===1?'flex':'none';
|
| 424 |
}
|
| 425 |
function renderAll(){ layoutBoard(); renderBoxes(); renderSummary(); renderTable(); renderSteps();
|
| 426 |
+
NS.el.ratioChips.forEach(c=>c.classList.toggle('sel', c.dataset.r===S.aspect));
|
| 427 |
+
const hint=NS.el.board.querySelector('.hint'); if(hint) hint.style.display=(!S.rendered && S.elements.length===0)?'flex':'none';
|
| 428 |
+
syncState(); }
|
| 429 |
function esc(s){return (s||'').replace(/[&<>]/g,m=>({'&':'&','<':'<','>':'>'}[m]));}
|
| 430 |
|
| 431 |
function select(e){ sel=e; NS.el.board.querySelectorAll('.box').forEach(d=>
|
|
|
|
| 439 |
function wireBox(d,e){
|
| 440 |
const idEl=d.querySelector('.id'), descEl=d.querySelector('.desc');
|
| 441 |
d.addEventListener('mousedown',ev=>{
|
| 442 |
+
if(ev.target.classList.contains('h')||ev.target.classList.contains('rm')||ev.target.classList.contains('id')) { select(e); return; }
|
| 443 |
+
if(ev.target.classList.contains('desc') && document.activeElement===ev.target) return; // editing: allow caret
|
| 444 |
+
select(e); ev.preventDefault();
|
| 445 |
+
const sx=ev.clientX, sy=ev.clientY; let moved=false; const isDesc=ev.target.classList.contains('desc');
|
| 446 |
+
const b=e.bbox.slice(); const p=px2norm(ev); const oy=p[0]-b[0], ox=p[1]-b[1];
|
| 447 |
+
const w=b[3]-b[1], h=b[2]-b[0];
|
| 448 |
+
function mv(ev2){ if(!moved && Math.abs(ev2.clientX-sx)+Math.abs(ev2.clientY-sy)>3) moved=true;
|
| 449 |
+
if(moved){ const q=px2norm(ev2); let x0=clamp(q[1]-ox,0,1000-w), y0=clamp(q[0]-oy,0,1000-h);
|
| 450 |
+
e.bbox=[y0,x0,y0+h,x0+w]; posBox(d,e); liveMeta(e); } }
|
| 451 |
+
function up(){ document.removeEventListener('mousemove',mv); document.removeEventListener('mouseup',up);
|
| 452 |
+
if(moved) renderAll(); else if(isDesc) descEl.focus(); }
|
| 453 |
+
document.addEventListener('mousemove',mv); document.addEventListener('mouseup',up);
|
| 454 |
});
|
| 455 |
d.querySelectorAll('.h').forEach(h=>h.addEventListener('mousedown',ev=>{
|
| 456 |
ev.preventDefault(); ev.stopPropagation(); select(e);
|