← back to Dw Photo Capture

public/themes/v1-magic-camera.html

361 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v1 — Magic Camera</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
  :root{
    --charcoal:#1C1C1E;
    --gold:#C9A24B;
    --cream:#FDFBF7;
    --green:#3FA66B;
  }
  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;background:#0a0a0a;font-family:'Inter',sans-serif;}
  .stage{
    width:390px;height:780px;margin:24px auto;position:relative;
    background:var(--charcoal);border-radius:36px;overflow:hidden;
    box-shadow:0 20px 60px rgba(0,0,0,.5);border:8px solid #000;
  }
  .screen{
    position:absolute;inset:0;display:none;flex-direction:column;
    background:var(--charcoal);color:var(--cream);
  }
  .screen.active{display:flex;}
  .light{background:var(--cream);color:var(--charcoal);}
  h1,h2,h3{font-family:'Fraunces',serif;margin:0;}
  .dw-mark{
    position:absolute;top:18px;left:18px;font-family:'Fraunces',serif;
    font-weight:700;font-size:15px;letter-spacing:1px;color:var(--cream);opacity:.85;z-index:5;
  }
  .hint{
    position:absolute;top:56px;left:0;right:0;text-align:center;
    font-size:17px;color:var(--cream);opacity:.9;z-index:5;
  }
  .viewfinder{
    position:absolute;inset:0;
    background:
      repeating-linear-gradient(135deg, #232326 0 40px, #1c1c1e 40px 80px);
  }
  .shutter-wrap{
    position:absolute;bottom:48px;left:0;right:0;display:flex;justify-content:center;z-index:5;
  }
  .shutter{
    width:96px;height:96px;border-radius:50%;background:var(--gold);
    border:6px solid var(--cream);cursor:pointer;font-size:40px;
    display:flex;align-items:center;justify-content:center;
    box-shadow:0 8px 24px rgba(0,0,0,.4);
  }
  .shutter:focus-visible, button:focus-visible, .card-btn:focus-visible, .brand-tile:focus-visible{
    outline:3px solid var(--gold);outline-offset:2px;
  }
  .btn:disabled{opacity:.4;cursor:not-allowed;}
  .demo-caption{font-size:13px;opacity:.55;margin-top:-10px;}
  .looking-wrap{align-items:center;justify-content:center;gap:18px;}
  .looking-wrap .spinner{
    width:64px;height:64px;border-radius:50%;
    border:6px solid rgba(255,255,255,.15);border-top-color:var(--gold);
    animation:spin 1s linear infinite;
  }
  @keyframes spin{to{transform:rotate(360deg);}}
  .looking-wrap p{font-size:19px;}
  .content{padding:28px 24px;display:flex;flex-direction:column;gap:18px;flex:1;overflow-y:auto;}
  .swatch{
    width:100%;height:220px;border-radius:18px;margin-top:4px;
    background:
      repeating-linear-gradient(45deg,#8FAE8B 0 22px,#B9CBB2 22px 44px),
      linear-gradient(135deg,#8FAE8B,#6f8d6c);
    background-blend-mode:multiply;
  }
  .swatch.blue{background:
      repeating-linear-gradient(45deg,#7C93B0 0 22px,#B3C3D6 22px 44px),
      linear-gradient(135deg,#7C93B0,#5f7692);
    background-blend-mode:multiply;}
  .item-title{font-size:22px;font-weight:700;}
  .item-sub{font-size:15px;opacity:.75;}
  .btn{
    min-height:56px;border-radius:16px;border:none;font-family:'Inter',sans-serif;
    font-size:18px;font-weight:600;cursor:pointer;padding:0 20px;width:100%;
  }
  .btn-primary{background:var(--gold);color:#1C1C1E;}
  .btn-secondary{background:transparent;color:var(--cream);border:2px solid rgba(253,251,247,.4);}
  .btn-light-primary{background:var(--gold);color:#1C1C1E;}
  .btn-light-secondary{background:#ece7dd;color:var(--charcoal);border:2px solid #ddd4c2;}
  .btn-success{background:var(--green);color:#fff;}
  .brand-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;overflow-y:auto;padding-right:2px;}
  .brand-tile{
    background:#2a2a2d;border:2px solid #3a3a3d;border-radius:14px;
    min-height:72px;display:flex;align-items:center;justify-content:center;
    font-size:17px;font-weight:600;color:var(--cream);cursor:pointer;text-align:center;padding:8px;
  }
  .brand-tile:hover{border-color:var(--gold);}
  .brand-tile.selected{border-color:var(--gold);background:#3a331f;box-shadow:inset 0 0 0 2px var(--gold);}
  .center-flex{align-items:center;justify-content:center;text-align:center;}
  .big-emoji{font-size:64px;}
  .pick-list{display:flex;flex-direction:column;gap:14px;margin-top:8px;}
  .home-hdr{text-align:center;font-size:17px;margin-top:4px;}
  .ux-home{position:absolute;top:14px;right:14px;z-index:20;min-height:44px;min-width:44px;padding:0 14px;border-radius:12px;
    border:2px solid var(--cream);background:rgba(28,28,30,.85);color:var(--cream);font:600 15px Inter,sans-serif;cursor:pointer}
  .ux-home[hidden]{display:none}
  .ux-cancel{margin-top:18px;min-height:48px;padding:0 22px;border-radius:12px;border:2px solid var(--cream);background:transparent;color:var(--cream);font:600 16px Inter,sans-serif;cursor:pointer}
</style>
<style id="ux-baseline">/* TK-12343 UX baseline: full-bleed on real phones, visible focus everywhere */
@media (max-width:405px){ html,body{margin:0;padding:0} body{overflow-x:hidden} .stage,.phone{width:100% !important;max-width:100%;margin:0 !important;border:0 !important;border-radius:0 !important;box-shadow:none !important;height:100dvh;min-height:640px} }
button:focus-visible,a:focus-visible,[tabindex]:focus-visible,input:focus-visible{outline:3px solid #9C7A33 !important;outline-offset:2px}
</style>
</head>
<body>
<div class="stage" id="stage">
  <button class="ux-home" id="uxHome" type="button" onclick="goHome()" hidden>⌂ Home</button>

  <!-- HOME -->
  <div class="screen active" id="home">
    <div class="dw-mark">DW</div>
    <div class="hint">Point at anything and tap 📸</div>
    <div class="viewfinder"></div>
    <div class="shutter-wrap">
      <button class="shutter" id="shutterBtn" aria-label="Shoot photo">📸</button>
    </div>
  </div>

  <!-- LOOKING -->
  <div class="screen looking-wrap" id="looking">
    <div class="spinner"></div>
    <p>Looking…</p>
    <button class="ux-cancel" type="button" onclick="goHome()">Cancel</button>
  </div>

  <!-- GUESS: ADD NEW ITEM -->
  <div class="screen" id="guessAdd">
    <div class="content">
      <h2>Looks like a New Item</h2>
      <p class="demo-caption">Demo: cycles through jobs — real version would ask</p>
      <div class="swatch"></div>
      <button class="btn btn-primary" onclick="show('addBrand')">Yes, that's right</button>
      <button class="btn btn-secondary" onclick="show('pickAnother')">No, pick another</button>
    </div>
  </div>

  <!-- ADD: BRAND GRID -->
  <div class="screen" id="addBrand">
    <div class="content">
      <h3>Which brand?</h3>
      <div class="brand-grid">
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'York')" onkeydown="onBrandKey(event,this,'York')">York</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Brewster')" onkeydown="onBrandKey(event,this,'Brewster')">Brewster</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Kravet')" onkeydown="onBrandKey(event,this,'Kravet')">Kravet</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Cole &amp; Son')" onkeydown="onBrandKey(event,this,'Cole &amp; Son')">Cole &amp; Son</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Thibaut')" onkeydown="onBrandKey(event,this,'Thibaut')">Thibaut</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Schumacher')" onkeydown="onBrandKey(event,this,'Schumacher')">Schumacher</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Mulberry')" onkeydown="onBrandKey(event,this,'Mulberry')">Mulberry</div>
        <div class="brand-tile" tabindex="0" role="button" onclick="selectBrand(this,'Other / Unsure')" onkeydown="onBrandKey(event,this,'Other / Unsure')">Other / Unsure</div>
      </div>
      <button class="btn btn-primary" id="saveDraftBtn" disabled onclick="saveDraft()">Save as Draft</button>
    </div>
  </div>

  <!-- ADD: SAVED -->
  <div class="screen light center-flex" id="addSaved">
    <div class="content center-flex">
      <div class="big-emoji">🎉</div>
      <h2>Saved!</h2>
      <div class="item-sub">Added as <strong id="savedBrandName"></strong></div>
      <button class="btn btn-light-primary" onclick="goHome()">Take Another</button>
    </div>
  </div>

  <!-- GUESS: UPDATE -->
  <div class="screen" id="guessUpdate">
    <div class="content">
      <h2>Found a Match</h2>
      <p class="demo-caption">Demo: cycles through jobs — real version would ask</p>
      <div class="swatch blue"></div>
      <div class="item-title">Palm Damask — Sage</div>
      <div class="item-sub">code DW-10423</div>
      <button class="btn btn-primary" onclick="show('updateCam2')">Yes, that's right</button>
      <button class="btn btn-secondary" onclick="show('pickAnother')">Not this item</button>
    </div>
  </div>

  <!-- UPDATE: TAKE NEW PHOTO -->
  <div class="screen" id="updateCam2">
    <div class="dw-mark">DW</div>
    <div class="hint">Take the new photo</div>
    <div class="viewfinder"></div>
    <div class="shutter-wrap">
      <button class="shutter" onclick="show('updateDone')" aria-label="Shoot new photo">📸</button>
    </div>
  </div>

  <!-- UPDATE: DONE -->
  <div class="screen light center-flex" id="updateDone">
    <div class="content center-flex">
      <div class="big-emoji">✅</div>
      <h2>Updated!</h2>
      <button class="btn btn-light-primary" onclick="goHome()">Take Another</button>
    </div>
  </div>

  <!-- GUESS: FIND -->
  <div class="screen" id="guessFind">
    <div class="content">
      <h2>Best Match</h2>
      <p class="demo-caption">Demo: cycles through jobs — real version would ask</p>
      <div class="swatch"></div>
      <div class="item-title">Palm Damask — Sage</div>
      <div class="item-sub">code DW-10423</div>
      <button class="btn btn-primary" onclick="show('findDone')">Yes, that's right</button>
      <button class="btn btn-secondary" onclick="show('findFallback')">Not this item</button>
    </div>
  </div>

  <!-- FIND: FALLBACK SEARCH -->
  <div class="screen" id="findFallback">
    <div class="content">
      <h3>Search another way</h3>
      <div class="pick-list">
        <button class="btn btn-secondary" onclick="show('findResult')">📷 Scan</button>
        <button class="btn btn-secondary" onclick="show('findResult')">🎤 Voice</button>
        <button class="btn btn-secondary" onclick="show('findResult')">⌨️ Type</button>
        <button class="btn btn-secondary" onclick="show('findResult')">🗂️ Browse</button>
      </div>
    </div>
  </div>

  <!-- FIND: RESULT -->
  <div class="screen" id="findResult">
    <div class="content">
      <h2>Here it is</h2>
      <div class="swatch blue"></div>
      <div class="item-title">Palm Damask — Sage</div>
      <div class="item-sub">code DW-10423</div>
      <button class="btn btn-primary" onclick="show('findDone')">Yes, that's right</button>
      <button class="btn btn-secondary" onclick="show('findFallback')">Not this item</button>
    </div>
  </div>

  <!-- FIND: DONE -->
  <div class="screen light center-flex" id="findDone">
    <div class="content center-flex">
      <div class="big-emoji">🔍</div>
      <h2>Found it!</h2>
      <button class="btn btn-light-primary" onclick="goHome()">Take Another</button>
    </div>
  </div>

  <!-- GUESS: SAMPLE -->
  <div class="screen" id="guessSample">
    <div class="content">
      <h2>Sample Matched</h2>
      <p class="demo-caption">Demo: cycles through jobs — real version would ask</p>
      <div class="swatch"></div>
      <div class="item-title">Palm Damask — Sage</div>
      <div class="item-sub">code DW-10423</div>
      <button class="btn btn-primary" onclick="show('samplePrinting')">Mark It Received</button>
      <button class="btn btn-secondary" onclick="show('pickAnother')">Not this item</button>
    </div>
  </div>

  <!-- SAMPLE: PRINTING -->
  <div class="screen looking-wrap" id="samplePrinting">
    <div class="spinner"></div>
    <p>Printing your sticker…</p>
    <button class="ux-cancel" type="button" onclick="goHome()">Cancel</button>
  </div>

  <!-- SAMPLE: DONE -->
  <div class="screen light center-flex" id="sampleDone">
    <div class="content center-flex">
      <div class="big-emoji">✅</div>
      <h2>Done!</h2>
      <button class="btn btn-light-primary" onclick="goHome()">Take Another</button>
    </div>
  </div>

  <!-- PICK ANOTHER (No, pick another fallback chooser) -->
  <div class="screen" id="pickAnother">
    <div class="content">
      <h3>Which job is this?</h3>
      <div class="pick-list">
        <button class="btn btn-secondary" onclick="show('addBrand')">Add New Item</button>
        <button class="btn btn-secondary" onclick="show('updateCam2')">Update an Item</button>
        <button class="btn btn-secondary" onclick="show('findFallback')">Find an Item</button>
        <button class="btn btn-secondary" onclick="show('guessSample')">A Sample Came In</button>
      </div>
    </div>
  </div>

</div>

<script>
  let jobIndex = 0;
  const jobGuesses = ['guessAdd','guessUpdate','guessFind','guessSample'];

  let selectedBrand = null;

  function show(id){
    document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
    document.getElementById(id).classList.add('active');
    document.getElementById('uxHome').hidden = (id === 'home');
    if(id === 'addBrand'){
      selectedBrand = null;
      document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
      document.getElementById('saveDraftBtn').disabled = true;
    }
  }

  function selectBrand(el, name){
    document.querySelectorAll('#addBrand .brand-tile').forEach(t=>t.classList.remove('selected'));
    el.classList.add('selected');
    selectedBrand = name;
    document.getElementById('saveDraftBtn').disabled = false;
  }

  function onBrandKey(evt, el, name){
    if(evt.key === 'Enter' || evt.key === ' '){
      evt.preventDefault();
      selectBrand(el, name);
    }
  }

  function saveDraft(){
    if(!selectedBrand) return;
    document.getElementById('savedBrandName').textContent = selectedBrand;
    show('addSaved');
  }

  let pendingTimer = null;
  function goHome(){
    if (pendingTimer) { clearTimeout(pendingTimer); pendingTimer = null; }
    show('home');
  }

  document.getElementById('shutterBtn').addEventListener('click', function(){
    show('looking');
    pendingTimer = setTimeout(function(){
      pendingTimer = null;
      const target = jobGuesses[jobIndex % jobGuesses.length];
      jobIndex++;
      show(target);
    }, 900);
  });

  // sample "Mark It Received" leads through printing -> done automatically
  document.addEventListener('DOMContentLoaded', function(){
    const printingScreen = document.getElementById('samplePrinting');
  });
  // auto-advance printing screen to done
  const origShow = show;
  show = function(id){
    origShow(id);
    if(id === 'samplePrinting'){
      pendingTimer = setTimeout(function(){ pendingTimer = null; origShow('sampleDone'); document.getElementById('uxHome').hidden = false; }, 1100);
    }
  };
</script>
</body>
</html>