← back to Rentv Sheet Enrich Refine
rentv :9797 legend: close (✕/Esc/click-outside) + per-row ↺ reset for a rename
21e6af57ef717596857abd21a98d39f25e505537 · 2026-08-13 20:11:32 -0700 · Steve Abrams
Completes the Color Key UX + fixes Cody's 'no recovery path' for a bad rename: a renamed
color now shows ↺ to clear the localStorage override back to its grounded/provisional name;
panel closes via ✕, Escape, or clicking outside (consistent with the status picker).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit 21e6af57ef717596857abd21a98d39f25e505537
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Aug 13 20:11:32 2026 -0700
rentv :9797 legend: close (✕/Esc/click-outside) + per-row ↺ reset for a rename
Completes the Color Key UX + fixes Cody's 'no recovery path' for a bad rename: a renamed
color now shows ↺ to clear the localStorage override back to its grounded/provisional name;
panel closes via ✕, Escape, or clicking outside (consistent with the status picker).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
public_live/index.html | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/public_live/index.html b/public_live/index.html
index 4bc958a..d4bcce7 100644
--- a/public_live/index.html
+++ b/public_live/index.html
@@ -101,6 +101,10 @@
.legendpanel .lgname:focus{box-shadow:inset 0 0 0 2px var(--accent)}
.legendpanel .lgname.lgguess{opacity:.72;font-style:italic}
.legendpanel .lgq{color:var(--dim);font-weight:700;font-size:11px;flex:0 0 auto}
+ .legendpanel .lgclose{position:absolute;top:6px;right:8px;background:transparent;border:0;color:var(--dim);cursor:pointer;font-size:14px;line-height:1;padding:2px 4px;z-index:1}
+ .legendpanel .lgclose:hover{color:var(--ink)}
+ .legendpanel .lgreset{background:transparent;border:0;color:var(--dim);cursor:pointer;font-size:12px;padding:0 3px;flex:0 0 auto}
+ .legendpanel .lgreset:hover{color:var(--accent)}
.legendpanel .lghex{color:var(--dim);font-variant-numeric:tabular-nums;font-size:10.5px}
.legendpanel .lgn{color:var(--dim);font-variant-numeric:tabular-nums;min-width:46px;text-align:right}
td.enriched{box-shadow:inset 3px 0 0 #7bc043;background:rgba(123,192,67,.09)}
@@ -566,14 +570,20 @@ function colorTally(){ const t={}; for(const hx of Object.values(COLORS))t[hx]=(
function renderLegend(){ let p=$('#legendpanel'); if(p&&document.activeElement&&p.contains(document.activeElement))return; // don't nuke a name mid-edit
if(!p){p=document.createElement('div');p.id='legendpanel';p.className='legendpanel';document.body.appendChild(p);}
const items=colorTally();
- if(!items.length){ p.innerHTML='<div class="lghead">Color key — this tab</div><div class="lgempty">No color-coded cells on this tab.</div>'; return; }
- p.innerHTML='<div class="lghead">Color key — this tab<span class="lgnote">Exact sheet colors + provisional meaning. Click a name to rename (saved locally). ❓ / grey “?” = unverified guess — rename to confirm.</span></div>'
- +items.map(([hx,n])=>{const sure=nameSure(hx);return `<div class="lgrow"><span class="lgsw" style="background:${hx}"></span><span class="lgname${sure?'':' lgguess'}" contenteditable="true" data-hx="${hx}" title="${sure?'Click to rename':'Heuristic guess — click to rename'}">${esc(provName(hx))}</span>${sure?'':'<span class="lgq" title="unverified guess">?</span>'}<span class="lghex">${hx}</span><span class="lgn">${n.toLocaleString()}</span></div>`;}).join('');
+ const CLOSE='<button class="lgclose" title="Close (Esc)">✕</button>';
+ if(!items.length){ p.innerHTML=CLOSE+'<div class="lghead">Color key — this tab</div><div class="lgempty">No color-coded cells on this tab.</div>'; p.querySelector('.lgclose').onclick=closeLegend; return; }
+ p.innerHTML=CLOSE+'<div class="lghead">Color key — this tab<span class="lgnote">Exact sheet colors + provisional meaning. Click a name to rename (saved locally); ↺ resets a rename. ❓ / grey “?” = unverified guess.</span></div>'
+ +items.map(([hx,n])=>{const sure=nameSure(hx);const ov=LS.get('cname.'+hx,null),hasOv=ov!=null&&ov!=='';const mid=hasOv?`<button class="lgreset" data-hx="${hx}" title="Reset to provisional name">↺</button>`:(sure?'':'<span class="lgq" title="unverified guess">?</span>');return `<div class="lgrow"><span class="lgsw" style="background:${hx}"></span><span class="lgname${sure?'':' lgguess'}" contenteditable="true" data-hx="${hx}" title="${sure?'Click to rename':'Heuristic guess — click to rename'}">${esc(provName(hx))}</span>${mid}<span class="lghex">${hx}</span><span class="lgn">${n.toLocaleString()}</span></div>`;}).join('');
+ p.querySelector('.lgclose').onclick=closeLegend;
+ p.querySelectorAll('.lgreset').forEach(b=>b.onclick=()=>{ localStorage.removeItem('rc2.cname.'+b.dataset.hx); renderLegend(); });
p.querySelectorAll('.lgname').forEach(el=>{ el.onblur=()=>{ const v=el.textContent.trim(); if(v)LS.set('cname.'+el.dataset.hx, v); };
el.onkeydown=e=>{ if(e.key==='Enter'){e.preventDefault();el.blur();} }; });
}
+function closeLegend(){ const p=$('#legendpanel'); if(p)p.style.display='none'; document.removeEventListener('mousedown',legendOutside); }
+function legendOutside(e){ if(!e.target.closest('#legendpanel')&&!e.target.closest('#legendtog'))closeLegend(); }
function toggleLegend(){ let p=$('#legendpanel'); const open=p&&p.style.display==='block';
- if(open){ p.style.display='none'; return; } renderLegend(); $('#legendpanel').style.display='block'; }
+ if(open){ closeLegend(); return; } renderLegend(); $('#legendpanel').style.display='block';
+ setTimeout(()=>document.addEventListener('mousedown',legendOutside),0); }
function isStatusCol(ci){ return STATUS_FIELD && DATA.headers[ci]===STATUS_FIELD; }
function lmCol(){ return DATA.headers.findIndex(h=>/^last modified$/i.test(String(h).trim())); }
async function stampLastMod(r){ // write "now" to the row's Last Modified cell (shown under the status chip)
@@ -802,7 +812,7 @@ applyTheme(LS.get('theme', (window.matchMedia&&matchMedia('(prefers-color-scheme
// Fit mode = table always fits the window: re-fit columns to the viewport when it resizes
window.addEventListener('resize',()=>{ if(WIDTHPRESET==='fit'){ clearTimeout(window._rzfit); window._rzfit=setTimeout(applyFit,120); } });
document.addEventListener('dragend',()=>{ window._dragText=false; }); // clear the text-move guard after any drag
-document.addEventListener('keydown',e=>{if(e.key==='Escape')closeDraft()});
+document.addEventListener('keydown',e=>{if(e.key==='Escape'){closeDraft();closeLegend();}});
(async()=>{await loadMeta();await loadData(); if(WIDTHPRESET==='fit')applyFit();})();
</script>
</body>
← 46c2c4d rentv :9797 legend: Cody fixes — empty-rename guard, mark he
·
back to Rentv Sheet Enrich Refine
·
rentv :9797 legend: Cody fixes — sticky header (✕ stays visi 72a7312 →