feat(nav): Crate Info panel — edit label_text + rotate crate.direction in /search
Per-crate panel under Crate Contents: rename (label_text) + a Facing segment (↑back/↓front/←left/→right) that rotates the crate live — the map arrow flips on click. CrateEditIn gained 'direction'. Restores the crate editing my tabbed rewrite dropped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6b679152bc
commit
cba339151f
@ -156,6 +156,7 @@ class CrateEditIn(BaseModel):
|
||||
name: str | None = None
|
||||
label_text: str | None = None
|
||||
crate_purpose: str | None = None
|
||||
direction: str | None = None # forward | back | left | right — the crate's facing (rotate)
|
||||
|
||||
|
||||
@router.post("/crate/{crate_id}")
|
||||
|
||||
@ -112,6 +112,18 @@
|
||||
</div>
|
||||
<div id="ccList" style="max-height:42vh;overflow:auto;margin-top:8px"><div class="muted">pick a crate on the map →</div></div>
|
||||
</div>
|
||||
<div class="panel" id="crateInfoPanel" style="display:none">
|
||||
<b style="font-size:13px">📦 Crate Info</b>
|
||||
<div class="bar" style="margin-top:8px"><input id="ciName" placeholder="crate name / label" style="flex:1"><button class="ghost" onclick="crateRename()">Save name</button></div>
|
||||
<div class="bar" style="margin-top:8px;align-items:center"><span class="muted">Facing</span>
|
||||
<span class="seg" id="ciFacing">
|
||||
<button data-d="back" onclick="crateRotate('back')">↑ back</button>
|
||||
<button data-d="forward" onclick="crateRotate('forward')">↓ front</button>
|
||||
<button data-d="left" onclick="crateRotate('left')">← left</button>
|
||||
<button data-d="right" onclick="crateRotate('right')">→ right</button>
|
||||
</span>
|
||||
<span id="ciSaved" class="ok" style="font-size:12px"></span></div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="bar" style="justify-content:space-between"><b style="font-size:13px">💿 Release Info</b>
|
||||
<div class="bar"><input id="relQ" placeholder="release id / sku" style="width:130px"><button class="ghost" onclick="relLookup()">↵</button></div></div>
|
||||
@ -194,7 +206,7 @@ function redraw(){ if(ST.view==='store') drawStore(); else if(ST.rack) drawRack(
|
||||
|
||||
// ───────────── STORE VIEW ─────────────
|
||||
async function toStore(){
|
||||
ST.view='store'; ST.rack=null; ST.selCrate=null;
|
||||
ST.view='store'; ST.rack=null; ST.selCrate=null; ST.crateInfo=null; renderCrateInfo();
|
||||
$('#lvlCtl').style.display='none'; $('#rackEditBtn').style.display='none';
|
||||
$('#crumb').textContent='Store map';
|
||||
const sid=$('#spaceSel').value;
|
||||
@ -317,9 +329,35 @@ async function loadCrate(id){
|
||||
<td class="muted">${esc(i.artist||'')}</td><td class="muted" style="font-size:11px">${esc(i.genre||'')}${i.style?' · '+esc(i.style):''}</td>
|
||||
<td class="pink">${money(i.price)}</td></tr>`).join('')+'</tbody></table>'
|
||||
: '<div class="muted">empty crate</div>';
|
||||
setViewBtns();
|
||||
setViewBtns(); renderCrateInfo();
|
||||
if(ST.tab==='scanner') renderScanner();
|
||||
}
|
||||
function renderCrateInfo(){
|
||||
const c=ST.crateInfo, p=$('#crateInfoPanel'); if(!p) return;
|
||||
if(!c){ p.style.display='none'; return; }
|
||||
p.style.display='';
|
||||
$('#ciName').value=c.label_text||c.name||'';
|
||||
const d=(c.direction||'').toLowerCase();
|
||||
document.querySelectorAll('#ciFacing button').forEach(b=>b.classList.toggle('on', b.dataset.d===d));
|
||||
$('#ciSaved').textContent='';
|
||||
}
|
||||
async function crateRotate(dir){
|
||||
if(!ST.selCrate) return;
|
||||
await post('/nav/crate/'+ST.selCrate,{direction:dir});
|
||||
ST.crateInfo.direction=dir;
|
||||
const c=(ST.crates||[]).find(x=>x.id===ST.selCrate); if(c) c.direction=dir;
|
||||
renderCrateInfo(); redraw(); // facing arrow flips live on the map
|
||||
$('#ciSaved').textContent='✓ rotated';
|
||||
}
|
||||
async function crateRename(){
|
||||
if(!ST.selCrate) return;
|
||||
const v=$('#ciName').value.trim();
|
||||
await post('/nav/crate/'+ST.selCrate,{label_text:v});
|
||||
ST.crateInfo.label_text=v;
|
||||
const c=(ST.crates||[]).find(x=>x.id===ST.selCrate); if(c) c.label_text=v;
|
||||
$('#ccName').innerHTML='📦 '+esc(v||('Crate '+ST.selCrate));
|
||||
$('#ciSaved').textContent='✓ saved'; redraw(); // crate label updates on the map
|
||||
}
|
||||
async function compressCrate(id){
|
||||
if(!confirm('Renumber this crate\'s slots 1..N (close gaps)?')) return;
|
||||
await fetch('/nav/reorg/compress/'+id,{method:'POST',headers:hdr()}); loadCrate(id);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user