← back to Dw Photo Capture
Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Auto) + accents, smart Suggested action, full UX (TK-12346)
6e2c3f26066caa4738bb3ee9bb3386d8f3b82eca · 2026-09-26 10:42:20 -0700 · Steve Abrams
Themed card chooser with icons, descriptions, 1-4/Enter shortcuts, incoming-samples
badge, last-used fallback suggestion, ARIA radiogroups, reduced-motion. Tokens scoped
to #homeScreen; theme/accent persisted in localStorage.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF
Files touched
Diff
commit 6e2c3f26066caa4738bb3ee9bb3386d8f3b82eca
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Sep 26 10:42:20 2026 -0700
Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Auto) + accents, smart Suggested action, full UX (TK-12346)
Themed card chooser with icons, descriptions, 1-4/Enter shortcuts, incoming-samples
badge, last-used fallback suggestion, ARIA radiogroups, reduced-motion. Tokens scoped
to #homeScreen; theme/accent persisted in localStorage.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF
---
public/index.html | 180 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 158 insertions(+), 22 deletions(-)
diff --git a/public/index.html b/public/index.html
index ce8a83a..9435d0a 100644
--- a/public/index.html
+++ b/public/index.html
@@ -419,18 +419,69 @@
#mUse{background:#2bd06a;color:#032}#mClose{background:#222;color:#fff}
.add-spec{display:flex;justify-content:space-between;gap:12px;font-size:12.5px;padding:4px 0;border-bottom:1px solid rgba(255,255,255,.05)}
.add-spec span{color:#9a917d}.add-spec b{color:var(--ink);text-align:right}
- /* onload chooser — three white pills on black */
- #homeScreen{position:fixed;inset:0;z-index:200;background:#000;display:flex;align-items:center;justify-content:center}
+ /* ── onload chooser (TK-12346): Adobe Spectrum themes (Light · Dark · Darkest) + accent, full UX ──
+ Tokens are scoped to #homeScreen so the rest of the app is untouched. Theme/accent persist in localStorage. */
+ #homeScreen{--h-bg:#080808;--h-surface:#1a1a1a;--h-surface-2:#232323;--h-border:#2c2c2c;--h-border-hi:#4a4a4a;
+ --h-ink:#e8e8e8;--h-muted:#9a9a9a;--h-accent:#2680eb;--h-accent-ink:#fff;--h-accent-soft:rgba(38,128,235,.16);--h-focus:#5aa9fa;
+ position:fixed;inset:0;z-index:200;background:var(--h-bg);color:var(--h-ink);overflow-y:auto;-webkit-overflow-scrolling:touch;
+ font-family:"Adobe Clean","Source Sans 3","SF Pro Text",-apple-system,system-ui,sans-serif;transition:background .2s,color .2s}
#homeScreen[hidden]{display:none}
- .home-inner{display:flex;flex-direction:column;gap:16px;align-items:center;width:100%;max-width:340px;padding:24px}
- .home-title{color:#fff;font-size:14px;letter-spacing:.1em;text-transform:uppercase;opacity:.55;margin-bottom:16px}
- .home-pill{width:100%;background:#fff;color:#000;border:none;border-radius:999px;padding:20px;font-size:19px;font-weight:700;cursor:pointer}
- .home-pill:active{transform:scale(.98)}
- .home-skip{margin-top:10px;background:none;border:none;color:#fff;opacity:.4;font-size:14px;cursor:pointer}
- .home-apps{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;width:100%;margin-top:20px;padding-top:16px;border-top:1px solid rgba(255,255,255,.15)}
- .home-apps-lbl{width:100%;text-align:center;color:#fff;opacity:.45;font-size:11px;letter-spacing:.1em;text-transform:uppercase}
- .home-apps a{color:#fff;text-decoration:none;border:1px solid rgba(255,255,255,.3);border-radius:999px;padding:8px 13px;font-size:13px}
+ #homeScreen[data-theme=dark]{--h-bg:#1d1d1d;--h-surface:#2c2c2c;--h-surface-2:#353535;--h-border:#3e3e3e;--h-border-hi:#5a5a5a;--h-ink:#ebebeb;--h-muted:#a8a8a8}
+ #homeScreen[data-theme=light]{--h-bg:#f5f5f5;--h-surface:#ffffff;--h-surface-2:#f0f0f0;--h-border:#dadada;--h-border-hi:#b1b1b1;--h-ink:#1f1f1f;--h-muted:#6d6d6d;--h-focus:#1473e6}
+ #homeScreen[data-accent=gold]{--h-accent:#c9a45c;--h-accent-ink:#1b1407;--h-accent-soft:rgba(201,164,92,.18)}
+ #homeScreen[data-accent=green]{--h-accent:#12805c;--h-accent-ink:#fff;--h-accent-soft:rgba(18,128,92,.18)}
+ #homeScreen[data-accent=purple]{--h-accent:#7e4bf3;--h-accent-ink:#fff;--h-accent-soft:rgba(126,75,243,.18)}
+ #homeScreen[data-accent=red]{--h-accent:#d31510;--h-accent-ink:#fff;--h-accent-soft:rgba(211,21,16,.15)}
+ .home-inner{display:flex;flex-direction:column;gap:12px;width:100%;max-width:440px;margin:0 auto;
+ padding:max(18px,env(safe-area-inset-top)) 16px max(22px,env(safe-area-inset-bottom));min-height:100%;box-sizing:border-box;justify-content:center}
+ .home-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:4px}
+ .home-title{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--h-muted);font-weight:700}
+ .home-greet{font-size:22px;font-weight:800;line-height:1.15;margin-top:4px;color:var(--h-ink)}
+ .home-date{font-size:12.5px;color:var(--h-muted);margin-top:2px}
+ .home-theme-btn{flex:0 0 auto;display:flex;align-items:center;gap:6px;background:var(--h-surface);color:var(--h-ink);border:1px solid var(--h-border);
+ border-radius:999px;padding:7px 11px;font-weight:600;font-size:12.5px;line-height:1;font-family:inherit;cursor:pointer}
+ .home-theme-btn .dot{width:12px;height:12px;border-radius:50%;background:var(--h-accent)}
+ .home-prefs{background:var(--h-surface);border:1px solid var(--h-border);border-radius:14px;padding:12px;display:flex;flex-direction:column;gap:10px}
+ .home-prefs[hidden]{display:none}
+ .home-prefs-lbl{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--h-muted);font-weight:700}
+ .seg{display:flex;background:var(--h-surface-2);border:1px solid var(--h-border);border-radius:10px;padding:3px;gap:3px}
+ .seg button{flex:1;background:none;border:none;border-radius:7px;padding:9px 4px;color:var(--h-muted);font-weight:600;font-size:13px;line-height:1;font-family:inherit;cursor:pointer}
+ .seg button[aria-checked=true]{background:var(--h-surface);color:var(--h-ink);box-shadow:0 1px 2px rgba(0,0,0,.25),inset 0 0 0 1px var(--h-border-hi)}
+ .swatches{display:flex;gap:10px}
+ .swatches button{width:30px;height:30px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;box-shadow:inset 0 0 0 2px var(--h-surface)}
+ .swatches button[aria-checked=true]{border-color:var(--h-ink)}
+ .home-sug{font-size:13px;color:var(--h-muted);min-height:18px;line-height:1.35}
+ .home-sug b{color:var(--h-ink)}
+ .home-card{position:relative;display:grid;grid-template-columns:44px 1fr auto;align-items:center;gap:12px;width:100%;text-align:left;
+ background:var(--h-surface);color:var(--h-ink);border:1px solid var(--h-border);border-radius:16px;padding:14px 14px;cursor:pointer;
+ font:inherit;transition:transform .12s,border-color .15s,background .15s,box-shadow .15s}
+ .home-card:hover{border-color:var(--h-border-hi)}
+ .home-card:active{transform:scale(.985)}
+ .home-card .ic{width:44px;height:44px;border-radius:12px;display:grid;place-items:center;background:var(--h-surface-2);color:var(--h-accent)}
+ .home-card .ic svg{width:24px;height:24px}
+ .home-card .tt{display:block;font-size:17px;font-weight:800;line-height:1.2}
+ .home-card .ds{display:block;font-size:12.5px;color:var(--h-muted);margin-top:3px;line-height:1.3}
+ .home-card kbd{font:600 11px/1 ui-monospace,Menlo,monospace;color:var(--h-muted);border:1px solid var(--h-border);border-bottom-width:2px;border-radius:5px;padding:4px 6px}
+ .home-card .badge{position:absolute;top:-7px;right:12px;background:var(--h-accent);color:var(--h-accent-ink);font-weight:800;font-size:11px;line-height:1;font-family:inherit;border-radius:999px;padding:4px 8px}
+ .home-card .badge[hidden]{display:none}
+ .home-card.suggested{border-color:var(--h-accent);background:linear-gradient(0deg,var(--h-accent-soft),var(--h-accent-soft)),var(--h-surface);box-shadow:0 0 0 1px var(--h-accent)}
+ .home-card .home-chip{display:none;width:max-content;margin-bottom:4px;font-weight:800;font-size:10px;line-height:1;letter-spacing:.08em;text-transform:uppercase;
+ color:var(--h-accent);border:1px solid var(--h-accent);border-radius:999px;padding:3px 7px}
+ .home-card.suggested .home-chip{display:block}
+ .home-card.suggested .ic{background:var(--h-accent);color:var(--h-accent-ink)}
+ #homeScreen button:focus-visible,#homeScreen a:focus-visible{outline:2px solid var(--h-accent);outline-offset:2px}
+ .home-skip{align-self:center;margin-top:2px;background:none;border:none;color:var(--h-muted);font-weight:600;font-size:14px;line-height:1;font-family:inherit;padding:10px;cursor:pointer}
+ .home-apps{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;width:100%;margin-top:6px;padding-top:14px;border-top:1px solid var(--h-border)}
+ .home-apps-lbl{width:100%;text-align:center;color:var(--h-muted);font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-weight:700}
+ .home-apps a{color:var(--h-ink);text-decoration:none;background:var(--h-surface);border:1px solid var(--h-border);border-radius:999px;padding:8px 13px;font-size:13px}
.home-apps a:active{transform:scale(.98)}
+ .home-hint{text-align:center;font-size:11px;color:var(--h-muted);opacity:.8}
+ @media (hover:none){ .home-card kbd,.home-hint{display:none} }
+ @media (prefers-reduced-motion:no-preference){
+ #homeScreen:not([hidden]) .home-card{animation:homeIn .28s both}
+ #homeScreen .home-card[data-act=update]{animation-delay:.04s}#homeScreen .home-card[data-act=lookup]{animation-delay:.08s}#homeScreen .home-card[data-act=check]{animation-delay:.12s}
+ }
+ @keyframes homeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
#homeBtn{background:none;border:none;color:var(--ink);opacity:.5;font-size:18px;cursor:pointer;float:right}
.ed-panel{flex:0 0 auto;background:var(--card);border-top:1px solid var(--line);padding:12px 14px max(14px,env(safe-area-inset-bottom));max-height:54vh;overflow-y:auto}
.ed-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
@@ -487,15 +538,53 @@
</style>
</head>
<body>
-<!-- onload chooser: three simple pills, white on black, centered -->
-<div id="homeScreen">
+<!-- onload chooser (TK-12346): Adobe Spectrum themes + accent, smart "Suggested" action, keyboard 1–4 / Enter -->
+<div id="homeScreen" role="dialog" aria-modal="true" aria-labelledby="homeGreet" data-theme="darkest" data-accent="blue">
<div class="home-inner">
- <div class="home-title">DW Sample Station</div>
- <button class="home-pill" data-act="add">Add New SKU</button>
- <button class="home-pill" data-act="update">Update SKU</button>
- <button class="home-pill" data-act="lookup">Look Up SKU</button>
- <button class="home-pill" data-act="check">Check Sample In</button>
- <button class="home-skip" data-act="skip">skip →</button>
+ <div class="home-top">
+ <div>
+ <div class="home-title">DW Sample Station</div>
+ <div class="home-greet" id="homeGreet">Welcome</div>
+ <div class="home-date" id="homeDate"></div>
+ </div>
+ <button class="home-theme-btn" id="homeThemeBtn" aria-expanded="false" aria-controls="homePrefs"><span class="dot"></span>Theme</button>
+ </div>
+ <div class="home-prefs" id="homePrefs" hidden>
+ <div class="home-prefs-lbl" id="lblTheme">Theme</div>
+ <div class="seg" role="radiogroup" aria-labelledby="lblTheme" id="homeThemeSeg">
+ <button role="radio" data-theme="light">Light</button>
+ <button role="radio" data-theme="dark">Dark</button>
+ <button role="radio" data-theme="darkest">Darkest</button>
+ <button role="radio" data-theme="auto">Auto</button>
+ </div>
+ <div class="home-prefs-lbl" id="lblAccent">Accent</div>
+ <div class="swatches" role="radiogroup" aria-labelledby="lblAccent" id="homeAccent">
+ <button role="radio" data-accent="blue" aria-label="Blue" style="background:#2680eb"></button>
+ <button role="radio" data-accent="gold" aria-label="DW Gold" style="background:#c9a45c"></button>
+ <button role="radio" data-accent="green" aria-label="Green" style="background:#12805c"></button>
+ <button role="radio" data-accent="purple" aria-label="Purple" style="background:#7e4bf3"></button>
+ <button role="radio" data-accent="red" aria-label="Red" style="background:#d31510"></button>
+ </div>
+ </div>
+ <div class="home-sug" id="homeSug" aria-live="polite"></div>
+ <button class="home-card" data-act="add" aria-keyshortcuts="1">
+ <span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="3"/><path d="M12 8v8M8 12h8"/></svg></span><span><span class="home-chip">Suggested</span><span class="tt">Add New SKU</span><span class="ds">Photograph a new sample front + back and create it</span></span><kbd>1</kbd>
+ <span class="badge" hidden></span>
+ </button>
+ <button class="home-card" data-act="update" aria-keyshortcuts="2">
+ <span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span><span><span class="home-chip">Suggested</span><span class="tt">Update SKU</span><span class="ds">Snap the label, then refresh photos or details</span></span><kbd>2</kbd>
+ <span class="badge" hidden></span>
+ </button>
+ <button class="home-card" data-act="lookup" aria-keyshortcuts="3">
+ <span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></span><span><span class="home-chip">Suggested</span><span class="tt">Look Up SKU</span><span class="ds">Scan a sample to identify it in the catalog</span></span><kbd>3</kbd>
+ <span class="badge" hidden></span>
+ </button>
+ <button class="home-card" data-act="check" aria-keyshortcuts="4">
+ <span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5z"/><path d="m8 12 3 3 5-6"/></svg></span><span><span class="home-chip">Suggested</span><span class="tt">Check Sample In</span><span class="ds">Mark ordered samples as received</span></span><kbd>4</kbd>
+ <span class="badge" hidden></span>
+ </button>
+ <button class="home-skip" data-act="skip">Browse catalog grid →</button>
+ <div class="home-hint">Press 1–4 to choose · Enter for the suggestion</div>
<!-- Other apps (TK-12162): the 4 simplified capture concepts -->
<nav class="home-apps" aria-label="Other apps">
<div class="home-apps-lbl">Other apps</div>
@@ -2933,8 +3022,11 @@ if(!(window.SpeechRecognition||window.webkitSpeechRecognition)){
console.log('Web Speech API unavailable — mic buttons hidden (native keyboard mic still works).');
}
-// ── onload chooser: Add New SKU · Update SKU · Check Sample In ──
-function routeHome(act){ $('#homeScreen').hidden=true;
+// ── onload chooser (TK-12346): Add · Update · Look Up · Check In — themed (Adobe Spectrum) + smart suggestion ──
+const HOME_KEYS={'1':'add','2':'update','3':'lookup','4':'check'};
+function hGet(k,d){ try{ return localStorage.getItem(k)||d; }catch(e){ return d; } }
+function hSet(k,v){ try{ localStorage.setItem(k,v); }catch(e){} }
+function routeHome(act){ $('#homeScreen').hidden=true; if(act!=='skip') hSet('dwHomeLast',act);
// onload → straight to the camera; details show after the first scan
if(act==='add') openAddModal(null,{mode:'add',camera:true});
else if(act==='update') openAddModal(null,{mode:'update',camera:true});
@@ -2942,8 +3034,52 @@ function routeHome(act){ $('#homeScreen').hidden=true;
else if(act==='check'){ openFbModal(); loadIncoming(); } // show the incoming (ordered-not-received) queue first
else if(act==='skip'){ if(!TWILITEMS.length) loadTwil(); } // lazy-load the big TWIL grid only when actually viewing it
}
-document.querySelectorAll('#homeScreen .home-pill, #homeScreen .home-skip').forEach(b=>b.addEventListener('click',()=>routeHome(b.dataset.act)));
-$('#homeBtn').addEventListener('click',()=>{ $('#homeScreen').hidden=false; });
+// theme: light | dark | darkest | auto (auto follows the OS light/dark setting)
+const _homeMQ=window.matchMedia?matchMedia('(prefers-color-scheme: light)'):null;
+function applyHomeTheme(){ const hs=$('#homeScreen'), pick=hGet('dwHomeTheme','darkest'), acc=hGet('dwHomeAccent','blue');
+ hs.dataset.theme = pick==='auto' ? (_homeMQ&&_homeMQ.matches?'light':'darkest') : pick;
+ hs.dataset.accent = acc;
+ document.querySelectorAll('#homeThemeSeg [role=radio]').forEach(b=>b.setAttribute('aria-checked',String(b.dataset.theme===pick)));
+ document.querySelectorAll('#homeAccent [role=radio]').forEach(b=>b.setAttribute('aria-checked',String(b.dataset.accent===acc)));
+}
+if(_homeMQ&&_homeMQ.addEventListener) _homeMQ.addEventListener('change',()=>{ if(hGet('dwHomeTheme','darkest')==='auto') applyHomeTheme(); });
+document.querySelectorAll('#homeThemeSeg [role=radio]').forEach(b=>b.addEventListener('click',()=>{ hSet('dwHomeTheme',b.dataset.theme); applyHomeTheme(); }));
+document.querySelectorAll('#homeAccent [role=radio]').forEach(b=>b.addEventListener('click',()=>{ hSet('dwHomeAccent',b.dataset.accent); applyHomeTheme(); }));
+$('#homeThemeBtn').addEventListener('click',()=>{ const p=$('#homePrefs'), open=p.hidden; p.hidden=!open; $('#homeThemeBtn').setAttribute('aria-expanded',String(open)); });
+// suggestion: samples waiting to check in beat everything; else the last action used here; else Add New SKU
+let _homeSuggest='add';
+function markSuggested(act,why){ _homeSuggest=act;
+ document.querySelectorAll('#homeScreen .home-card').forEach(c=>c.classList.toggle('suggested',c.dataset.act===act));
+ $('#homeSug').innerHTML=why?('✨ '+why):'';
+}
+async function refreshHomeSuggestion(){
+ const h=new Date().getHours();
+ $('#homeGreet').textContent=h<12?'Good morning':h<17?'Good afternoon':'Good evening';
+ $('#homeDate').textContent=new Date().toLocaleDateString(undefined,{weekday:'long',month:'short',day:'numeric'});
+ const last=hGet('dwHomeLast','');
+ const lastName={add:'Add New SKU',update:'Update SKU',lookup:'Look Up SKU',check:'Check Sample In'}[last];
+ markSuggested(lastName?last:'add', lastName?('Picking up where you left off — <b>'+lastName+'</b>'):'Start by adding a new sample');
+ const badge=$('#homeScreen .home-card[data-act=check] .badge');
+ try{
+ const ctl=new AbortController(), t=setTimeout(()=>ctl.abort(),3000);
+ const r=await(await fetch('/api/incoming-samples',{signal:ctl.signal})).json(); clearTimeout(t);
+ const n=((r&&r.samples)||[]).length;
+ badge.hidden=!n; badge.textContent=n>99?'99+':String(n);
+ if(n) markSuggested('check','<b>'+n+' sample'+(n===1?'':'s')+'</b> ordered and waiting to be checked in');
+ }catch(e){ badge.hidden=true; } // offline / slow → keep the last-used suggestion
+ if(!$('#homeScreen').hidden && matchMedia('(hover:hover)').matches){ const c=$('#homeScreen .home-card.suggested'); if(c) c.focus({preventScroll:true}); }
+}
+function showHome(){ $('#homeScreen').hidden=false; applyHomeTheme(); refreshHomeSuggestion(); }
+document.querySelectorAll('#homeScreen .home-card, #homeScreen .home-skip').forEach(b=>b.addEventListener('click',()=>routeHome(b.dataset.act)));
+document.addEventListener('keydown',e=>{
+ if($('#homeScreen').hidden||e.metaKey||e.ctrlKey||e.altKey) return;
+ const tag=(e.target&&e.target.tagName)||''; if(/INPUT|TEXTAREA|SELECT/.test(tag)) return;
+ if(HOME_KEYS[e.key]){ e.preventDefault(); routeHome(HOME_KEYS[e.key]); }
+ else if(e.key==='Enter' && !(e.target&&e.target.closest&&e.target.closest('#homeScreen button,#homeScreen a'))){ e.preventDefault(); routeHome(_homeSuggest); }
+ else if(e.key==='Escape'){ const p=$('#homePrefs'); if(!p.hidden){ p.hidden=true; $('#homeThemeBtn').setAttribute('aria-expanded','false'); } }
+});
+$('#homeBtn').addEventListener('click',showHome);
+applyHomeTheme(); if(!$('#homeScreen').hidden) refreshHomeSuggestion();
$('#scanvideo').addEventListener('click',resumeScan); // tap the paused overlay to resume scanning
$('#scanStatus').addEventListener('click',resumeScan);
$('#scanCancel').addEventListener('click',closeLiveScan);
← 4ace5d4 Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Ph
·
back to Dw Photo Capture
·
Front screen: one-at-a-time swipe theme picker (Figma v1-v25 24bc0c3 →