From 4064de53a9abfa7620d9d7e3f95e867ba0bf54e3 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Jul 2026 22:35:24 -0500 Subject: refactor(gallery): extract indicators N20-N28 into GW builders --- docs/prototypes/panel-widget-gallery.html | 137 +++++------------------------- 1 file changed, 20 insertions(+), 117 deletions(-) (limited to 'docs/prototypes/panel-widget-gallery.html') diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 0e10631..2d7bcb9 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -1823,37 +1823,31 @@ card(I,'26','Nixie tube', (st,rd)=>GW.nixie(st,{onChange:(v,t)=>rd(t)}), 'a single warm-glowing numeral. One lit digit per tube, leading zeros dark. Click to increment the count.'); card(I,'N20','Split-flap display', - `DNS`, + (st,rd)=>GW.splitFlap(st,{animate:!reduced,onChange:(v,t)=>rd(t)}), 'flips to the new value. Each card drops to the next glyph with the mechanical clack. Auto-flips; click to flip now.'); card(I,'N21','Seven-segment display', - ``, + (st,rd)=>GW.sevenSeg(st,{onChange:(v,t)=>rd(t)}), 'a lit-segment number. Green segments, distinct from the nixie glow. Live countdown; click to add a minute.'); card(I,'N22','VFD marquee', - `ARCHSETUP · NET OK · BT 2 · SND 62%`, + (st,rd)=>GW.vfdMarquee(st,{onChange:(v,t)=>rd(t)}), 'scrolling status line. Teal glow, dot-matrix mesh, text tracks across. Scrolls live; click to change the message.'); card(I,'N23','Annunciator panel', - `
- SYNCLOW BATTLINK - NO DNSVPNDISK -
MSTR CAUTION - -
`, + (st,rd)=>GW.annunciator(st,{onChange:(v,t)=>rd(t)}), 'a grid of named alarms with the alarm lifecycle. Cells light amber to warn, red to fault; any active alarm flashes MSTR CAUTION until ACK steadies it, a new alarm re-flashes it, RESET clears the board, TEST proves the bulbs. Click cells to raise alarms.'); card(I,'N24','Jewel pilot lamps', - ` - `, + (st,rd)=>GW.jewels(st,{onChange:(v,t)=>rd(t)}), 'a faceted glass indicator. The chunky bezel pilot lamp with a real bloom. Click a jewel to cycle red · amber · green · dark.'); card(I,'N25','Tape counter', - ``, + (st,rd)=>GW.tapeCounter(st,{onChange:(v,t)=>rd(t)}), 'rolling odometer digits. Numbered wheels roll to the next figure. Rolls live; readout shows the total.'); card(I,'N26','Analog clock', - ``, + (st,rd)=>GW.analogClock(st,{onChange:(v,t)=>rd(t)}), 'time on a real face. Engraved ticks, three hands, live seconds sweep. Runs live; readout shows the time.'); card(I,'N27','Frequency-dial scale', - `MHz`, + (st,rd)=>GW.freqScale(st,{onChange:(v,t)=>rd(t)}), 'a printed log scale. Marks crowd low, spread high — a real logarithmic axis. Drag the pointer; readout shows the frequency.'); card(I,'N28','Patch-bay jack field', - `
`, + (st,rd)=>GW.patchBay(st,{onChange:(v,t)=>rd(t)}), 'routing shown as patches. A grid of jacks with cables between connected pairs. Click one jack then another to add/remove a cable.'); card(I,'R10','Data matrix readout', ``, @@ -1901,70 +1895,7 @@ card(I,'R52','Blinkenlights front panel', /* ============ INDICATOR WIRING ============ */ /* 18-23, 26 extracted to widgets.js (GW.*) — wired at their card records */ -/* N23 annunciator with alarm lifecycle: raise -> MSTR CAUTION flashes -> ACK steadies -> RESET clears */ -(function(){const st=['acell','acell warn','acell fault'];const nm=['ok','warn','fault']; - const mc=$('anmc');let acked=false; - const active=()=>$('annun').querySelectorAll('.warn,.fault').length; - const refresh=()=>{const n=active(); - mc.classList.toggle('on',n>0); - mc.classList.toggle('fl',n>0&&!acked); - setRd('N23',n===0?'clear':n+' active · '+(acked?'ACK':'UNACK'));}; - $('annun').querySelectorAll('.acell').forEach(cell=>{const label=cell.textContent;cell.onclick=()=>{ - let cur=cell.className.trim();let i=st.indexOf(cur);if(i<0)i=0;i=(i+1)%st.length;cell.className=st[i]; - if(i>0)acked=false; // a new alarm re-arms the flasher - refresh();setRd('N23',label+' → '+nm[i]);};}); - $('annbar').querySelectorAll('.key').forEach(k=>k.addEventListener('click',()=>{ - const a=k.dataset.k; - if(a==='ACK'){if(active()>0)acked=true;refresh();} - else if(a==='RESET'){$('annun').querySelectorAll('.acell').forEach(c=>c.className='acell');acked=false;refresh();} - else if(a==='TEST'){const prev=[...$('annun').querySelectorAll('.acell')].map(c=>c.className); - $('annun').querySelectorAll('.acell').forEach(c=>c.className='acell fault'); - mc.classList.add('on','fl');setRd('N23','lamp test'); - setTimeout(()=>{[...$('annun').querySelectorAll('.acell')].forEach((c,i)=>c.className=prev[i]);refresh();},1100);}})); - refresh();})(); -/* N24 jewel */ -(function(){const cols=['var(--jewel-r)','var(--jewel-a)','var(--jewel-g)'];const nm=['red','amber','green']; - $('jewels').querySelectorAll('.jewel').forEach(j=>{j.onclick=()=>{ - if(j.classList.contains('dim')){j.classList.remove('dim');j.style.setProperty('--jc',cols[0]);setRd('N24','red');return;} - let cur=j.style.getPropertyValue('--jc').trim();let i=cols.indexOf(cur); - if(i>=cols.length-1||i<0){j.classList.add('dim');setRd('N24','dark');}else{j.style.setProperty('--jc',cols[i+1]);setRd('N24',nm[i+1]);}};});})(); -setRd('N24','click to cycle'); -/* N27 frequency-dial + pointer */ -(function(){const fs=$('fscale');const W=184;const marks=[0.5,1,2,3,5,7,10,14,20];const lo=Math.log10(0.5),hi=Math.log10(20); - marks.forEach(m=>{const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12); - const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='11px';fs.appendChild(tk); - const mk=document.createElement('span');mk.className='mk';mk.style.left=x+'px';mk.textContent=m;fs.appendChild(mk);}); - for(let m=0.5;m<=20;m+=(m<2?0.25:m<10?1:2)){const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12); - const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='6px';tk.style.opacity='.5';fs.appendChild(tk);} - const ptr=document.createElement('span');ptr.className='fptr';fs.appendChild(ptr); - function freqAt(p){return Math.pow(10,lo+(p/100)*(hi-lo));} - window.setFreq=function(p){ptr.style.left=(6+p/100*(W-12))+'px';const f=freqAt(p);setRd('N27',(f<10?f.toFixed(1):Math.round(f))+' MHz');}; - dragX(fs,window.setFreq);window.setFreq(45);})(); -/* N28 patch-bay */ -(function(){const patch=$('patch');const rows=2,cols=4;const jacks=[]; - for(let r=0;rj.classList.remove('hot')); - conns.forEach(pair=>{const[a,b]=pair.split('-').map(Number); - const ra=jacks[a].getBoundingClientRect(),rb=jacks[b].getBoundingClientRect(); - const x1=ra.left-pr.left+ra.width/2,y1=ra.top-pr.top+ra.height/2; - const x2=rb.left-pr.left+rb.width/2,y2=rb.top-pr.top+rb.height/2; - const p=document.createElementNS('http://www.w3.org/2000/svg','path'); - const my=Math.max(y1,y2)+16;p.setAttribute('d',`M${x1} ${y1} C${x1} ${my} ${x2} ${my} ${x2} ${y2}`);svg.appendChild(p); - jacks[a].classList.add('hot');jacks[b].classList.add('hot');}); - setRd('N28',conns.length?conns.map(c=>{const[a,b]=c.split('-');return a+'↔'+b;}).join(' '):'no cables');} - jacks.forEach(j=>{j.onclick=()=>{const id=+j.dataset.id; - if(pending==null){pending=id;j.classList.add('sel');return;} - if(pending===id){pending=null;j.classList.remove('sel');return;} - const k=key(pending,id);const i=conns.indexOf(k);if(i>=0)conns.splice(i,1);else conns.push(k); - jacks[pending].classList.remove('sel');pending=null;draw();};}); - conns=['0-5','2-7'];draw();window.addEventListener('resize',draw);})(); +/* N20-N28 extracted to widgets.js (GW.*) — wired at their card records */ /* ============ REFERENCE-BATCH (R) WIDGETS — SVG builders ============ */ /* svgEl, polar, VUDB live in widgets.js (GW) */ @@ -2199,14 +2130,8 @@ setRgraph(1200,6.5); /* extracted meters: the page keeps the clock + demo signal, drives card handles */ const MH={vu:$('card-11').gw,mini:$('card-12').gw,spark:$('card-16').gw,wave:$('card-17').gw, scope:$('card-N11').gw,eq:$('card-N12').gw,strip:$('card-N16').gw,mcvu:$('card-R01').gw}; -(function(){const cl=$('clock');for(let i=0;i<12;i++){const t=document.createElement('span');t.className='tk'; - t.style.transform=`rotate(${i*30}deg)`;cl.insertBefore(t,cl.firstChild);}})(); -const counterDigits=[4,7,1,3,0,0]; -(function(){const ct=$('counter');counterDigits.forEach((d,idx)=>{const w=document.createElement('span'); - w.className='cwheel'+(idx>=4?' redw':'');const col=document.createElement('span');col.className='col'; - for(let n=-1;n<=10;n++){const s=document.createElement('span');s.textContent=((n+10)%10);col.appendChild(s);} - w.appendChild(col);ct.appendChild(w);setWheel(w,d);});})(); -function setWheel(w,d){w.querySelector('.col').style.top=(-(d+1)*34)+'px';} +const IH={flap:$('card-N20').gw,seven:$('card-N21').gw,vfd:$('card-N22').gw, + counter:$('card-N25').gw,clock:$('card-N26').gw}; let ph=0; const eqBands=Array.from({length:11},(_,i)=>({v:0.4,ph:i*0.6})); @@ -2226,36 +2151,14 @@ function fastTick(){ MH.eq.set(eqBands.map(bd=>bd.v)); MH.strip.push((28+24*Math.sin(ph*0.7)*(0.6+0.4*Math.sin(ph*0.13))-(Math.random()-0.5)*4)/56); } -/* clock */ -function tickClock(){const d=new Date();const s=d.getSeconds(),m=d.getMinutes(),h=d.getHours()%12; - $('clks').style.transform=`rotate(${s*6}deg)`;$('clkm').style.transform=`rotate(${m*6+s*0.1}deg)`;$('clkh').style.transform=`rotate(${h*30+m*0.5}deg)`; - setRd('N26',String(d.getHours()).padStart(2,'0')+':'+String(m).padStart(2,'0')+':'+String(s).padStart(2,'0'));} -/* split-flap */ -const flapWords=['DNS ','LINK','SYNC','WIFI','SCAN'];let flapI=0; -function tickFlap(){flapI=(flapI+1)%flapWords.length;const w=flapWords[flapI].padEnd(4,' '); - $('flap').querySelectorAll('.flapd').forEach((dd,i)=>{const ch=w[i]||' ';const bel=dd.querySelector('b'); - if(bel.textContent!==ch){bel.textContent=ch;if(!reduced){dd.classList.remove('flip');void dd.offsetWidth;dd.classList.add('flip');}}}); - setRd('N20',flapWords[flapI].trim());} -$('flap').onclick=tickFlap; -/* seven-segment countdown */ -let sevenSecs=24*60+10; -function renderSeven(){const mm=String(Math.floor(sevenSecs/60)).padStart(2,'0'),ss=String(sevenSecs%60).padStart(2,'0'); - $('seven').innerHTML=seg7(mm[0])+seg7(mm[1])+''+seg7(ss[0])+seg7(ss[1]);setRd('N21',mm+':'+ss);} -function tickSeven(){sevenSecs=(sevenSecs-1+3600)%3600;renderSeven();} -$('seven').onclick=()=>{sevenSecs=(sevenSecs+60)%3600;renderSeven();}; -renderSeven(); -/* tabular timer: builder owns the countdown; the page keeps the 1s clock */ +/* indicator loops: builders own state + clicks; the page keeps the clocks and + the time source (tick contract) */ +function tickClock(){const d=new Date();IH.clock.set(d.getHours(),d.getMinutes(),d.getSeconds());} +function tickFlap(){IH.flap.next();} +function tickSeven(){IH.seven.tick();} function tickT(){$('card-20').gw.tick();} -/* VFD marquee */ -const vfdMsgs=['ARCHSETUP · NET OK · BT 2 · SND 62%','WIFI @Hyatt · 300 Mbps · VPN UP','BATTERY 84% · DISK 61% · TEMP 47C'];let vfdMi=0,vfdX=176; -function tickVfd(){const t=$('vfdt');vfdX-=1.1;if(vfdX< -t.offsetWidth)vfdX=176;t.style.left=vfdX+'px';} -$('vfdm').onclick=()=>{vfdMi=(vfdMi+1)%vfdMsgs.length;$('vfdt').textContent=vfdMsgs[vfdMi];vfdX=176;setRd('N22','msg '+(vfdMi+1)+'/'+vfdMsgs.length);}; -setRd('N22','scrolling'); -/* tape counter */ -let ctrVal=471300; -function tickCounter(){ctrVal+=137;const s=String(ctrVal).padStart(6,'0'); - $('counter').querySelectorAll('.cwheel').forEach((w,i)=>setWheel(w,+s[i]));setRd('N25',s);} -setRd('N25',String(ctrVal).padStart(6,'0')); +function tickVfd(){IH.vfd.tick();} +function tickCounter(){IH.counter.set(IH.counter.get()+137);} /* reels spin keyframe */ (function(){const st=document.createElement('style');st.textContent='@keyframes reelspin{to{transform:rotate(360deg)}}';document.head.appendChild(st);})(); @@ -2270,7 +2173,7 @@ function paintStatic(){ MH.eq.set(eqBands.map(bd=>bd.v)); MH.scope.set(Array.from({length:60},(_,i)=>Math.sin(i*0.5)*18/22),0.74); MH.strip.set(Array.from({length:60},(_,i)=>0.5+Math.sin(i*0.3)*16/56),0.5); - tickClock();renderSeven();setRd('N20','DNS');setRd('N22','scrolling');setRd('N25',String(ctrVal).padStart(6,'0')); + tickClock();IH.flap.set(0); MH.mcvu.set(.5); } -- cgit v1.2.3