aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-selector/generate.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/theme-selector/generate.py')
-rw-r--r--scripts/theme-selector/generate.py63
1 files changed, 56 insertions, 7 deletions
diff --git a/scripts/theme-selector/generate.py b/scripts/theme-selector/generate.py
index d6832084..d66ae4fb 100644
--- a/scripts/theme-selector/generate.py
+++ b/scripts/theme-selector/generate.py
@@ -221,6 +221,10 @@ HTML = """<!doctype html><meta charset=utf-8><title>theme-selector</title>
.pane{min-width:0} .pane.grow{flex:1} .pane.saveload{flex:0 0 auto;margin-left:auto}
.pane h1{margin-top:0}
.filebar.end{justify-content:flex-end} .langbar{margin-bottom:10px;display:flex;gap:8px;align-items:center}
+ .pkgbar{margin:0 0 10px;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
+ .pkgbar button{background:#252321;color:#e8bd30;border:1px solid #3a3a3a;border-radius:4px;padding:6px 12px;font:10pt monospace;cursor:pointer}
+ .hstep{background:#161412;border:1px solid #252321;color:#cdced1;border-radius:4px;padding:3px 4px;font:10pt monospace;width:56px}
+ #pkgbody td{padding:3px 8px}
#codepre{width:100%;box-sizing:border-box}
.mock{border:1px solid #252321;border-radius:8px;overflow:hidden;font:15px/1.7 monospace;display:flex;flex-direction:column}
.mock .mbuf{flex:1} .mock .ln{display:flex;align-items:stretch;white-space:pre}
@@ -289,6 +293,21 @@ HTML = """<!doctype html><meta charset=utf-8><title>theme-selector</title>
<div id="mockframe" class="mock"></div>
</section>
</div>
+<h1>package faces</h1>
+<div class="pkgbar">
+ <label style="color:#b4b1a2">application</label><select id="appsel" class="chip" style="width:auto;font:bold 10pt monospace"></select>
+ <label style="color:#b4b1a2">filter</label><input id="pkgfilter" type="text" placeholder="face name" oninput="buildPkgTable()" style="background:#161412;border:1px solid #252321;color:#cdced1;border-radius:4px;padding:5px 8px;font:10pt monospace;width:160px">
+ <button onclick="resetApp()">&#8635; reset all</button>
+</div>
+<div class="cols stretch">
+ <section class="pane">
+ <table class="leg" id="pkgtable"><thead><tr><th>face</th><th>fg</th><th>bg</th><th>weight</th><th>inherit</th><th>size</th><th>contrast</th><th></th></tr></thead><tbody id="pkgbody"></tbody></table>
+ </section>
+ <section class="pane grow" style="display:flex;flex-direction:column">
+ <div class="langbar"><label style="color:#b4b1a2">preview (generic — face names in their own colors)</label></div>
+ <div id="pkgpreview" class="mock" style="overflow:auto"></div>
+ </section>
+</div>
<script>
const SAMPLES=SAMPLES_J, CATS=CATS_J, UI_FACES=UIFACES_J, APPS=APPS_J;
let MAP=MAP_J, PALETTE=PALETTE_J, BOLD=BOLD_J, ITALIC={}, UIMAP=UIMAP_J;
@@ -369,7 +388,7 @@ function renderPalette(){
d.ondragleave=()=>d.classList.remove('over');
d.ondrop=(e)=>{e.preventDefault();d.classList.remove('over');if(dragFrom===null||dragFrom===i)return;const m=PALETTE.splice(dragFrom,1)[0];PALETTE.splice(i,0,m);dragFrom=null;selectedIdx=null;renderPalette();buildTable();buildUITable();};
p.appendChild(d);});
- buildUITable();
+ buildUITable();if(document.getElementById('pkgbody'))buildPkgTable();
}
function notify(msg,err){const m=document.getElementById('palmsg');if(!m)return;m.textContent=msg;m.style.color=err?'#cb6b4d':'#8a9496';m.style.opacity='1';clearTimeout(m._t);m._t=setTimeout(()=>{m.style.opacity='0';},err?4000:2800);}
function applyEdit(){if(selectedIdx!==null)updateColor();else addColor();}
@@ -384,6 +403,7 @@ function updateColor(){
PALETTE[i]=[newHex,newName];
for(const k in MAP){if(MAP[k]===oldHex)MAP[k]=newHex;}
for(const f in UIMAP){if(UIMAP[f].fg===oldHex)UIMAP[f].fg=newHex;if(UIMAP[f].bg===oldHex)UIMAP[f].bg=newHex;}
+ for(const ap in PKGMAP)for(const fc in PKGMAP[ap]){const o=PKGMAP[ap][fc];if(o.fg===oldHex)o.fg=newHex;if(o.bg===oldHex)o.bg=newHex;}
closePicker();renderPalette();buildTable();buildUITable();renderCode();applyGround();notify('updated "'+newName+'"',false);
}
function normHex(s){s=s.trim();if(/^[0-9a-fA-F]{6}$/.test(s))s='#'+s;return /^#[0-9a-fA-F]{6}$/.test(s)?s.toLowerCase():null;}
@@ -432,7 +452,7 @@ function importFile(ev){const f=ev.target.files[0];if(!f)return;const r=new File
BOLD={};(d.bold||[]).forEach(k=>BOLD[k]=true);ITALIC={};(d.italic||[]).forEach(k=>ITALIC[k]=true);
if(d.ui)Object.assign(UIMAP,d.ui);
PKGMAP=seedPkgmap();if(d.packages)mergePackagesInto(PKGMAP,d.packages);
- renderPalette();buildTable();buildUITable();renderCode();applyGround();updateTitle();}catch(e){alert('bad theme file: '+e.message);}};
+ renderPalette();buildTable();buildUITable();buildPkgTable();buildPkgPreview();renderCode();applyGround();updateTitle();}catch(e){alert('bad theme file: '+e.message);}};
r.readAsText(f);ev.target.value='';}
function applyGround(){document.querySelectorAll('pre').forEach(p=>p.style.background=MAP['bg']);document.querySelectorAll('.ex').forEach(e=>e.style.background=MAP['bg']);}
function uf(f){return UIMAP[f]||{};}
@@ -487,16 +507,45 @@ function buildMockFrame(){
fr.innerHTML=html;fr.style.background=bg;fr.style.color=fg;
fr.onclick=(e)=>{const u=e.target.closest('[data-face]');if(u){flashUi(u.dataset.face);return;}const k=e.target.closest('[data-k]');if(k)flashAssign(k.dataset.k);};
}
-function uiSelect(face,attr){
+function colorDropdown(value,onpick){
const sel=document.createElement('select');sel.className='chip';
const none=document.createElement('option');none.value='';none.textContent='— none —';none.style.background='#161412';none.style.color='#b4b1a2';sel.appendChild(none);
for(const [hex,name] of PALETTE){const o=document.createElement('option');o.value=hex;o.textContent=name+' '+hex;o.style.background=hex;o.style.color=textOn(hex);sel.appendChild(o);}
- sel.value=UIMAP[face][attr]||'';
+ sel.value=value||'';
function style(){if(sel.value){sel.style.background=sel.value;sel.style.color=textOn(sel.value);}else{sel.style.background='#161412';sel.style.color='#b4b1a2';}}
style();
- sel.onchange=()=>{UIMAP[face][attr]=sel.value||null;style();paintUI(face);buildMockFrame();};
+ sel.onchange=()=>{style();onpick(sel.value||null);};
return sel;
}
+function uiSelect(face,attr){return colorDropdown(UIMAP[face][attr],v=>{UIMAP[face][attr]=v;paintUI(face);buildMockFrame();});}
+const BASE_INHERITS=['fixed-pitch','variable-pitch','default','link','bold','italic','shadow'];
+function seedFace(d){return {fg:pname(d.fg),bg:pname(d.bg),bold:!!d.bold,italic:!!d.italic,inherit:d.inherit||null,height:d.height||1,source:'default'};}
+function curApp(){const s=document.getElementById('appsel');return s&&s.value?s.value:Object.keys(APPS)[0];}
+function pkgEffFg(app,face,seen){seen=seen||{};const f=PKGMAP[app]&&PKGMAP[app][face];if(!f||seen[face])return null;seen[face]=1;if(f.fg)return f.fg;if(f.inherit&&PKGMAP[app][f.inherit])return pkgEffFg(app,f.inherit,seen);return null;}
+function pkgEffBg(app,face,seen){seen=seen||{};const f=PKGMAP[app]&&PKGMAP[app][face];if(!f||seen[face])return null;seen[face]=1;if(f.bg)return f.bg;if(f.inherit&&PKGMAP[app][f.inherit])return pkgEffBg(app,f.inherit,seen);return null;}
+function buildAppSel(){const s=document.getElementById('appsel');if(!s)return;s.innerHTML='';for(const app in APPS){const o=document.createElement('option');o.value=app;o.textContent=APPS[app].label;s.appendChild(o);}s.onchange=pkgChanged;}
+function pkgChanged(){buildPkgTable();buildPkgPreview();syncPkgHeight();}
+function buildPkgTable(){
+ const app=curApp(),tb=document.getElementById('pkgbody');if(!tb)return;tb.innerHTML='';
+ const flt=(document.getElementById('pkgfilter').value||'').trim().toLowerCase();
+ const inh=[''].concat(BASE_INHERITS).concat(APPS[app].faces.map(r=>r[0]));
+ for(const [face,label,def] of APPS[app].faces){
+ if(flt&&!(face.toLowerCase().includes(flt)||label.toLowerCase().includes(flt)))continue;
+ const f=PKGMAP[app][face],tr=document.createElement('tr');
+ const c0=document.createElement('td');c0.className='cat';c0.textContent=label;c0.title=face;
+ const cf=document.createElement('td');cf.appendChild(colorDropdown(f.fg,v=>{f.fg=v;f.source='user';pkgChanged();}));
+ const cb=document.createElement('td');cb.appendChild(colorDropdown(f.bg,v=>{f.bg=v;f.source='user';pkgChanged();}));
+ const cw=document.createElement('td');[['B','bold'],['I','italic']].forEach(([ch,at])=>{const b=document.createElement('button');b.className='sbtn'+(f[at]?' on':'');b.textContent='a';b.style.fontWeight=at==='bold'?'bold':'normal';b.style.fontStyle=at==='italic'?'italic':'normal';b.onclick=()=>{f[at]=!f[at];f.source='user';pkgChanged();};cw.appendChild(b);});
+ const ci=document.createElement('td');const isel=document.createElement('select');isel.className='chip';isel.style.cssText='width:150px;font:10pt monospace';inh.forEach(o=>{const op=document.createElement('option');op.value=o;op.textContent=o||'— none —';isel.appendChild(op);});isel.value=f.inherit||'';isel.onchange=()=>{f.inherit=isel.value||null;f.source='user';pkgChanged();};ci.appendChild(isel);
+ const ch=document.createElement('td');const hin=document.createElement('input');hin.type='number';hin.min='0.8';hin.max='2.5';hin.step='0.05';hin.value=f.height||1;hin.className='hstep';hin.onchange=()=>{f.height=parseFloat(hin.value)||1;f.source='user';pkgChanged();};ch.appendChild(hin);
+ const cc=document.createElement('td');cc.style.fontSize='10pt';cc.style.whiteSpace='nowrap';const efg=pkgEffFg(app,face)||MAP['p'],ebg=pkgEffBg(app,face)||MAP['bg'],r=contrast(efg,ebg);cc.innerHTML=`<span style="color:${ratingColor(r)}">${r.toFixed(1)} ${rating(r)}</span>`;
+ const cr=document.createElement('td');const rb=document.createElement('button');rb.className='sbtn';rb.textContent='↺';rb.title='reset to default';rb.onclick=()=>{PKGMAP[app][face]=seedFace(def);pkgChanged();};cr.appendChild(rb);
+ tr.append(c0,cf,cb,cw,ci,ch,cc,cr);tb.appendChild(tr);
+ }
+}
+function buildPkgPreview(){const app=curApp(),p=document.getElementById('pkgpreview');if(!p)return;let h='<div style="padding:10px 14px;font:15px/1.8 monospace">';for(const [face,label,def] of APPS[app].faces){const f=PKGMAP[app][face],efg=pkgEffFg(app,face)||MAP['p'],ebg=pkgEffBg(app,face);h+=`<div style="color:${efg};${ebg?'background:'+ebg+';':''}font-weight:${f.bold?'bold':'normal'};font-style:${f.italic?'italic':'normal'};font-size:${(f.height||1)}em">${esc(label)}</div>`;}p.innerHTML=h+'</div>';p.style.background=MAP['bg'];}
+function resetApp(){const app=curApp();PKGMAP[app]={};for(const [face,label,d] of APPS[app].faces)PKGMAP[app][face]=seedFace(d);pkgChanged();}
+function syncPkgHeight(){const t=document.getElementById('pkgtable'),m=document.getElementById('pkgpreview');if(!t||!m)return;const lb=m.previousElementSibling,lbh=lb?lb.getBoundingClientRect().height+10:30;m.style.height=Math.max(t.getBoundingClientRect().height-lbh,220)+'px';}
function paintUI(face){const pv=document.getElementById('uiprev-'+face);if(!pv)return;pv.style.color=UIMAP[face].fg||MAP['p'];pv.style.background=UIMAP[face].bg||MAP['bg'];}
function buildUITable(){
const tb=document.getElementById('uibody');tb.innerHTML='';
@@ -514,8 +563,8 @@ function srt(c){const tb=document.getElementById('legbody');const r=[...tb.rows]
r.sort((a,b)=>{const x=(c===0?a.querySelector('select').value:a.cells[2].innerText).toLowerCase(),
y=(c===0?b.querySelector('select').value:b.cells[2].innerText).toLowerCase();
return (x<y?-1:x>y?1:0)*(D[c]?1:-1);});r.forEach(x=>tb.appendChild(x));}
-buildLangSel();renderPalette();buildTable();buildUITable();renderCode();applyGround();updateTitle();initPicker();syncMockHeight();
-addEventListener('resize',syncMockHeight);
+buildLangSel();buildAppSel();renderPalette();buildTable();buildUITable();renderCode();applyGround();updateTitle();initPicker();buildPkgTable();buildPkgPreview();syncMockHeight();syncPkgHeight();
+addEventListener('resize',()=>{syncMockHeight();syncPkgHeight();});
// Phase-1 self-test (open with #selftest): seed -> export -> import -> compare.
function pkgSelftest(){
const seeded=seedPkgmap();