From 7c2aa5e0418648f6982fae7add292baebc5b479f Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 25 Jun 2026 18:32:10 -0400 Subject: feat(theme-studio): move reuse context from app labels into a hover Clean the app labels and move the "what reuses this" context into the app dropdown's tooltip, so the labels stay short. The foundational face sets name their consumers on hover: ansi-color (vterm, eshell, compilation, ghostel, eat), shr (eww, nov, mu4e/message), gnus (mu4e article view), and dired (dirvish). Labels now carry only the name plus any acronym expansion. A small APP_HOVERS dict in face_data.py feeds an app "hover" field that sets the dropdown's title on selection. --- scripts/theme-studio/app.js | 5 +++-- scripts/theme-studio/face_data.py | 14 ++++++++++++-- scripts/theme-studio/generate.py | 2 +- scripts/theme-studio/theme-studio.html | 7 ++++--- 4 files changed, 20 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/scripts/theme-studio/app.js b/scripts/theme-studio/app.js index be9af17f1..2f26e138a 100644 --- a/scripts/theme-studio/app.js +++ b/scripts/theme-studio/app.js @@ -492,11 +492,11 @@ function updateViewLockIndicators(){const s=document.getElementById('viewsel');i for(const o of s.querySelectorAll('option')){const base=o.dataset.label||o.textContent; o.textContent=(areAllLocked(viewLockKeys(o.value),LOCKED)?'🔒 ':'')+base;}} function buildViewSel(){const s=document.getElementById('viewsel');if(!s)return;s.innerHTML=''; - const mk=(v,t)=>{const o=document.createElement('option');o.value=v;o.dataset.label=t;o.textContent=t;return o;}; + const mk=(v,t,ti)=>{const o=document.createElement('option');o.value=v;o.dataset.label=t;o.textContent=t;if(ti)o.title=ti;return o;}; s.appendChild(mk('@code','color/code assignments')); s.appendChild(mk('@ui','ui faces')); const og=document.createElement('optgroup');og.label='package faces'; - for(const app of appViewKeysSorted(APPS))og.appendChild(mk(app,APPS[app].label)); + for(const app of appViewKeysSorted(APPS))og.appendChild(mk(app,APPS[app].label,APPS[app].hover)); s.appendChild(og);updateViewLockIndicators();} // The ‹ › buttons flanking the dropdown step the selection by DIR and re-render // the view (faces table + preview), so you can walk the list without reopening it. @@ -515,6 +515,7 @@ function stepLang(dir){ function onViewChange(){const s=document.getElementById('viewsel');const v=(s&&s.value)||'@code'; const show=(id,on)=>{const e=document.getElementById(id);if(e)e.style.display=on?'':'none';}; show('view-code',v==='@code');show('view-ui',v==='@ui');show('view-pkg',v[0]!=='@'); + if(s)s.title=(v[0]!=='@'&&APPS[v]&&APPS[v].hover)?APPS[v].hover:''; if(v==='@code')renderCode(); else if(v==='@ui'){buildUITable();buildMockFrame();syncPaneHeight('uitable','mockframe');} else pkgChanged();} diff --git a/scripts/theme-studio/face_data.py b/scripts/theme-studio/face_data.py index bca6b27b5..18f097abe 100644 --- a/scripts/theme-studio/face_data.py +++ b/scripts/theme-studio/face_data.py @@ -365,10 +365,10 @@ BESPOKE_APP_SPECS=[ ("magit","magit","magit",MAGIT_FACES,"magit-",MAGIT_SEED), ("elfeed","elfeed","elfeed",ELFEED_FACES,"elfeed-",ELFEED_SEED), ("mu4e","mu4e","mu4e",MU4E_FACES,"mu4e-",MU4E_SEED), - ("gnus","gnus (mu4e article view)","gnus",GNUS_FACES,"gnus-",GNUS_SEED), + ("gnus","gnus","gnus",GNUS_FACES,"gnus-",GNUS_SEED), ("org-faces","org-faces","orgfaces",ORGFACES_FACES,"org-faces-",ORGFACES_SEED), ("ghostel","ghostel","ghostel",GHOSTEL_FACES,"ghostel-",GHOSTEL_SEED), - ("ansi-color","ansi-color (vterm/eshell/compilation/ghostel)","ansicolor",ANSI_COLOR_FACES,"ansi-color-",ANSI_COLOR_SEED), + ("ansi-color","ansi-color","ansicolor",ANSI_COLOR_FACES,"ansi-color-",ANSI_COLOR_SEED), ("eat","Emulate A Terminal (EAT)","eat",EAT_FACES,"eat-",EAT_SEED), ("auto-dim-other-buffers","auto-dim","autodim",AUTODIM_FACES,"auto-dim-other-buffers-",AUTODIM_SEED), ("dashboard","dashboard","dashboard",DASHBOARD_FACES,"dashboard-",DASHBOARD_SEED), @@ -387,3 +387,13 @@ BESPOKE_APP_SPECS=[ ("telega","telega","telega",TELEGA_FACES,"telega-",TELEGA_SEED), ("shr","Simple HTML Renderer (SHR)","shr",SHR_FACES,"shr-",SHR_SEED), ] + +# Hover text for foundational/reused apps: names what consumes these faces, so +# the app label can stay clean and the "who reuses this" context rides the app +# dropdown's tooltip instead. Apps not listed here get no hover. +APP_HOVERS={ + "ansi-color":"The 16 ANSI palette faces. Reused by vterm, eshell, compilation, ghostel, and eat, whose own color faces inherit these.", + "shr":"Simple HTML Renderer. Reused by eww, nov (epub reading), and mu4e / message for HTML mail.", + "gnus":"Article-view faces, reused by mu4e's article view.", + "dired":"Directory-listing faces, reused by dirvish (a dired frontend).", +} diff --git a/scripts/theme-studio/generate.py b/scripts/theme-studio/generate.py index 797fcc28e..e50d102de 100644 --- a/scripts/theme-studio/generate.py +++ b/scripts/theme-studio/generate.py @@ -359,7 +359,7 @@ def _build(): apply_syntax_seed(_d if _seed else {},SYNTAX,MAP) # Bespoke apps are single-sourced as BESPOKE_APP_SPECS in face_data.py (one # row per app: key, label, preview, FACES, prefix, SEED). - APPS={key:{"label":label,"preview":preview,"faces":face_rows(faces,prefix,seed)} + APPS={key:{"label":label,"preview":preview,"hover":APP_HOVERS.get(key,""),"faces":face_rows(faces,prefix,seed)} for key,label,preview,faces,prefix,seed in BESPOKE_APP_SPECS} # Phase 6: merge the generated all-package inventory (refresh with build-inventory.el). # Bespoke apps stay; every other installed package becomes an editable generic app. diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index a619bb5ea..13545e9e8 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -297,7 +297,7 @@