aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/app.js
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/theme-studio/app.js')
-rw-r--r--scripts/theme-studio/app.js41
1 files changed, 33 insertions, 8 deletions
diff --git a/scripts/theme-studio/app.js b/scripts/theme-studio/app.js
index 2da0558a3..f3f93b6f6 100644
--- a/scripts/theme-studio/app.js
+++ b/scripts/theme-studio/app.js
@@ -142,12 +142,37 @@ function mkLockCell(lockKey,els){
// selector, a slant selector, and box-like underline and strike controls. Each
// edit mutates the face object and calls onChange to repaint. Returns the control
// elements so the caller lays them out and hands them to mkLockCell.
-const WEIGHT_OPTS=[['','wt'],['light','light'],['normal','normal'],['medium','medium'],['semibold','semi'],['bold','bold'],['heavy','heavy']];
-const SLANT_OPTS=[['','sl'],['normal','normal'],['italic','italic'],['oblique','oblique']];
-function mkEnumSelect(opts,get,set,title){
- const s=document.createElement('select');s.className='chip stylesel';s.title=title;
- for(const [v,label] of opts){const o=document.createElement('option');o.value=v;o.textContent=label;s.appendChild(o);}
- s.value=get()||'';s.onchange=()=>set(s.value||null);return s;}
+const WEIGHT_OPTS=[['light','light'],['normal','normal'],['medium','medium'],['semibold','semibold'],['bold','bold'],['heavy','heavy']];
+const SLANT_OPTS=[['normal','normal'],['italic','italic'],['oblique','oblique']];
+// A compact custom dropdown for an enum attribute (weight / slant), themed like
+// the color dropdown. The trigger shows the current value drawn in its own weight
+// or slant; the popup lists each option drawn with the attribute applied, so the
+// choice previews itself. opts.styleFor(value) returns the preview style props
+// ({fontWeight} / {fontStyle}); opts.placeholder is the unset-state label.
+function mkEnumDropdown(options,get,set,opts={}){
+ const t=document.createElement('div');t.className='cdd enumdd';t.tabIndex=0;
+ const styleFor=opts.styleFor||(()=>({}));
+ const labelOf=v=>{const o=options.find(p=>p[0]===v);return o?o[1]:'';};
+ function applyPreview(el,v){el.style.fontWeight='';el.style.fontStyle='';const s=styleFor(v);if(s.fontWeight)el.style.fontWeight=s.fontWeight;if(s.fontStyle)el.style.fontStyle=s.fontStyle;}
+ function paint(){const v=get()||'';t.dataset.val=v;t.classList.toggle('is-default',!v);
+ t.textContent=v?labelOf(v):(opts.placeholder||'set');applyPreview(t,v);t.title=opts.title||'';}
+ paint();
+ t.onclick=(e)=>{e.stopPropagation();if(t.dataset.locked==='1')return;if(_ddPop){closeColorDropdown();return;}
+ const pop=document.createElement('div');pop.className='cddpop enumpop';const cur=get()||'';
+ const pick=v=>{set(v||null);paint();closeColorDropdown();};
+ const def=document.createElement('button');def.type='button';
+ def.className='enumopt enumdef'+(cur===''?' sel':'');def.textContent='default';
+ def.title='clear — use the default';def.onclick=ev=>{ev.stopPropagation();pick('');};pop.appendChild(def);
+ for(const [v,label] of options){const b=document.createElement('button');b.type='button';
+ b.className='enumopt'+(v===cur?' sel':'');b.textContent=label;applyPreview(b,v);
+ b.onclick=ev=>{ev.stopPropagation();pick(v);};pop.appendChild(b);}
+ document.body.appendChild(pop);const r=t.getBoundingClientRect();
+ pop.style.left=r.left+'px';pop.style.minWidth=r.width+'px';pop.style.top=(r.bottom+2)+'px';
+ const ph=pop.getBoundingClientRect().height;
+ if(r.bottom+ph>window.innerHeight-6)pop.style.top=Math.max(6,r.top-ph-2)+'px';
+ _ddPop=pop;};
+ t.setValue=()=>paint();t.syncLocked=()=>paint();
+ return t;}
// Underline control: none / line / wave glyph buttons plus a color swatch shown
// while a style is active. Mirrors mkBoxControl; get()/set() read and write the
// underline object ({style,color}) or null.
@@ -171,8 +196,8 @@ function mkStrikeControl(get,set,opts={}){
// underline control lives in the per-row expander (it carries the wave/color
// detail), keeping the row compact.
function mkStyleControls(face,onChange,opts={}){
- const w=mkEnumSelect(WEIGHT_OPTS,()=>face.weight,v=>{face.weight=v;onChange();},'font weight');
- const s=mkEnumSelect(SLANT_OPTS,()=>face.slant,v=>{face.slant=v;onChange();},'font slant');
+ const w=mkEnumDropdown(WEIGHT_OPTS,()=>face.weight,v=>{face.weight=v;onChange();},{placeholder:'weight',title:'font weight',styleFor:v=>({fontWeight:cssWeight(v)})});
+ const s=mkEnumDropdown(SLANT_OPTS,()=>face.slant,v=>{face.slant=v;onChange();},{placeholder:'slant',title:'font slant',styleFor:v=>({fontStyle:v||'normal'})});
const k=mkStrikeControl(()=>face.strike,v=>{face.strike=v;onChange();},opts);
return [w,s,k];}
function mkOverlineControl(get,set,opts={}){