From 858caec5aa942ba621845d054c000269e0fe0384 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Jul 2026 20:24:11 -0500 Subject: feat(gallery): validation lamps and the readout/options/text card order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every card gets a status lamp at the upper-right for the pre-componentization validation pass: click cycles not-done, in-progress, done, and the state persists per card in localStorage. Below the stage the card now reads readout, then options, then descriptive text, with separators between the zones and no labels — chips moved into a generic options container that future selectors share. --- docs/prototypes/panel-widget-gallery.html | 29 +++++++++++++++++++++++------ todo.org | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index fbf2e0a..99342bc 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -102,12 +102,21 @@ h2::after{content:"";height:1px;background:var(--wash);flex:1} box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 6px 14px rgba(0,0,0,.4)} .wname{color:var(--cream);font-size:.95rem;font-weight:700;display:flex;align-items:center;gap:8px} .wname .no{color:var(--panel);background:var(--gold);border-radius:4px;font-size:.7rem;padding:0 5px;font-weight:400} +/* validation lamp: off = not done, amber = in progress, green = done; click cycles, state persists */ +.vlamp{margin-left:auto;flex:0 0 auto;width:10px;height:10px;border-radius:50%;cursor:pointer; + background:#221f1b;border:1px solid #33302b} +.vlamp[data-v="amber"]{background:var(--gold);border-color:#7d5c16;box-shadow:0 0 6px 1px rgba(var(--glow-lo),.6)} +.vlamp[data-v="green"]{background:var(--pass);border-color:#4a5c22;box-shadow:0 0 6px 1px rgba(116,147,47,.6)} .stagew{background:var(--well);border:1px solid #201d17;border-radius:9px;padding:14px 12px; min-height:78px;display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap} .wrd{color:var(--gold-hi);font-size:.8rem;letter-spacing:.06em;font-variant-numeric:tabular-nums; - min-height:.95rem;display:flex;align-items:center;gap:6px} + min-height:.95rem;display:flex;align-items:center;gap:6px; + border-top:1px solid var(--wash);padding-top:9px;margin-top:2px} .wrd::before{content:"▸";color:var(--steel);font-size:.7rem} -.wnote{color:var(--dim);font-size:.85rem;line-height:1.45} +.opts{display:flex;flex-direction:column;gap:5px} +.opts:empty{display:none} +.wnote{color:var(--dim);font-size:.85rem;line-height:1.45; + border-top:1px solid var(--wash);padding-top:9px;margin-top:2px} .wnote b{color:var(--steel);font-weight:400} /* per-card spec sheet (collapsible) */ @@ -795,7 +804,7 @@ function screenChips(no,el,fams,def){ row.querySelectorAll('.fc').forEach(x=>x.classList.toggle('on',x===b)); setRd(no,'screen '+f);}); row.appendChild(b);}); - cardEl.insertBefore(row,cardEl.querySelector('.wrd')); + cardEl.querySelector('.opts').appendChild(row); } /* ---- per-card spec sheets ---- input how you drive it, incl. the model: click widgets port to every target (Emacs click-regions @@ -1517,10 +1526,18 @@ 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'}; function card(host, no, name, html, note){ const c=document.createElement('div'); c.className='card'; - c.innerHTML=`
${no}${name}
`+ - `
${html}
${note}
`; + c.innerHTML=`
${no}${name}
`+ + `
${html}
`+ + `
${note}
`; + const lamp=c.querySelector('.vlamp'), VKEY='gv-'+no, VSTATES=['off','amber','green']; + const setV=v=>{lamp.dataset.v=v;lamp.title=VLAMP_TITLES[v];}; + setV(localStorage.getItem(VKEY)||'off'); + lamp.addEventListener('click',e=>{e.stopPropagation(); + const v=VSTATES[(VSTATES.indexOf(lamp.dataset.v)+1)%3]; + setV(v);localStorage.setItem(VKEY,v);}); const inf=(typeof INFO!=='undefined')&&INFO[no]; if(inf){const d=document.createElement('details'); d.className='winfo'; let rows=''; @@ -4244,7 +4261,7 @@ BOOST.forEach(no=>{const rd=document.getElementById('rd-'+no); row.appendChild(b);}}; group('on',ON_OPTS,'amber'); group('off',OFF_OPTS,'dark'); - cardEl.insertBefore(row,cardEl.querySelector('.wrd'));})(); + cardEl.querySelector('.opts').appendChild(row);})(); diff --git a/todo.org b/todo.org index 7afc720..36959d0 100644 --- a/todo.org +++ b/todo.org @@ -59,6 +59,8 @@ New "Palette — design tokens" section above Controls: 33 tiles read live from Six period families defined (green = P1 phosphor built on =phos=, amber = P3 on the gold family, red = the nixie neon pulled out, blue = P4 white-blue, vfd = the marquee's =--vfd=, white = mono LCD), applied via scoped CSS vars with the shipped color as fallback — defaults are pixel-identical until a chip is clicked. Chips on the five clearly-screen widgets: R10 data matrix (amber), R17 CRT scope (green face), R19 waveform LCD (white), R31 radar (amber — the "in amber" one; green chip gives the classic PPI), N11 oscilloscope (green). Answers to the green question: the kit deliberately has four greens — phos #7fe0a0 (CRT trace), vfd #63e6c8 (marquee, blue-leaning), sevgrn #57d357 (LED), jewel-g #6fce33 (jewel lens); the phosphor-screen green is phos, not the others. Nixie left chipless: neon is only ever orange. Families live in gallery JS, not tokens.json — tokenize the winners once picked, the way amber earned its tokens. CDP-verified: recolors land on all five, interactions intact, zero exceptions. *** 2026-07-12 Sun @ 13:15:19 -0500 Added spec sheets to all 84 cards Every card now carries a collapsible "spec sheet" (a details element under the note) with up to 8 fields: input (always present, names the model — click ports everywhere including Emacs click-regions, drag needs a click/key idiom there, display widgets take no real input), solves, use (common vs specialty + where it shines), limits, origin, difficulty, prefer-when, and period (present on 41 of 84 — only where the component is clearly not timeless, e.g. nixie 1955-75 sits with keypads/telegraphs and clashes with VFD and LED seven-seg). Content lives in one INFO object keyed by card number; card() renders it. CDP-verified: 84/84 sheets present (missing-key check), fields render, zero exceptions. +*** TODO Widget validation pass +Craig validates every control before any componentization build (his call — the lamps are his worklist, not agent-checkable). Each card carries a status lamp at the upper-right: click cycles off → amber → green, state persists per card in localStorage (key =gv-=). When the pass completes, bake the final statuses into the gallery source and use the green set as the build order for the widgets.js extraction. *** TODO Component classification taxonomy Brainstorm WITH Craig (after the squash merge, not solo): break the components down by use — freeform output, binary selection, multi-selection, fine-tuning, etc. The taxonomy identifies use-cases with no appropriate component, which fills out the gallery with some confidence of completeness. ** DOING [#B] Retro widget catalogue :feature:design: -- cgit v1.2.3