← back to Dw Photo Capture
public/kid-simple/v10-todays-inbox.html
397 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>v10 — Today's Inbox</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,500;6..72,600;6..72,700&family=Manrope:wght@500;600;700;800&display=swap" rel="stylesheet">
<style>
:root{
--bg:#F3EEE4; --card:#FFFFFF; --ink:#24211C; --muted:#8A8171;
--brass:#A9772F; --brass-ink:#3A2A0E;
--terracotta:#B85C38; --terracotta-bg:#F3E1D6;
--teal:#4F7A73; --teal-bg:#DEEAE7;
--plum:#6B4E71; --plum-bg:#E9E0EB;
--green:#4C8C6B; --green-bg:#DCEEE3;
--line:#E7DFCF;
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;background:#ccc;font-family:'Manrope',sans-serif;color:var(--ink);}
body{display:flex; align-items:flex-start; justify-content:center; min-height:100vh; padding:20px 0;}
.phone{
width:390px; min-height:780px; background:var(--bg); border-radius:36px; overflow:hidden;
box-shadow:0 24px 60px rgba(0,0,0,.28); display:flex; flex-direction:column; position:relative;
}
.screen{ flex:1; display:flex; flex-direction:column; padding:26px 22px 30px; overflow-y:auto; }
button{ font-family:'Manrope',sans-serif; cursor:pointer; }
/* ---- Home / Inbox ---- */
.inbox-header{ margin-bottom:18px; }
.inbox-eyebrow{ font-size:14px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); margin:0 0 2px; }
.inbox-title{ font-family:'Newsreader',serif; font-weight:600; font-size:34px; line-height:1.1; margin:0; color:var(--ink); }
.inbox-sub{ font-size:15px; color:var(--muted); margin:8px 0 0; }
.rowlist{ display:flex; flex-direction:column; gap:12px; margin-top:20px; }
.row{
display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
background:var(--card); border:1px solid var(--line); border-radius:20px; padding:12px 16px;
text-align:left; box-shadow:0 2px 6px rgba(36,33,28,.05);
}
.row:focus-visible, .bigbtn:focus-visible, .linktext:focus-visible, .fab:focus-visible, .brandrow:focus-visible{
outline:3px solid #2B6CB0; outline-offset:2px;
}
.badge{
flex:0 0 auto; width:52px; height:52px; border-radius:16px; display:flex; align-items:center;
justify-content:center; font-size:24px;
}
.badge.terracotta{ background:var(--terracotta-bg); }
.badge.teal{ background:var(--teal-bg); }
.badge.plum{ background:var(--plum-bg); }
.row-text{ flex:1; min-width:0; }
.row-title{ font-size:17px; font-weight:800; margin:0; color:var(--ink); }
.row-sub{ font-size:14px; color:var(--muted); margin:2px 0 0; }
.chev{ font-size:20px; color:var(--muted); flex:0 0 auto; }
.caughtup{
display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
background:var(--green-bg); border:1px solid transparent; border-radius:20px; padding:12px 16px;
}
.caughtup .badge{ background:#fff; }
.caughtup .row-title{ color:#2C5C42; }
.caughtup .row-sub{ color:#4C8C6B; }
.fab{
position:absolute; right:20px; bottom:26px; z-index:20;
width:68px; height:68px; border-radius:50%; background:var(--brass); border:4px solid #fff;
color:#fff; font-size:26px; display:flex; align-items:center; justify-content:center;
box-shadow:0 10px 22px rgba(169,119,47,.45);
}
.fab-label{
position:absolute; right:20px; bottom:98px; z-index:20; background:var(--ink); color:#fff;
font-size:12px; font-weight:700; padding:6px 10px; border-radius:10px; opacity:.88;
}
/* ---- Shared question / answer patterns ---- */
.topbar{ display:flex; align-items:center; gap:10px; margin-bottom:10px; min-height:56px; }
.backbtn{
background:none; border:none; color:var(--muted); font-size:15px; font-weight:700;
min-height:56px; padding:6px 4px; display:flex; align-items:center; gap:4px;
}
.question{
font-family:'Newsreader',serif; font-weight:600; font-size:28px; line-height:1.2;
margin:6px 0 20px; color:var(--ink);
}
.answers{ flex:1; display:flex; flex-direction:column; gap:14px; }
.bigbtn{
width:100%; min-height:64px; border-radius:18px; font-size:18px; font-weight:800;
background:#fff; border:2px solid var(--line); color:var(--ink); padding:12px 18px;
}
.bigbtn-primary{ background:var(--brass); border:2px solid var(--brass); color:#fff; }
.bigbtn-secondary{ background:#fff; border:2px solid var(--muted); color:var(--muted); }
.linktext{
background:none; border:none; color:var(--muted); font-size:16px; text-decoration:underline;
text-align:center; min-height:56px; width:100%; font-weight:700;
}
/* ---- Queue lists (samples / photos) ---- */
.queuelist{ display:flex; flex-direction:column; gap:12px; }
.queuecard{
display:flex; align-items:center; gap:14px; width:100%; min-height:76px;
background:#fff; border:1px solid var(--line); border-radius:20px; padding:12px 14px; text-align:left;
}
.swatch{ flex:0 0 auto; width:52px; height:52px; border-radius:14px; }
.sw1{background:repeating-linear-gradient(45deg,#8FAE8B 0 10px,#6f8f6b 10px 20px);}
.sw2{background:repeating-linear-gradient(-45deg,#B85C38 0 10px,#96482a 10px 20px);}
.sw3{background:radial-gradient(circle at 30% 30%, #A9772F 0 8px, #E9D9BD 9px 20px);}
.sw4{background:repeating-linear-gradient(90deg,#6B4E71 0 9px,#54394f 9px 18px);}
.sw5{background:radial-gradient(circle at 60% 40%, #4F7A73 0 9px, #DCEEE3 10px 22px);}
.qc-text{ flex:1; min-width:0; }
.qc-title{ font-size:16px; font-weight:800; margin:0; }
.qc-sub{ font-size:13px; color:var(--muted); margin:2px 0 0; }
.itemname{ font-size:21px; font-weight:800; margin:14px 0 0; text-align:center; }
.itemmeta{ font-size:15px; color:var(--muted); margin:4px 0 0; text-align:center; }
.swatch.big{ width:100%; height:170px; border-radius:20px; margin:0 auto; }
/* ---- Camera ---- */
.camwrap{ flex:1; display:flex; flex-direction:column; padding:0; margin:-26px -22px -30px; }
.camview{
flex:1; background:#1c1c1e; position:relative; display:flex; align-items:center; justify-content:center;
color:#fff; min-height:520px;
}
.camview .hint{
position:absolute; top:44px; left:20px; right:20px; text-align:center;
font-family:'Newsreader',serif; font-size:25px; font-weight:600; color:#fdfbf7;
}
.camview .status{ font-size:17px; font-weight:700; color:#e9dfca; }
.shutter{
position:absolute; bottom:34px; left:50%; transform:translateX(-50%);
width:88px; height:88px; border-radius:50%; background:var(--brass); border:6px solid #fff;
font-size:32px; display:flex; align-items:center; justify-content:center;
}
.camback{
position:absolute; top:16px; left:16px; z-index:5; min-width:56px; min-height:56px;
background:rgba(255,255,255,.16); border:none; border-radius:12px; color:#fff; font-size:14px; font-weight:700;
}
.center{ display:flex; flex-direction:column; align-items:center; justify-content:center; flex:1; gap:10px; }
/* ---- Brand list ---- */
.brandlist{ display:flex; flex-direction:column; gap:12px; overflow-y:auto; }
.brandrow{
width:100%; min-height:60px; border-radius:16px; background:#fff; border:2px solid var(--line);
font-size:17px; font-weight:700; color:var(--ink); padding:10px 16px; text-align:left;
}
</style>
</head>
<body>
<div class="phone">
<div class="screen" id="screen" role="main"></div>
</div>
<script>
const BRANDS = ['York Wallcoverings','Brewster Home','Kravet','Cole & Son','Thibaut','Ronald Redding'];
let samplesWaiting = [
{name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw4'},
{name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
{name:'Harbor Stripe', color:'Rust', code:'DW-71190', sw:'sw2'},
];
let photosNeeded = [
{name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
{name:'Meadow Grid', color:'Moss', code:'DW-33982', sw:'sw5'},
];
const FIND_ITEMS = [
{name:'Trellis Weave', color:'Indigo', code:'DW-88214', sw:'sw4'},
{name:'Palm Damask', color:'Sage', code:'DW-10423', sw:'sw1'},
{name:'Linen Bloom', color:'Blush', code:'DW-55071', sw:'sw3'},
];
const state = { screen:'home', brand:null, newItemSw:'sw1', sampleIdx:0, photoIdx:0, findIdx:0, activeItem:null };
function go(screen){ state.screen = screen; render(); }
function cameraScreen(hint, onShoot, backTo){
return `<div class="camwrap"><div class="camview">
${backTo ? `<button class="camback" onclick="go('${backTo}')">‹ Inbox</button>` : ''}
<div class="hint">${hint}</div>
<div class="status" id="camStatus">Tap the shutter</div>
<button class="shutter" aria-label="Take photo" onclick="${onShoot}">📸</button>
</div></div>`;
}
function shoot(cb){
const st = document.getElementById('camStatus');
const btn = document.querySelector('.shutter');
if(btn) btn.disabled = true;
if(st) st.textContent = 'Snapping…';
setTimeout(()=>{ cb(); }, 650);
}
function render(){
const s = document.getElementById('screen');
let html = '';
// ---------------- HOME ----------------
if(state.screen==='home'){
const today = new Date();
const dateStr = today.toLocaleDateString(undefined,{weekday:'long', month:'long', day:'numeric'});
html += `<div class="inbox-header">
<p class="inbox-eyebrow">DW · Today's Inbox</p>
<h1 class="inbox-title">${dateStr}</h1>
<p class="inbox-sub">Here's what's waiting on you.</p>
</div>
<div class="rowlist">`;
if(samplesWaiting.length){
html += `<button class="row" onclick="go('sample-queue')">
<div class="badge terracotta">📦</div>
<div class="row-text">
<p class="row-title">${samplesWaiting.length} sample${samplesWaiting.length>1?'s':''} came in</p>
<p class="row-sub">Tap to check ${samplesWaiting.length>1?'them':'it'} in</p>
</div>
<div class="chev">›</div>
</button>`;
}
if(photosNeeded.length){
html += `<button class="row" onclick="go('update-queue')">
<div class="badge teal">🔄</div>
<div class="row-text">
<p class="row-title">${photosNeeded.length} item${photosNeeded.length>1?'s':''} need${photosNeeded.length>1?'':'s'} new photos</p>
<p class="row-sub">Tap to update ${photosNeeded.length>1?'them':'it'}</p>
</div>
<div class="chev">›</div>
</button>`;
}
if(!samplesWaiting.length && !photosNeeded.length){
html += `<div class="caughtup">
<div class="badge">🎉</div>
<div class="row-text">
<p class="row-title">All caught up!</p>
<p class="row-sub">Nothing waiting right now</p>
</div>
</div>`;
}
html += `<button class="row" onclick="state.findIdx=0; go('find-method')">
<div class="badge plum">🔍</div>
<div class="row-text">
<p class="row-title">Find an item</p>
<p class="row-sub">Scan, talk, or type</p>
</div>
<div class="chev">›</div>
</button>`;
html += `</div>`;
html += `<div class="fab-label">Add new</div>
<button class="fab" aria-label="Add a new item" onclick="go('new-cam')">📸</button>`;
}
// ---------------- ADD NEW ITEM (via FAB) ----------------
else if(state.screen==='new-cam'){
html += cameraScreen('Take a photo of it.', "shoot(()=>go('new-brand'))", 'home');
}
else if(state.screen==='new-brand'){
html += `<h1 class="question">Which brand is it?</h1><div class="brandlist">`;
BRANDS.forEach(b=>{ html += `<button class="brandrow" onclick="state.brand='${b}'; go('new-save')">${b}</button>`; });
html += `</div>`;
}
else if(state.screen==='new-save'){
html += `<h1 class="question">Save it?</h1>
<div class="swatch big ${state.newItemSw}"></div>
<p class="itemmeta">${state.brand}</p>
<div class="answers" style="margin-top:20px;">
<button class="bigbtn bigbtn-primary" onclick="go('new-done')">Save as Draft</button>
<button class="linktext" onclick="go('new-cam')">Retake Photo</button>
</div>`;
}
else if(state.screen==='new-done'){
html += `<div class="center"><h1 class="question">Saved! 🎉</h1></div>
<div class="answers">
<button class="bigbtn bigbtn-primary" onclick="go('new-cam')">Add Another</button>
<button class="linktext" onclick="go('home')">Back to Inbox</button>
</div>`;
}
// ---------------- SAMPLE QUEUE (row 1) ----------------
else if(state.screen==='sample-queue'){
html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
<h1 class="question">Samples waiting (${samplesWaiting.length})</h1>
<div class="queuelist">`;
samplesWaiting.forEach((it,i)=>{
html += `<button class="queuecard" onclick="state.sampleIdx=${i}; go('sample-confirm')">
<div class="swatch ${it.sw}"></div>
<div class="qc-text"><p class="qc-title">${it.name} — ${it.color}</p><p class="qc-sub">code ${it.code}</p></div>
<div class="chev">›</div>
</button>`;
});
html += `</div>`;
}
else if(state.screen==='sample-confirm'){
const it = samplesWaiting[state.sampleIdx];
html += `<div class="topbar"><button class="backbtn" onclick="go('sample-queue')">‹ Back</button></div>
<h1 class="question">Mark it received?</h1>
<div class="swatch big ${it.sw}"></div>
<p class="itemname">${it.name} — ${it.color}</p>
<p class="itemmeta">code ${it.code}</p>
<div class="answers" style="margin-top:20px;">
<button class="bigbtn bigbtn-primary" onclick="go('sample-printing')">Yes, Mark Received</button>
</div>`;
}
else if(state.screen==='sample-printing'){
html += `<div class="center"><h1 class="question">Printing your sticker…</h1><p class="itemmeta">🖨️ One sec…</p></div>`;
setTimeout(()=>{ if(state.screen==='sample-printing'){
samplesWaiting.splice(state.sampleIdx,1);
if(state.sampleIdx>=samplesWaiting.length) state.sampleIdx = 0;
go('sample-done');
} }, 1000);
}
else if(state.screen==='sample-done'){
html += `<div class="center"><h1 class="question">Received! ✅</h1></div>
<div class="answers">
${samplesWaiting.length ? `<button class="bigbtn bigbtn-primary" onclick="go('sample-queue')">Next Sample</button>` : ''}
<button class="linktext" onclick="go('home')">Back to Inbox</button>
</div>`;
}
// ---------------- UPDATE QUEUE (row 2) ----------------
else if(state.screen==='update-queue'){
html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
<h1 class="question">Items needing photos (${photosNeeded.length})</h1>
<div class="queuelist">`;
photosNeeded.forEach((it,i)=>{
html += `<button class="queuecard" onclick="state.photoIdx=${i}; go('update-cam')">
<div class="swatch ${it.sw}"></div>
<div class="qc-text"><p class="qc-title">${it.name} — ${it.color}</p><p class="qc-sub">code ${it.code}</p></div>
<div class="chev">›</div>
</button>`;
});
html += `</div>`;
}
else if(state.screen==='update-cam'){
const it = photosNeeded[state.photoIdx];
html += cameraScreen(`Take a new photo of ${it.name}.`, "shoot(()=>go('update-done'))", 'update-queue');
}
else if(state.screen==='update-done'){
html += `<div class="center"><h1 class="question">Updated! ✅</h1></div>`;
photosNeeded.splice(state.photoIdx,1);
if(state.photoIdx>=photosNeeded.length) state.photoIdx = 0;
html += `<div class="answers">
${photosNeeded.length ? `<button class="bigbtn bigbtn-primary" onclick="go('update-queue')">Next Item</button>` : ''}
<button class="linktext" onclick="go('home')">Back to Inbox</button>
</div>`;
}
// ---------------- FIND AN ITEM (row 3) ----------------
else if(state.screen==='find-method'){
html += `<div class="topbar"><button class="backbtn" onclick="go('home')">‹ Inbox</button></div>
<h1 class="question">How do you want to find it?</h1>
<div class="answers">
<button class="bigbtn" onclick="go('find-result')">📷 Scan</button>
<button class="bigbtn" onclick="go('find-result')">🎤 Talk</button>
<button class="bigbtn" onclick="go('find-result')">⌨️ Type</button>
</div>`;
}
else if(state.screen==='find-result'){
const it = FIND_ITEMS[state.findIdx];
html += `<div class="topbar"><button class="backbtn" onclick="go('find-method')">‹ Back</button></div>
<h1 class="question">Which one is it?</h1>
<div class="swatch big ${it.sw}"></div>
<p class="itemname">${it.name} — ${it.color}</p>
<p class="itemmeta">code ${it.code}</p>
<div class="answers" style="margin-top:20px;">
<button class="bigbtn bigbtn-primary" onclick="pickResult()">Yes, This One</button>
<button class="bigbtn bigbtn-secondary" onclick="nextResult()">Next Result</button>
</div>`;
}
else if(state.screen==='find-detail'){
html += `<div class="center">
<h1 class="question" style="font-size:24px; margin-bottom:12px;">${state.activeItem.name}</h1>
<div class="swatch big ${state.activeItem.sw}" style="max-width:240px;"></div>
<p class="itemmeta">${state.activeItem.color} · code ${state.activeItem.code}</p>
</div>
<div class="answers">
<button class="bigbtn bigbtn-primary" onclick="go('update-cam-fromfind')">Update This</button>
<button class="bigbtn bigbtn-secondary" onclick="state.findIdx=0; go('find-method')">Search Again</button>
<button class="linktext" onclick="go('home')">Back to Inbox</button>
</div>`;
}
else if(state.screen==='update-cam-fromfind'){
html += cameraScreen(`Take the new photo of ${state.activeItem.name}.`, "shoot(()=>go('find-updated'))", 'find-detail');
}
else if(state.screen==='find-updated'){
html += `<div class="center"><h1 class="question">Updated! ✅</h1></div>
<button class="bigbtn bigbtn-primary" onclick="go('home')">Back to Inbox</button>`;
}
s.innerHTML = html;
}
function pickResult(){ state.activeItem = FIND_ITEMS[state.findIdx]; go('find-detail'); }
function nextResult(){
if(state.findIdx < FIND_ITEMS.length-1){ state.findIdx++; go('find-result'); }
else { state.findIdx = 0; go('find-result'); }
}
render();
</script>
</body>
</html>