diff options
Diffstat (limited to 'docs/prototypes/panel-widget-gallery.html')
| -rw-r--r-- | docs/prototypes/panel-widget-gallery.html | 99 |
1 files changed, 24 insertions, 75 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index d6e847b..a6d40c9 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -1515,10 +1515,14 @@ const INFO={ const INFO_FIELDS=[['input','input'],['solves','solves'],['use','use'],['limits','limits'], ['origin','origin'],['difficulty','difficulty'],['prefer','prefer when'],['period','period']]; const VLAMP_TITLES={off:'validation: not done',amber:'validation: in progress',green:'validation: done'}; +/* card(host, no, name, htmlOrBuild, note) — the declarative card record. + htmlOrBuild: a legacy stage-HTML string, or a builder function (stage, rd) => handle + that instantiates a GW.* widget into the stage; rd(txt) writes the card readout. */ function card(host, no, name, html, note){ + const isBuild=typeof html==='function'; const c=document.createElement('div'); c.className='card'; c.id='card-'+no; c.innerHTML=`<div class="wname"><span class="no">${no}</span>${name}<span class="vlamp" data-v="off"></span></div>`+ - `<div class="stagew">${html}</div><div class="wrd" id="rd-${no}">—</div>`+ + `<div class="stagew">${isBuild?'':html}</div><div class="wrd" id="rd-${no}">—</div>`+ `<div class="opts"></div><div class="wnote">${note}</div>`; const lamp=c.querySelector('.vlamp'), VKEY='gv-'+no, VSTATES=['off','amber','green']; const setV=v=>{lamp.dataset.v=v;lamp.title=VLAMP_TITLES[v];}; @@ -1533,7 +1537,9 @@ function card(host, no, name, html, note){ if(inf.ref) rows+=`<div class="ik">reference</div><div class="iv"><a href="${inf.ref}" target="_blank">photo</a></div>`; d.innerHTML=`<summary>spec sheet</summary><div class="igrid">${rows}</div>`; c.appendChild(d);} - host.appendChild(c); return c; + host.appendChild(c); + if(isBuild)c.gw=html(c.querySelector('.stagew'),txt=>setRd(no,txt)); + return c; } function setRd(no,txt){const e=$('rd-'+no);if(e)e.textContent=txt;} /* drag helpers, seg7, buildBars live in widgets.js (GW) */ @@ -1541,45 +1547,41 @@ function setRd(no,txt){const e=$('rd-'+no);if(e)e.textContent=txt;} /* ============ CONTROLS ============ */ const C=$('controls'); card(C,'01','Slide toggle', - `<span id="toggle01"><span class="switch on"></span></span>`, + (st,rd)=>GW.slideToggle(st,{on:true,onChange:(v,t)=>rd(t)}), '<b>on / off, the touchscreen way.</b> The one born-digital control in the kit — the smartphone pill toggle the live net/bt/audio panels use. Click to flip; readout shows the state. Physical cousins: the bat-handle (R03) and the rocker (N01).'); card(C,'02','Console key', - `<span id="keys02"><button class="key on">LIVE</button><button class="key">SCAN</button><button class="key red">MUTED</button></span>`, + (st,rd)=>GW.consoleKeys(st,{onChange:(i,t)=>rd(t)}), '<b>physical push button.</b> Mutually exclusive — click one to engage. Gold = live, terracotta = muted.'); card(C,'03','Horizontal fader', - `<div class="fader" id="f1"><div class="slot"><div class="fill" style="width:68%"></div></div><div class="cap" style="left:68%"></div></div>`, + (st,rd)=>GW.faderH(st,{value:68,onChange:(v,t)=>rd(t)}), '<b>continuous 0-100.</b> Per-device volume, brightness. Drag the gold cap; readout tracks.'); card(C,'04','Vertical fader', - `<div class="vfader" id="v1"><div class="slot"><div class="fill" style="height:60%"></div></div><div class="cap" style="bottom:60%"></div></div> - <div class="vfader" id="v2"><div class="slot"><div class="fill" style="height:35%"></div></div><div class="cap" style="bottom:35%"></div></div>`, + (st,rd)=>{let ready=false; + const upd=()=>{if(ready)rd('A '+Math.round(a.get())+' · B '+Math.round(b.get()));}; + const a=GW.faderV(st,{value:60,onChange:upd}); + const b=GW.faderV(st,{value:35,onChange:upd}); + ready=true;upd();return {a,b};}, '<b>channel-strip style.</b> A mixer column per device. Drag each fader up or down.'); card(C,'05','Rotary knob', - `<span class="knob" id="knob"><span class="ind" id="kind"></span></span>`, + (st,rd)=>GW.knob(st,{value:53,onChange:v=>rd('gain '+Math.round(v))}), '<b>dial in a value.</b> Volume/gain the analog way. Drag up/down to turn; readout shows the level.'); card(C,'06','Segmented selector', - `<div class="seg" id="seg06"><button class="on">TIMER</button><button>ALARM</button><button>POMO</button></div>`, + (st,rd)=>GW.segmented(st,{onChange:(i,t)=>rd(t)}), '<b>pick one of a few.</b> Timer type, layout mode. Click a segment; readout names the choice.'); card(C,'07','Chip toggle', - `<span class="chip on" id="chip07">discoverable on</span>`, + (st,rd)=>GW.chipToggle(st,{on:true,onChange:(v,t)=>rd(t)}), '<b>inline binary.</b> A soft toggle inside a line of text. Click to flip; gold when on.'); card(C,'08','Arm-to-fire', - `<button class="arm" id="arm">forget</button>`, + (st,rd)=>GW.armButton(st,{onChange:(v,t)=>rd(t)}), '<b>two-stage confirm.</b> Destructive actions. First click arms (red), second fires. Readout shows the stage.'); card(C,'09','Lamp row', - `<div class="lrow" id="lrow9"><span class="lamp gold"></span><span class="who"><b>WH-1000XM4</b></span><span class="what">tap to connect</span></div>`, + (st,rd)=>GW.lampRow(st,{onChange:(i,t)=>rd(t)}), '<b>actionable list item.</b> Lamp + name + status. Click to cycle idle → connecting → connected.'); card(C,'24','Rotary selector', - `<span class="rotsel" id="rotsel24"> - <span class="pos" style="left:14%;top:53%">4</span><span class="pos" style="left:28%;top:18%">6</span><span class="pos on" style="left:50%;top:7%">8</span><span class="pos" style="left:72%;top:18%">10</span><span class="pos" style="left:86%;top:53%">12</span> - <span class="knob"><span class="ind"></span></span> - </span>`, + (st,rd)=>GW.rotarySelector(st,{onChange:(v,t)=>rd(t)}), '<b>pick one of N by position.</b> Printed detents, the pointer names the value. Click to turn; readout shows it.'); card(C,'25','Slide-rule dial', - `<span class="tuner" id="tuner" tabindex="0" role="slider" aria-label="slide-rule value"> - <span class="tick" style="left:12px"></span><span class="tick" style="left:51px"></span><span class="tick" style="left:90px"></span><span class="tick" style="left:129px"></span><span class="tick" style="left:168px"></span> - <span class="mk" style="left:12px">4</span><span class="mk" style="left:51px">6</span><span class="mk on" style="left:90px">8</span><span class="mk" style="left:129px">10</span><span class="mk" style="left:168px">12</span> - <span class="ndl" id="tundl" style="left:90px"></span> - </span>`, + (st,rd)=>GW.slideRule(st,{onChange:(v,t)=>rd(t)}), '<b>value on a printed scale.</b> A lit pointer glides a warm-backlit strip. Click a mark to jump, or focus it and press ←/→ (↑/↓); readout shows it.'); card(C,'N01','Rocker power switch', `<span class="rocker on" id="rocker"><span class="half top">ON</span><span class="half bot">OFF</span></span>`, @@ -1926,60 +1928,7 @@ card(I,'R52','Blinkenlights front panel', /* ============ CONTROL WIRING ============ */ /* 01 toggle */ -(function(){const sw=$('toggle01').querySelector('.switch'); - function upd(){setRd('01',sw.classList.contains('on')?'ON':'OFF');} - sw.onclick=()=>{sw.classList.toggle('on');upd();};upd();})(); -/* 02 console key */ -$('keys02').querySelectorAll('.key').forEach(k=>k.onclick=()=>{ - $('keys02').querySelectorAll('.key').forEach(x=>x.classList.remove('on','red')); - k.classList.add(k.textContent==='MUTED'?'red':'on');setRd('02',k.textContent);}); -setRd('02','LIVE'); -/* 03 horizontal fader */ -function setF1(p){const f=$('f1');f.querySelector('.fill').style.width=p+'%';f.querySelector('.cap').style.left=p+'%';setRd('03','level '+Math.round(p));} -dragX($('f1'),setF1);setF1(68); -/* 04 vertical faders */ -let vfA=60,vfB=35; -function vfUpd(){setRd('04','A '+Math.round(vfA)+' · B '+Math.round(vfB));} -function setVf(el,p){el.querySelector('.fill').style.height=p+'%';el.querySelector('.cap').style.bottom=p+'%';} -dragY($('v1'),p=>{vfA=p;setVf($('v1'),p);vfUpd();}); -dragY($('v2'),p=>{vfB=p;setVf($('v2'),p);vfUpd();}); -setVf($('v1'),60);setVf($('v2'),35);vfUpd(); -/* 05 knob */ -let knobV=53; -function setKnob(v){knobV=v;$('kind').style.transform=`rotate(${-150+v/100*300}deg)`;setRd('05','gain '+Math.round(v));} -dragDelta($('knob'),()=>knobV,setKnob,{min:0,max:100});setKnob(53); -/* 06 segmented */ -$('seg06').querySelectorAll('button').forEach(b=>b.onclick=()=>{ - $('seg06').querySelectorAll('button').forEach(x=>x.classList.remove('on'));b.classList.add('on');setRd('06',b.textContent);}); -setRd('06','TIMER'); -/* 07 chip */ -$('chip07').onclick=()=>{$('chip07').classList.toggle('on');setRd('07',$('chip07').classList.contains('on')?'ON':'OFF');}; -setRd('07','ON'); -/* 08 arm */ -let armed=false; -$('arm').onclick=()=>{const a=$('arm');if(!armed){armed=true;a.classList.add('armed');a.textContent='forget? again';setRd('08','ARMED');} - else{armed=false;a.classList.remove('armed');a.textContent='forget';setRd('08','FIRED · reset');}}; -setRd('08','SAFE'); -/* 09 lamp row */ -const lrStates=[['gold','tap to connect'],['busy','connecting…'],['','connected']];let lrI=0; -$('lrow9').onclick=()=>{lrI=(lrI+1)%3;const s=lrStates[lrI];$('lrow9').querySelector('.lamp').className='lamp '+s[0]; - $('lrow9').querySelector('.what').textContent=s[1];setRd('09',s[1]);}; -setRd('09','tap to connect'); -/* 24 rotary selector */ -const rotVals=[4,6,8,10,12];let rotIdx=2;const rotAng=[-70,-35,0,35,70]; -$('rotsel24').querySelector('.knob').onclick=()=>{rotIdx=(rotIdx+1)%5; - $('rotsel24').querySelector('.ind').style.transform=`rotate(${rotAng[rotIdx]}deg)`; - $('rotsel24').querySelectorAll('.pos').forEach((p,i)=>p.classList.toggle('on',i===rotIdx));setRd('24','size '+rotVals[rotIdx]);}; -setRd('24','size 8'); -/* 25 slide-rule */ -const tunVals=[4,6,8,10,12];let tunIdx=2;const tunX=[12,51,90,129,168]; -function setTun(i){tunIdx=Math.max(0,Math.min(tunVals.length-1,i));$('tundl').style.left=tunX[tunIdx]+'px'; - $('tuner').querySelectorAll('.mk').forEach((m,j)=>m.classList.toggle('on',j===tunIdx));setRd('25','pos '+tunVals[tunIdx]);} -$('tuner').onclick=(e)=>{const r=$('tuner').getBoundingClientRect(),x=e.clientX-r.left; - let best=0,bd=1e9;tunX.forEach((tx,j)=>{const d=Math.abs(tx-x);if(d<bd){bd=d;best=j;}});setTun(best);$('tuner').focus();}; -$('tuner').onkeydown=(e)=>{if(e.key==='ArrowLeft'||e.key==='ArrowDown'){e.preventDefault();setTun(tunIdx-1);} - else if(e.key==='ArrowRight'||e.key==='ArrowUp'){e.preventDefault();setTun(tunIdx+1);}}; -setRd('25','pos 8'); +/* 01-09, 24, 25 extracted to widgets.js (GW.*) — wired at their card records */ /* N01 rocker */ $('rocker').onclick=()=>{$('rocker').classList.toggle('on');setRd('N01',$('rocker').classList.contains('on')?'ON':'OFF');}; setRd('N01','ON'); |
