From c15c835425141ca018aa02e6b2f7447a73e152ca Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 13 Jul 2026 00:23:23 -0500 Subject: feat(gallery): give the segmented selector amber, green, and red accents The lit segment rides new --seg-on-* vars with the shipped amber as the stylesheet fallback, and GW.segmented gains opts.accent plus setStyle backed by GW.segmented.STYLES, the same shape as the slide toggle. Card 06 is the third chips demo rig, so the per-card IIFEs collapse into one styleChips(no, STYLES, AXES) helper serving cards 01, R05, and 06. --- docs/prototypes/panel-widget-gallery.html | 37 +++++++++---------------------- docs/prototypes/widgets.js | 22 +++++++++++++++--- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 63695df..654ffd5 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -1131,7 +1131,7 @@ card(C,'05','Rotary knob', 'dial in a value. Volume/gain the analog way. Drag up/down to turn; readout shows the level.'); card(C,'06','Segmented selector', (st,rd)=>GW.segmented(st,{onChange:(i,t)=>rd(t)}), - 'pick one of a few. Timer type, layout mode. Click a segment; readout names the choice.'); + 'pick one of a few. Timer type, layout mode. Click a segment; readout names the choice. The lit segment ships in amber, green, or red — the accent chips below switch it.'); card(C,'07','Chip toggle', (st,rd)=>GW.chipToggle(st,{on:true,onChange:(v,t)=>rd(t)}), 'inline binary. A soft toggle inside a line of text. Click to flip; gold when on.'); @@ -1584,43 +1584,28 @@ BOOST.forEach(no=>{const rd=document.getElementById('rd-'+no); el.innerHTML=el.innerHTML.replace(/\b(R\d{2}|N\d{2})\b/g, m=>ids.has(m)?`${m}`:m);});})(); -/* slide-toggle style chips: demo rig for GW.slideToggle's constructor opts — - the named styles live in GW.slideToggle.STYLES; chips drive setStyle on the live instance */ -(function(){const h=$('card-01')?.gw;if(!h)return; +/* style chips: shared demo rig for builders with constructor style opts — + reads a builder's STYLES table and drives setStyle on the live card instance */ +function styleChips(no,STYLES,AXES){ + const h=$('card-'+no)?.gw; if(!h)return; const cardEl=h.el.closest('.card'); const row=document.createElement('div'); row.className='famchips'; - const AXES=[['on','on','amber'],['off','off','dark'],['off text','offText','white'],['thumb','thumb','light']]; for(const [label,axis,def] of AXES){ const g=document.createElement('span'); g.className='fgroup'; const lab=document.createElement('span'); lab.className='lab'; lab.textContent=label; g.appendChild(lab); const chips=[]; - for(const [name,o] of Object.entries(GW.slideToggle.STYLES[axis])){ + for(const [name,o] of Object.entries(STYLES[axis])){ const b=document.createElement('span'); b.className='fc'+(name===def?' on':''); b.style.background=o.dot; b.title=name; chips.push(b); b.addEventListener('click',()=>{h.setStyle(axis,name); chips.forEach(x=>x.classList.toggle('on',x===b));}); g.appendChild(b);} row.appendChild(g);} - cardEl.querySelector('.opts').appendChild(row);})(); - -/* filter-bank style chips: demo rig for GW.filterBank's constructor opts — - the named skins live in GW.filterBank.STYLES; chips drive setStyle on the live instance */ -(function(){const h=$('card-R05')?.gw;if(!h)return; - const cardEl=h.el.closest('.card'); - const row=document.createElement('div'); row.className='famchips'; - const AXES=[['panel','panel','silver'],['shape','caps','block'],['color','capColor','black']]; - for(const [label,axis,def] of AXES){ - const g=document.createElement('span'); g.className='fgroup'; - const lab=document.createElement('span'); lab.className='lab'; lab.textContent=label; g.appendChild(lab); - const chips=[]; - for(const [name,o] of Object.entries(GW.filterBank.STYLES[axis])){ - const b=document.createElement('span'); b.className='fc'+(name===def?' on':''); - b.style.background=o.dot; b.title=name; chips.push(b); - b.addEventListener('click',()=>{h.setStyle(axis,name); - chips.forEach(x=>x.classList.toggle('on',x===b));}); - g.appendChild(b);} - row.appendChild(g);} - cardEl.querySelector('.opts').appendChild(row);})(); + cardEl.querySelector('.opts').appendChild(row); +} +styleChips('01',GW.slideToggle.STYLES,[['on','on','amber'],['off','off','dark'],['off text','offText','white'],['thumb','thumb','light']]); +styleChips('R05',GW.filterBank.STYLES,[['panel','panel','silver'],['shape','caps','block'],['color','capColor','black']]); +styleChips('06',GW.segmented.STYLES,[['accent','accent','amber']]); /* final tally pass: setV fires per card during build, but each card is still detached at that moment, so the running counts lag by one — recount now */ diff --git a/docs/prototypes/widgets.js b/docs/prototypes/widgets.js index 1465e46..d194068 100644 --- a/docs/prototypes/widgets.js +++ b/docs/prototypes/widgets.js @@ -234,17 +234,33 @@ GW.knob = function (host, opts = {}) { return { el: k, get: () => val, set }; }; -/* 06 segmented selector — pick one of a few */ +/* 06 segmented selector — pick one of a few. opts.accent picks the lit-segment + color from GW.segmented.STYLES (amber / green / red); defaults match the + stylesheet fallbacks. setStyle(axis, name) restyles a live instance. */ GW.segmented = function (host, opts = {}) { const onChange = opts.onChange || noop; const items = opts.items || ['TIMER', 'ALARM', 'POMO']; const seg = document.createElement('div'); seg.className = 'seg'; host.appendChild(seg); + const setStyle = (axis, name) => { + const o = (GW.segmented.STYLES[axis] || {})[name]; + if (!o) return; + for (const [k, v] of Object.entries(o.vars)) seg.style.setProperty(k, v); + }; + setStyle('accent', opts.accent || 'amber'); const btns = items.map(t => { const b = document.createElement('button'); b.textContent = t; seg.appendChild(b); return b; }); let idx; const set = i => { idx = i; btns.forEach((b, j) => b.classList.toggle('on', j === i)); onChange(i, items[i]); }; btns.forEach((b, i) => b.addEventListener('click', () => set(i))); set(opts.active || 0); - return { el: seg, get: () => idx, set }; + return { el: seg, get: () => idx, set, setStyle }; +}; +/* named styles per axis: dot = swatch color for pickers, vars = --seg-* overrides */ +GW.segmented.STYLES = { + accent: { + amber: { dot: 'var(--gold-hi)', vars: { '--seg-on-bg': 'linear-gradient(180deg,var(--amber-grad-top),var(--gold))', '--seg-on-ink': 'var(--panel)' } }, + green: { dot: '#8fb944', vars: { '--seg-on-bg': 'linear-gradient(180deg,#a9c95f,var(--pass))', '--seg-on-ink': 'var(--panel)' } }, + red: { dot: 'var(--fail)', vars: { '--seg-on-bg': 'linear-gradient(180deg,#d98a6f,var(--fail))', '--seg-on-ink': 'var(--panel)' } }, + }, }; /* 07 chip toggle — inline binary inside a line of text */ @@ -4041,7 +4057,7 @@ const GW_CSS = ` .seg{display:flex;border:1px solid #33302b;border-radius:8px;overflow:hidden} .seg button{font:inherit;font-size:11px;color:var(--silver);background:#191715;border:0;border-right:1px solid #33302b;padding:7px 11px;cursor:pointer} .seg button:last-child{border-right:0} -.seg button.on{background:linear-gradient(180deg,var(--amber-grad-top),var(--gold));color:var(--panel);font-weight:700} +.seg button.on{background:var(--seg-on-bg,linear-gradient(180deg,var(--amber-grad-top),var(--gold)));color:var(--seg-on-ink,var(--panel));font-weight:700} /* engraved section label */ .engrave{width:180px;color:var(--steel);font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;cursor:pointer; -- cgit v1.2.3