diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-15 19:54:37 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-15 19:54:37 -0500 |
| commit | 1b4e5f88353180cf999412faa2be9e0326b78361 (patch) | |
| tree | 523ffa0c8b995ef239be947b7b62b9e198de0e6b /scripts/theme-studio/palette-actions.js | |
| parent | 5f6e07d7024135d86a4883439b3d04de5314916a (diff) | |
| download | dotemacs-1b4e5f88353180cf999412faa2be9e0326b78361.tar.gz dotemacs-1b4e5f88353180cf999412faa2be9e0326b78361.zip | |
feat(theme-studio): show view-area > element usages on palette tile hover
I added paletteUsages, which enumerates every place a color is assigned, grouped by view area (the view dropdown's names: color/code assignments, ui faces, each package app) and the element within it. renderPalette builds the per-area scopes once and appends the list to each used tile's hover title, under the existing name/hex/nearest-deltaE line. Node tests and a #usagetest gate cover it.
Diffstat (limited to 'scripts/theme-studio/palette-actions.js')
| -rw-r--r-- | scripts/theme-studio/palette-actions.js | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/scripts/theme-studio/palette-actions.js b/scripts/theme-studio/palette-actions.js index dd060dc8c..0f49225a8 100644 --- a/scripts/theme-studio/palette-actions.js +++ b/scripts/theme-studio/palette-actions.js @@ -87,7 +87,7 @@ function renderPaletteWarnings(warnings,overflow){ } // One palette chip for PALETTE[i], with its remove / rename / select handlers. // Families sort deterministically, so the old move-arrow / drag reordering is gone. -function paletteChip(i,nearest,used){ +function paletteChip(i,nearest,used,scopes){ const [hex,name]=PALETTE[i],tc=textOn(hex),nde=nearest[i]; const role=groundRoleOfEntry(PALETTE[i],{bg:MAP['bg'],fg:MAP['p']}); const locked=(role==='bg'||role==='fg'); @@ -95,6 +95,7 @@ function paletteChip(i,nearest,used){ d.dataset.paletteIndex=String(i); d.title=name+' '+hex+(nde===Infinity||nde===undefined?'':' — nearest ΔE '+nde.toFixed(3)); if(used&&!used.has(hex.toLowerCase())){d.classList.add('unused');d.title+=' — not used in the theme';} + else if(scopes){const u=paletteUsages(hex,scopes,PALETTE);if(u.length)d.title+='\n'+u.join('\n');} const rm=locked?`<span class="lock" title="${role==='bg'?'background':'foreground'} — can't remove" style="color:${tc}">🔒</span>`:`<button class="rm" title="remove" style="color:${tc}">×</button>`; d.innerHTML=`${rm}<input class="nm" value="${name}" readonly style="color:${tc}"><div class="hx" style="color:${tc}">${hex}</div>`; if(!locked)d.querySelector('.rm').onclick=(e)=>{e.stopPropagation();rememberGone(hex,name);PALETTE.splice(i,1);if(selectedIdx===i)selectedIdx=null;refreshPaletteState({code:false,ground:false});}; @@ -185,6 +186,13 @@ function renderPalette(){ const {warnings,overflow,nearest}=paletteWarnings(PALETTE,DELTAE_MIN,5); const {ground,columns}=columnsFromPalette(PALETTE,{bg:MAP['bg'],fg:MAP['p']}); const usedHexes=usedPaletteHexes(PALETTE,SYNTAX,UIMAP,PKGMAP,{bg:MAP['bg'],fg:MAP['p']}); + // Per-view-area scopes for the hover "view area > element" usage list. Area + // names match the view dropdown; elements use each tier's display label. + const usageScopes=[ + {area:'color/code assignments',faces:Object.fromEntries(CATS.filter(c=>c[0]!=='bg'&&c[0]!=='p').map(c=>[c[1]||c[0],syntaxFace(c[0])]))}, + {area:'ui faces',faces:Object.fromEntries(UI_FACES.map(u=>[u[1]||u[0],UIMAP[u[0]]]))}, + ...Object.keys(APPS).map(app=>({area:APPS[app].label,faces:Object.fromEntries(APPS[app].faces.map(r=>[r[1]||r[0],PKGMAP[app][r[0]]]))})) + ]; const used=new Set(); const idxOf=(hex,name)=>{for(let i=0;i<PALETTE.length;i++)if(!used.has(i)&&PALETTE[i][0]===hex&&PALETTE[i][1]===name){used.add(i);return i;}return -1;}; const strip=(cls)=>{const s=document.createElement('div');s.className='fstrip'+(cls||'');p.appendChild(s);return s;}; @@ -194,7 +202,7 @@ function renderPalette(){ gs.appendChild(groundSpanControl()); (paletteShowFull?groundColumnMembers():groundColumnMembers().filter(m=>!/^ground[+-]\d+$/i.test(m.name||''))).forEach(m=>{ const i=idxOf(m.hex,m.name); - if(i>=0)gs.appendChild(paletteChip(i,nearest,usedHexes)); + if(i>=0)gs.appendChild(paletteChip(i,nearest,usedHexes,usageScopes)); else{const tc=textOn(m.hex),sw=document.createElement('div');sw.className='pchip';sw.style.background=m.hex;sw.title=(m.name||'ground')+' '+m.hex; sw.innerHTML=`<input class="nm" value="${m.name||'ground'}" disabled style="color:${tc}"><div class="hx" style="color:${tc}">${m.hex}</div>`;gs.appendChild(sw);} }); @@ -206,7 +214,7 @@ function renderPalette(){ const s=strip('');s.dataset.column=f.column||f.base; s.appendChild(columnHeader(f,pos,ordered.length)); s.appendChild(columnCountControl(f)); - (paletteShowFull?f.members:f.members.filter(m=>m.hex.toLowerCase()===f.base.toLowerCase())).forEach(m=>{const i=idxOf(m.hex,m.name);if(i>=0)s.appendChild(paletteChip(i,nearest,usedHexes));}); + (paletteShowFull?f.members:f.members.filter(m=>m.hex.toLowerCase()===f.base.toLowerCase())).forEach(m=>{const i=idxOf(m.hex,m.name);if(i>=0)s.appendChild(paletteChip(i,nearest,usedHexes,usageScopes));}); if(f.members.every(m=>!usedHexes.has(m.hex.toLowerCase())))s.classList.add('unused-col'); }); renderPaletteWarnings(warnings,overflow); |
