Six self-contained HTML documents, one per user journey, each combining mobile/desktop previews with machine-readable implementation guides: - j1-add-recipe.html (B1, B3) - j2-plan-the-week.html (C1, C2, C3) - j3-cook-tonight.html (B2, B4) - j4-adapt-on-the-fly.html (swap trigger, C2 swap) - j5-shopping-list.html (D1) - j6-household-setup.html (A1, A2, A3/D3, A4) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
395 lines
40 KiB
HTML
395 lines
40 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8"/>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||
<title>J1 — Add a Recipe</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet"/>
|
||
<style>
|
||
:root{--color-page:#FAFAF7;--color-surface:#F5F4EE;--color-subtle:#EDECEA;--color-border:#D8D7D0;--color-text-muted:#6B6A63;--color-text:#1C1C18;--green-tint:#E8F5EA;--green-light:#AEDCB0;--green:#3D8C4A;--green-dark:#2E6E39;--green-deeper:#1E4A26;--yellow-tint:#FDF6D8;--yellow-light:#F9E08A;--yellow:#F2C12E;--yellow-dark:#C49610;--yellow-text:#8A6800;--blue-tint:#E6F1FB;--blue-light:#A4CFF4;--blue:#2D7DD2;--blue-dark:#185FA5;--purple-tint:#EEEDFE;--purple:#534AB7;--purple-dark:#3C3489;--orange-tint:#FEF0E6;--orange:#E8862A;--orange-dark:#B46820;--color-error:#DC4C3E;--font-display:'Fraunces',Georgia,serif;--font-sans:'DM Sans',system-ui,sans-serif;--font-mono:'DM Mono',monospace;--radius-sm:4px;--radius-md:6px;--radius-lg:10px;--radius-xl:16px;--shadow-card:0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);--shadow-raised:0 4px 12px rgba(28,28,24,.08),0 2px 4px rgba(28,28,24,.04);--shadow-overlay:0 8px 32px rgba(28,28,24,.12),0 2px 8px rgba(28,28,24,.06);}
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
|
||
body{font-family:var(--font-sans);background:#E8E7E2;color:var(--color-text);font-size:14px;line-height:1.6;}
|
||
.doc{max-width:1200px;margin:0 auto;padding:48px 40px 120px;}
|
||
|
||
/* Header */
|
||
.doc-header{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:28px;border-bottom:1px solid var(--color-border);margin-bottom:48px;background:var(--color-page);margin:-48px -40px 48px;padding:48px 40px 28px;border-radius:var(--radius-xl) var(--radius-xl) 0 0;}
|
||
.doc-header h1{font-family:var(--font-display);font-size:28px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
|
||
.doc-header p{font-size:13px;color:var(--color-text-muted);}
|
||
.doc-meta{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);text-align:right;line-height:1.9;}
|
||
.pill{display:inline-block;padding:2px 8px;border-radius:var(--radius-sm);font-size:10px;font-weight:500;letter-spacing:.05em;background:var(--green-tint);color:var(--green-dark);}
|
||
|
||
/* Sections */
|
||
.section{margin-bottom:64px;}
|
||
.section-title{font-size:10px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-muted);padding-bottom:10px;border-bottom:1px solid var(--color-border);margin-bottom:24px;}
|
||
.prose{font-size:13px;color:var(--color-text-muted);line-height:1.65;max-width:720px;margin-bottom:20px;}
|
||
|
||
/* Journey headers */
|
||
.jh{padding:20px 24px;border-radius:var(--radius-xl);margin-bottom:40px;display:flex;align-items:center;gap:16px;}
|
||
.jh .jn{font-family:var(--font-display);font-size:48px;font-weight:300;line-height:1;opacity:.5;}
|
||
.jh h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
|
||
.jh p{font-size:13px;line-height:1.5;}.jh .fl{font-family:var(--font-mono);font-size:11px;margin-top:6px;opacity:.7;}
|
||
.jh-p{background:var(--purple-tint);border:1px solid #CECBF6;}.jh-p .jn{color:var(--purple);}.jh-p p,.jh-p .fl{color:var(--purple-dark);}
|
||
.jh-g{background:var(--green-tint);border:1px solid var(--green-light);}.jh-g .jn{color:var(--green);}.jh-g p,.jh-g .fl{color:var(--green-dark);}
|
||
.jh-y{background:var(--yellow-tint);border:1px solid var(--yellow-light);}.jh-y .jn{color:var(--yellow-dark);}.jh-y p,.jh-y .fl{color:var(--yellow-text);}
|
||
.jh-o{background:var(--orange-tint);border:1px solid #FBCDA4;}.jh-o .jn{color:var(--orange);}.jh-o p,.jh-o .fl{color:var(--orange-dark);}
|
||
.jh-b{background:var(--blue-tint);border:1px solid var(--blue-light);}.jh-b .jn{color:var(--blue);}.jh-b p,.jh-b .fl{color:var(--blue-dark);}
|
||
|
||
/* Screen block */
|
||
.scr{margin-bottom:56px;}
|
||
.scr-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
|
||
.scr-head h3{font-family:var(--font-display);font-size:20px;font-weight:500;letter-spacing:-.02em;}
|
||
.scr-id{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);padding:2px 8px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-page);}
|
||
.scr-desc{font-size:12px;color:var(--color-text-muted);line-height:1.6;max-width:720px;margin-bottom:6px;}
|
||
.scr-var{font-size:11px;color:var(--color-text-muted);margin-bottom:20px;}.scr-var strong{color:var(--color-text);}
|
||
|
||
/* Preview container */
|
||
.previews{display:flex;gap:32px;flex-wrap:wrap;justify-content:center;align-items:flex-start;margin-bottom:20px;}
|
||
.prev-col{display:flex;flex-direction:column;align-items:center;gap:10px;}
|
||
.bp-lbl{font-family:var(--font-mono);font-size:10px;color:var(--color-text-muted);}
|
||
|
||
/* Phone frame - 320px */
|
||
.phone{width:320px;flex-shrink:0;background:var(--color-page);border-radius:36px;overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.07);display:flex;flex-direction:column;border:6px solid #1C1C18;}
|
||
.pst{padding:10px 20px 0;display:flex;justify-content:space-between;align-items:center;font-size:12px;background:var(--color-page);}.pst b{font-weight:600;}.pst span{font-size:10px;}
|
||
.pb{flex:1;overflow-y:auto;display:flex;flex-direction:column;}
|
||
|
||
/* Desktop frame - 1040px */
|
||
.desk{width:100%;max-width:1040px;background:var(--color-page);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.06);display:flex;min-height:520px;}
|
||
|
||
/* Shared nav components */
|
||
.mtb{padding:10px 16px;background:var(--color-page);border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;}
|
||
.mtb-t{font-family:var(--font-display);font-size:20px;font-weight:500;letter-spacing:-.02em;}
|
||
.mi{width:32px;height:32px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-surface);display:flex;align-items:center;justify-content:center;font-size:13px;color:var(--color-text-muted);flex-shrink:0;}.mi.gn{background:var(--green);border-color:var(--green);color:#fff;}
|
||
.mbt{border-top:1px solid var(--color-border);background:var(--color-surface);padding:8px 16px 28px;display:flex;justify-content:space-around;}
|
||
.mt-i{display:flex;flex-direction:column;align-items:center;gap:2px;}.mt-ic{width:20px;height:20px;border-radius:4px;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:11px;}.mt-i.a .mt-ic{background:var(--green-tint);}.mt-l{font-size:9px;font-weight:500;color:var(--color-text-muted);}.mt-i.a .mt-l{color:var(--green-dark);}
|
||
|
||
/* Desktop sidebar - 224px per nav-spec */
|
||
.dsb{width:224px;flex-shrink:0;background:var(--color-surface);border-right:1px solid var(--color-border);display:flex;flex-direction:column;}
|
||
.dsb-logo{padding:20px 16px 16px;border-bottom:1px solid var(--color-border);}
|
||
.dsb-lm{display:flex;align-items:center;gap:8px;margin-bottom:2px;}.dsb-ic{width:24px;height:24px;border-radius:5px;background:var(--green);display:flex;align-items:center;justify-content:center;font-size:12px;}.dsb-nm{font-family:var(--font-display);font-size:16px;font-weight:500;letter-spacing:-.02em;}.dsb-sub{font-size:10px;color:var(--color-text-muted);padding-left:32px;}
|
||
.dsb-nav{padding:12px 10px;flex:1;}.dsb-nl{font-size:8px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--color-text-muted);padding:0 8px;margin-bottom:4px;}.dsb-ni{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:var(--radius-md);font-size:13px;color:var(--color-text-muted);margin-bottom:2px;cursor:default;}.dsb-ni.a{background:var(--green-tint);color:var(--green-dark);font-weight:500;}.dsb-nc{font-size:13px;width:18px;text-align:center;}
|
||
.dm{flex:1;display:flex;flex-direction:column;min-width:0;}
|
||
.dtb{padding:12px 24px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;flex-shrink:0;}
|
||
.dtb-t{font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;}
|
||
.dtb-r{display:flex;align-items:center;gap:8px;}
|
||
.dab{font-family:var(--font-sans);font-size:13px;font-weight:500;padding:7px 16px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;}
|
||
.dab-b{background:var(--blue);}
|
||
|
||
/* Shared form */
|
||
.fi{width:100%;font-family:var(--font-sans);font-size:14px;padding:10px 12px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-page);color:var(--color-text);outline:none;}
|
||
.fl{font-size:12px;font-weight:500;color:var(--color-text);margin-bottom:6px;display:block;}
|
||
.fg{margin-bottom:16px;}
|
||
.bp{font-family:var(--font-sans);font-size:14px;font-weight:500;padding:12px 24px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;cursor:pointer;width:100%;}
|
||
.bg{font-family:var(--font-sans);font-size:13px;font-weight:500;padding:10px 20px;border-radius:var(--radius-md);background:var(--color-subtle);color:var(--color-text-muted);border:1px solid var(--color-border);cursor:pointer;}
|
||
|
||
/* Tags */
|
||
.tc{display:inline-flex;font-size:12px;font-weight:500;padding:6px 12px;border-radius:20px;border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text-muted);cursor:pointer;margin:0 4px 4px 0;user-select:none;}.tc.s{background:var(--green-tint);color:var(--green-dark);border-color:var(--green-light);}
|
||
.badge{font-size:9px;font-weight:500;padding:2px 6px;border-radius:3px;display:inline-block;}.badge-g{background:var(--green-tint);color:var(--green-dark);}.badge-y{background:var(--yellow-tint);color:var(--yellow-text);}.badge-m{background:var(--color-subtle);color:var(--color-text-muted);}
|
||
|
||
/* Ingredient rows */
|
||
.ir{display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--color-subtle);}.ir:last-child{border-bottom:none;}.ir-q{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted);width:55px;flex-shrink:0;text-align:right;}.ir-n{font-size:13px;color:var(--color-text);flex:1;}.ir-x{font-size:14px;color:var(--color-border);cursor:pointer;width:20px;text-align:center;}
|
||
|
||
/* Checklist */
|
||
.ck{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--color-subtle);cursor:pointer;}.ck:last-child{border-bottom:none;}.ck-b{width:22px;height:22px;border-radius:4px;border:2px solid var(--color-border);flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;}.ck.d .ck-b{background:var(--green);border-color:var(--green);color:#fff;}.ck-c{flex:1;}.ck-n{font-size:14px;color:var(--color-text);}.ck.d .ck-n{text-decoration:line-through;color:var(--color-text-muted);}.ck-s{font-size:10px;color:var(--color-text-muted);}.ck-q{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted);flex-shrink:0;}
|
||
|
||
/* Suggestion cards */
|
||
.sg{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:12px;margin-bottom:8px;display:flex;align-items:center;gap:10px;}.sg-r{font-family:var(--font-display);font-size:16px;font-weight:300;color:var(--color-text-muted);width:20px;text-align:center;flex-shrink:0;}.sg-b{flex:1;}.sg-n{font-family:var(--font-display);font-size:13px;font-weight:400;color:var(--color-text);margin-bottom:2px;}.sg-i{font-size:10px;color:var(--color-text-muted);}.sg-w{font-size:9px;color:var(--green-dark);background:var(--green-tint);padding:2px 6px;border-radius:3px;display:inline-block;margin-top:3px;}.sg-p{font-size:11px;font-weight:500;color:var(--green);flex-shrink:0;}
|
||
|
||
/* Eyebrow labels */
|
||
.eye{font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);}
|
||
|
||
/* Agent table */
|
||
.agent{background:var(--color-text);color:#E8E8E2;padding:24px;border-radius:var(--radius-lg);margin-top:20px;}
|
||
.agent h4{font-size:9px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#5A5A55;margin-bottom:12px;}
|
||
.agent pre{font-family:var(--font-mono);font-size:10px;color:#444440;margin-bottom:16px;line-height:1.8;white-space:pre-wrap;}
|
||
.at{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:10px;}
|
||
.at thead tr{border-bottom:1px solid #2A2A26;}.at th{text-align:left;padding:6px 10px;font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#5A5A55;font-family:var(--font-sans);}.at td{padding:5px 10px;border-bottom:1px solid #1E1E1A;vertical-align:top;line-height:1.5;}.at tr:last-child td{border-bottom:none;}.at td:first-child{color:#7A7A72;}.at td:nth-child(2){color:#E8E8E2;font-weight:500;}.at td:nth-child(3){color:#5A5A55;}.at .grp td{padding-top:14px;font-family:var(--font-sans);font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#3A3A36;}
|
||
|
||
/* LLM instruction box */
|
||
.llm{background:var(--color-page);border:2px solid var(--green);border-radius:var(--radius-xl);padding:32px 40px;margin-top:64px;}
|
||
.llm h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:8px;color:var(--green-dark);}
|
||
.llm h3{font-size:14px;font-weight:600;margin:20px 0 8px;color:var(--color-text);}
|
||
.llm p,.llm li{font-size:13px;color:var(--color-text-muted);line-height:1.65;}
|
||
.llm ul,.llm ol{padding-left:20px;margin-bottom:12px;}
|
||
.llm li{margin-bottom:4px;}
|
||
.llm code{font-family:var(--font-mono);font-size:11px;background:var(--color-surface);padding:1px 5px;border-radius:3px;}
|
||
.llm table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px;}
|
||
.llm th,.llm td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--color-border);}
|
||
.llm th{font-weight:500;color:var(--color-text);font-size:11px;text-transform:uppercase;letter-spacing:.05em;}
|
||
.llm td{color:var(--color-text-muted);}
|
||
|
||
@media(max-width:900px){.doc{padding:24px 16px 80px;}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="doc">
|
||
|
||
<div class="jh jh-g">
|
||
<div class="jn">J1</div>
|
||
<div><h2>Add a recipe</h2><p>Save recipe with ingredients, steps, tags, and hero image.</p><div class="fl">B1 → B3 → B1 · Planner · Min: effort + 1 category tag</div></div>
|
||
</div>
|
||
|
||
<!-- ═══ B1 RECIPE LIBRARY ═══ -->
|
||
<div class="scr" id="b1">
|
||
<div class="scr-head"><h3>Recipe library</h3><span class="scr-id">B1</span></div>
|
||
<div class="scr-desc">Browse all recipes. Desktop: app sidebar + topbar with search bar and filter chips + 4-column card grid. The grid fills the content area naturally — not wrapped in an additional card or panel.</div>
|
||
<div class="scr-var"><strong>V2 · Card grid</strong> — mobile 2-col, desktop sidebar + 4-col with filters</div>
|
||
|
||
<div class="previews">
|
||
<div class="prev-col">
|
||
<div class="bp-lbl">Mobile · 320px</div>
|
||
<div class="phone">
|
||
<div class="pst"><b>9:41</b><span>●●● WiFi 🔋</span></div>
|
||
<div class="pb">
|
||
<div class="mtb"><div class="mtb-t">Recipes</div><div style="display:flex;gap:6px;"><div class="mi">🔍</div><div class="mi gn">+</div></div></div>
|
||
<div style="padding:10px 12px;">
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:64px;background:var(--green-tint);display:flex;align-items:center;justify-content:center;font-size:28px;">🍝</div><div style="padding:8px 10px;"><div style="font-family:var(--font-display);font-size:12px;margin-bottom:3px;">Tomato pasta</div><div style="font-size:9px;color:var(--color-text-muted);">45 min · Easy</div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:64px;background:var(--yellow-tint);display:flex;align-items:center;justify-content:center;font-size:28px;">🍗</div><div style="padding:8px 10px;"><div style="font-family:var(--font-display);font-size:12px;margin-bottom:3px;">Chicken stir-fry</div><div style="font-size:9px;color:var(--color-text-muted);">25 min · Easy</div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:64px;background:var(--blue-tint);display:flex;align-items:center;justify-content:center;font-size:28px;">🐟</div><div style="padding:8px 10px;"><div style="font-family:var(--font-display);font-size:12px;margin-bottom:3px;">Salmon teriyaki</div><div style="font-size:9px;color:var(--color-text-muted);">35 min · Medium</div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:64px;background:var(--green-tint);display:flex;align-items:center;justify-content:center;font-size:28px;">🍄</div><div style="padding:8px 10px;"><div style="font-family:var(--font-display);font-size:12px;margin-bottom:3px;">Mushroom risotto</div><div style="font-size:9px;color:var(--color-text-muted);">50 min · Medium</div></div></div>
|
||
</div>
|
||
</div>
|
||
<div class="mbt"><div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Planner</div></div><div class="mt-i a"><div class="mt-ic">📖</div><div class="mt-l">Recipes</div></div><div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Shopping</div></div><div class="mt-i"><div class="mt-ic">⚙️</div><div class="mt-l">Settings</div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="prev-col">
|
||
<div class="bp-lbl">Desktop · 1040px</div>
|
||
<div class="desk">
|
||
<div class="dsb">
|
||
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥗</div><div class="dsb-nm">Mealplan</div></div><div class="dsb-sub">Smith household</div></div>
|
||
<div class="dsb-nav"><div style="margin-bottom:16px;"><div class="dsb-nl">Plan</div><div class="dsb-ni"><span class="dsb-nc">📅</span>Planner</div><div class="dsb-ni a"><span class="dsb-nc">📖</span>Recipes</div><div class="dsb-ni"><span class="dsb-nc">🛒</span>Shopping</div></div><div><div class="dsb-nl">Account</div><div class="dsb-ni"><span class="dsb-nc">👨👩👧</span>Household</div><div class="dsb-ni"><span class="dsb-nc">⚙️</span>Settings</div></div></div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="dtb"><div class="dtb-t">Recipe library</div><div class="dtb-r"><input class="fi" style="width:220px;font-size:12px;padding:7px 12px;" placeholder="🔍 Search recipes…"/><button class="dab">+ Add recipe</button></div></div>
|
||
<div style="flex:1;padding:20px 24px;overflow-y:auto;">
|
||
<!-- Filter chips -->
|
||
<div style="display:flex;gap:5px;margin-bottom:16px;">
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;background:var(--green-tint);color:var(--green-dark);">All (24)</div>
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;border:1px solid var(--color-border);color:var(--color-text-muted);">Easy</div>
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;border:1px solid var(--color-border);color:var(--color-text-muted);">Medium</div>
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;border:1px solid var(--color-border);color:var(--color-text-muted);">Chicken</div>
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;border:1px solid var(--color-border);color:var(--color-text-muted);">Fish</div>
|
||
<div style="font-size:11px;font-weight:500;padding:5px 14px;border-radius:12px;border:1px solid var(--color-border);color:var(--color-text-muted);">Veggie</div>
|
||
</div>
|
||
<!-- 4-col grid -->
|
||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;">
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;cursor:pointer;"><div style="height:100px;background:var(--green-tint);display:flex;align-items:center;justify-content:center;font-size:32px;">🍝</div><div style="padding:10px 12px;"><div style="font-family:var(--font-display);font-size:14px;font-weight:400;margin-bottom:4px;">Slow-roasted tomato pasta</div><div style="font-size:10px;color:var(--color-text-muted);margin-bottom:6px;">45 min · Easy · Last cooked 3 days ago</div><div style="display:flex;gap:3px;"><span class="badge badge-g">Vegetarian</span><span class="badge badge-y">Child-friendly</span></div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:100px;background:var(--yellow-tint);display:flex;align-items:center;justify-content:center;font-size:32px;">🍗</div><div style="padding:10px 12px;"><div style="font-family:var(--font-display);font-size:14px;font-weight:400;margin-bottom:4px;">Chicken stir-fry</div><div style="font-size:10px;color:var(--color-text-muted);margin-bottom:6px;">25 min · Easy · 5 days ago</div><div style="display:flex;gap:3px;"><span class="badge badge-m">Chicken</span></div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:100px;background:var(--blue-tint);display:flex;align-items:center;justify-content:center;font-size:32px;">🐟</div><div style="padding:10px 12px;"><div style="font-family:var(--font-display);font-size:14px;font-weight:400;margin-bottom:4px;">Salmon teriyaki with rice</div><div style="font-size:10px;color:var(--color-text-muted);margin-bottom:6px;">35 min · Medium · 2 weeks ago</div><div style="display:flex;gap:3px;"><span class="badge badge-m">Fish</span></div></div></div>
|
||
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;"><div style="height:100px;background:var(--green-tint);display:flex;align-items:center;justify-content:center;font-size:32px;">🍄</div><div style="padding:10px 12px;"><div style="font-family:var(--font-display);font-size:14px;font-weight:400;margin-bottom:4px;">Mushroom risotto</div><div style="font-size:10px;color:var(--color-text-muted);margin-bottom:6px;">50 min · Medium · 2 weeks ago</div><div style="display:flex;gap:3px;"><span class="badge badge-g">Vegetarian</span></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="agent">
|
||
<h4>B1 · Recipe library</h4>
|
||
<pre>/* Desktop: 224px sidebar + topbar (search 220px + Add button) + content: filter chips row + 4-col grid.
|
||
* Desktop cards are richer: 100px image area + name (Fraunces 14px) + meta + tags row.
|
||
* Mobile: 2-col, 64px image, no tags on cards (too small).
|
||
* Filter chips: from tag table. Active: green-tint. 12px border-radius.
|
||
* Grid fills the content area directly — no wrapping card.
|
||
* Card click → B2 (recipe detail). Add button → B3 (empty form). */</pre>
|
||
<table class="at"><thead><tr><th>Element</th><th>Value</th><th>Notes</th></tr></thead><tbody>
|
||
<tr class="grp"><td colspan="3">Desktop</td></tr>
|
||
<tr><td>Grid</td><td>4 columns, 12px gap, content padding 20px 24px</td><td>Cards: radius-lg, border-default, overflow hidden</td></tr>
|
||
<tr><td>Card image</td><td>100px height. hero_image_url → object-fit:cover. NULL → tint + emoji.</td><td>Tint color based on first protein tag</td></tr>
|
||
<tr><td>Card content</td><td>10px 12px padding. Name: Fraunces 14px. Meta: 10px muted. Tags: badge row.</td><td>meta shows cook time + effort + "last cooked X ago"</td></tr>
|
||
<tr><td>Filter chips</td><td>11px/500, 5px 14px pad, 12px radius</td><td>Active: green-tint bg + green-dark text. Others: border-default.</td></tr>
|
||
<tr class="grp"><td colspan="3">Mobile</td></tr>
|
||
<tr><td>Grid</td><td>2 columns, 8px gap</td><td>Cards: 64px image, 12px name, 9px meta. No tags.</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ═══ B3 ADD/EDIT RECIPE ═══ -->
|
||
<div class="scr" id="b3">
|
||
<div class="scr-head"><h3>Add / edit recipe</h3><span class="scr-id">B3</span></div>
|
||
<div class="scr-desc">Single form for add + edit. Mobile: V1 single scroll. Desktop: V5 sidebar + topbar + split content (form left, tags + live preview panel right). The tags panel is a natural sidebar within the content area, not a floating card.</div>
|
||
<div class="scr-var"><strong>V1 mobile / V5 desktop</strong> — form left, tags + preview right on desktop</div>
|
||
|
||
<div class="previews">
|
||
<div class="prev-col">
|
||
<div class="bp-lbl">Mobile · 320px</div>
|
||
<div class="phone">
|
||
<div class="pst"><b>9:45</b><span>●●● WiFi 🔋</span></div>
|
||
<div class="pb">
|
||
<div style="padding:10px 16px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;">
|
||
<div style="font-size:13px;color:var(--green);font-weight:500;">← Recipes</div>
|
||
<div style="font-family:var(--font-display);font-size:16px;font-weight:500;">New recipe</div>
|
||
<div style="font-size:13px;color:var(--green);font-weight:500;">Save</div>
|
||
</div>
|
||
<div style="padding:16px;">
|
||
<div style="height:56px;background:var(--color-subtle);border:1px dashed var(--color-border);border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center;margin-bottom:16px;"><div style="text-align:center;"><div style="font-size:14px;color:var(--color-border);">📷</div><div style="font-size:9px;color:var(--color-text-muted);">Add photo</div></div></div>
|
||
<div class="fg"><label class="fl">Recipe name</label><input class="fi" value="Slow-roasted tomato pasta"/></div>
|
||
<div style="display:flex;gap:8px;">
|
||
<div class="fg" style="flex:1;"><label class="fl">Serves</label><input class="fi" type="number" value="4"/></div>
|
||
<div class="fg" style="flex:1;"><label class="fl">Cook time</label><input class="fi" value="45 min"/></div>
|
||
</div>
|
||
<div class="eye" style="margin-bottom:6px;">Ingredients</div>
|
||
<div style="border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:4px 12px;margin-bottom:6px;">
|
||
<div class="ir"><div class="ir-q">500g</div><div class="ir-n">Cherry tomatoes</div><div class="ir-x">×</div></div>
|
||
<div class="ir"><div class="ir-q">300g</div><div class="ir-n">Penne pasta</div><div class="ir-x">×</div></div>
|
||
<div class="ir"><div class="ir-q">3 cloves</div><div class="ir-n">Garlic</div><div class="ir-x">×</div></div>
|
||
</div>
|
||
<button class="bg" style="width:100%;font-size:11px;padding:7px;margin-bottom:12px;">+ Add ingredient</button>
|
||
<div class="eye" style="margin-bottom:6px;">Tags (required)</div>
|
||
<div style="font-size:11px;color:var(--color-text-muted);margin-bottom:4px;">Effort</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:10px;"><span class="tc s">Easy</span><span class="tc">Medium</span><span class="tc">Hard</span></div>
|
||
<div style="font-size:11px;color:var(--color-text-muted);margin-bottom:4px;">Category (pick ≥ 1)</div>
|
||
<div style="margin-bottom:14px;"><span class="tc">Chicken</span><span class="tc">Fish</span><span class="tc s">Vegetarian</span><span class="tc s">Child-friendly</span><span class="tc">Pasta</span></div>
|
||
<button class="bp">Save recipe</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="prev-col">
|
||
<div class="bp-lbl">Desktop · 1040px</div>
|
||
<div class="desk" style="min-height:540px;">
|
||
<div class="dsb">
|
||
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥗</div><div class="dsb-nm">Mealplan</div></div><div class="dsb-sub">Smith household</div></div>
|
||
<div class="dsb-nav"><div><div class="dsb-nl">Plan</div><div class="dsb-ni"><span class="dsb-nc">📅</span>Planner</div><div class="dsb-ni a"><span class="dsb-nc">📖</span>Recipes</div><div class="dsb-ni"><span class="dsb-nc">🛒</span>Shopping</div></div></div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="dtb">
|
||
<div style="display:flex;align-items:center;gap:8px;"><span style="font-size:13px;color:var(--color-text-muted);">← Recipes</span><span style="color:var(--color-border);">/</span><span class="dtb-t">New recipe</span></div>
|
||
<div class="dtb-r"><button class="bg" style="padding:7px 14px;font-size:12px;">Cancel</button><button class="dab">Save recipe</button></div>
|
||
</div>
|
||
<div style="flex:1;display:flex;overflow:hidden;">
|
||
<!-- Left: form -->
|
||
<div style="flex:1;padding:24px;overflow-y:auto;border-right:1px solid var(--color-border);">
|
||
<div style="height:80px;background:var(--color-subtle);border:1px dashed var(--color-border);border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center;margin-bottom:20px;cursor:pointer;"><span style="font-size:13px;color:var(--color-text-muted);">📷 Add hero image</span></div>
|
||
<div class="fg"><label class="fl">Recipe name</label><input class="fi" value="Slow-roasted tomato pasta" style="font-size:16px;padding:12px 14px;"/></div>
|
||
<div style="display:flex;gap:12px;">
|
||
<div class="fg" style="flex:1;"><label class="fl">Serves</label><input class="fi" type="number" value="4"/></div>
|
||
<div class="fg" style="flex:1;"><label class="fl">Cook time</label><input class="fi" value="45 min"/></div>
|
||
<div class="fg" style="flex:1;"><label class="fl">Prep time</label><input class="fi" placeholder="Optional"/></div>
|
||
</div>
|
||
<div class="eye" style="margin:8px 0;">Ingredients</div>
|
||
<div style="border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:4px 14px;margin-bottom:8px;">
|
||
<div class="ir"><div class="ir-q">500g</div><div class="ir-n">Cherry tomatoes</div><div class="ir-x">×</div></div>
|
||
<div class="ir"><div class="ir-q">300g</div><div class="ir-n">Penne pasta</div><div class="ir-x">×</div></div>
|
||
<div class="ir"><div class="ir-q">3 cloves</div><div class="ir-n">Garlic</div><div class="ir-x">×</div></div>
|
||
<div class="ir"><div class="ir-q">2 tbsp</div><div class="ir-n">Olive oil</div><div class="ir-x">×</div></div>
|
||
</div>
|
||
<button class="bg" style="width:100%;font-size:12px;padding:8px;">+ Add ingredient</button>
|
||
<div class="eye" style="margin:16px 0 8px;">Steps</div>
|
||
<div style="display:flex;gap:10px;padding:8px 0;border-bottom:1px solid var(--color-subtle);"><div style="width:24px;height:24px;border-radius:50%;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:500;flex-shrink:0;">1</div><div style="font-size:13px;line-height:1.5;">Preheat oven to 180°C. Halve the tomatoes and place on a baking tray.</div></div>
|
||
<div style="display:flex;gap:10px;padding:8px 0;border-bottom:1px solid var(--color-subtle);"><div style="width:24px;height:24px;border-radius:50%;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:500;flex-shrink:0;">2</div><div style="font-size:13px;line-height:1.5;">Drizzle with olive oil, season. Roast for 40 minutes.</div></div>
|
||
<div style="display:flex;gap:10px;padding:8px 0;"><div style="width:24px;height:24px;border-radius:50%;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:500;flex-shrink:0;">3</div><div style="font-size:13px;line-height:1.5;">Cook pasta. Toss with roasted tomatoes and garlic.</div></div>
|
||
<button class="bg" style="width:100%;font-size:12px;padding:8px;margin-top:8px;">+ Add step</button>
|
||
</div>
|
||
<!-- Right: tags + preview -->
|
||
<div style="width:280px;flex-shrink:0;padding:24px;background:var(--color-surface);overflow-y:auto;">
|
||
<div class="eye" style="margin-bottom:8px;">Tags (required)</div>
|
||
<div style="font-size:11px;font-weight:500;margin-bottom:4px;">Effort level</div>
|
||
<div style="display:flex;gap:4px;margin-bottom:14px;"><span class="tc s">Easy</span><span class="tc">Medium</span><span class="tc">Hard</span></div>
|
||
<div style="font-size:11px;font-weight:500;margin-bottom:4px;">Category</div>
|
||
<div style="margin-bottom:20px;"><span class="tc">Chicken</span><span class="tc">Fish</span><span class="tc">Beef</span><span class="tc s">Vegetarian</span><span class="tc s">Child-friendly</span><span class="tc">Pasta</span></div>
|
||
<div style="border-top:1px solid var(--color-border);padding-top:16px;">
|
||
<div class="eye" style="margin-bottom:8px;">Live preview</div>
|
||
<div style="background:var(--color-page);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;">
|
||
<div style="height:48px;background:var(--green-tint);display:flex;align-items:center;justify-content:center;font-size:18px;">🍝</div>
|
||
<div style="padding:10px;"><div style="font-family:var(--font-display);font-size:13px;margin-bottom:3px;">Slow-roasted tomato pasta</div><div style="font-size:9px;color:var(--color-text-muted);margin-bottom:4px;">45 min · 4 servings · 4 ingredients</div><div style="display:flex;gap:3px;"><span class="badge badge-g">Easy</span><span class="badge badge-g">Vegetarian</span><span class="badge badge-y">Child-friendly</span></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="agent">
|
||
<h4>B3 · Add/edit recipe</h4>
|
||
<pre>/* Desktop: 224px sidebar + topbar (breadcrumb + Save) + split content:
|
||
* Left (flex:1, page bg): hero upload + name + serves/time/prep (3-col) + ingredients + steps
|
||
* Right (280px, surface bg): effort chips + category chips + live preview card
|
||
* Form content is NOT in a card — it's directly on the page bg.
|
||
* Tags panel (right) uses surface bg as a section differentiator, not as a card.
|
||
* Mobile: single scroll, full width. Back + title + Save in topbar.
|
||
* Ingredient autocomplete: citext ILIKE from ingredient table. */</pre>
|
||
<table class="at"><thead><tr><th>Element</th><th>Value</th><th>Notes</th></tr></thead><tbody>
|
||
<tr class="grp"><td colspan="3">Desktop</td></tr>
|
||
<tr><td>Form area</td><td>flex:1, page bg, 24px padding, border-right</td><td>Contains: hero + name (16px input) + 3-col row + ingredients + steps</td></tr>
|
||
<tr><td>Tags panel</td><td>280px, surface bg, 24px padding</td><td>Effort chips + category chips + divider + live preview card</td></tr>
|
||
<tr><td>Live preview</td><td>Mini B1 card inside the panel</td><td>Updates as user types. Shows name, time, servings, ingredient count, tags.</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ LLM IMPLEMENTATION GUIDE ═══ -->
|
||
<div class="llm">
|
||
<h2>Implementation Guide — J1 Add a Recipe</h2>
|
||
|
||
<h3>1. Journey Flow</h3>
|
||
<p>B1 (Recipe library) → B3 (Add/edit form) → B1 (Recipe library). Actor: <strong>Planner only</strong>.</p>
|
||
|
||
<h3>2. Screen B1 — Recipe Library</h3>
|
||
<ul>
|
||
<li><strong>Mobile:</strong> topbar + 2-col card grid (8px gap, 64px image, no tags on cards).</li>
|
||
<li><strong>Desktop:</strong> 224px sidebar + topbar (search input 220px + Add button) + filter chips row + 4-col grid (12px gap, 100px image, tags visible as badge row).</li>
|
||
<li><strong>Filter chips:</strong> sourced from the <code>tag</code> table. Active chip = <code>green-tint</code> bg / <code>green-dark</code> text. Inactive chip = <code>border-default</code>. Style: <code>font-size:11px; font-weight:500; padding:5px 14px; border-radius:12px</code>.</li>
|
||
<li>Card click → B2 (recipe detail). Add button → B3 (empty form).</li>
|
||
</ul>
|
||
|
||
<h3>3. Screen B3 — Add/Edit Recipe</h3>
|
||
<ul>
|
||
<li>Single form component with two states: empty (new recipe) vs prefilled (edit existing recipe).</li>
|
||
<li><strong>Design rule:</strong> B3 add = B3 edit — build once with two initial states.</li>
|
||
<li><strong>Mobile:</strong> single scroll column, full width.</li>
|
||
<li><strong>Desktop:</strong> 224px sidebar + topbar (breadcrumb + Save/Cancel buttons) + split content: form left (<code>flex:1</code>, page bg, 24px padding) + tags panel right (280px, surface bg).</li>
|
||
</ul>
|
||
<p><strong>Form sections:</strong></p>
|
||
<ol>
|
||
<li>Hero image upload (optional) — dashed border placeholder, click to upload.</li>
|
||
<li>Recipe name (required) — 16px font on desktop.</li>
|
||
<li>Serves / Cook time / Prep time — 3-col row on desktop, 2-col on mobile (prep time hidden or below).</li>
|
||
<li>Ingredients — editable list with autocomplete. Each row: quantity + name + remove button.</li>
|
||
<li>Steps — numbered list, optional at save. Each step: circle number + text.</li>
|
||
</ol>
|
||
<p><strong>Tags (required):</strong></p>
|
||
<ul>
|
||
<li>Effort level: Easy / Medium / Hard — single-select chip group.</li>
|
||
<li>Category: at least 1 required — Chicken, Fish, Beef, Vegetarian, Pasta, etc. Multi-select chips.</li>
|
||
</ul>
|
||
<p><strong>Desktop right panel:</strong> live preview card (mini B1 card) updates as user types — shows name, time, servings, ingredient count, and selected tags.</p>
|
||
<p><strong>Ingredient autocomplete:</strong> <code>citext ILIKE</code> query against the <code>ingredient</code> table.</p>
|
||
|
||
<h3>4. Data Operations</h3>
|
||
<table>
|
||
<thead><tr><th>Screen</th><th>Operation</th><th>Tables</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>B1</td><td><code>SELECT</code> recipes with tags</td><td><code>recipe</code> JOIN <code>recipe_tag</code> + <code>tag</code></td></tr>
|
||
<tr><td>B3</td><td><code>INSERT</code> / <code>UPDATE</code> recipe</td><td><code>recipe</code></td></tr>
|
||
<tr><td>B3</td><td><code>INSERT</code> / <code>DELETE</code> ingredients</td><td><code>recipe_ingredient</code></td></tr>
|
||
<tr><td>B3</td><td><code>INSERT</code> / <code>DELETE</code> steps</td><td><code>recipe_step</code></td></tr>
|
||
<tr><td>B3</td><td><code>INSERT</code> / <code>DELETE</code> tags</td><td><code>recipe_tag</code></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Minimum to save:</strong> name + effort tag + at least 1 category tag.</p>
|
||
|
||
<h3>5. Design Constraints</h3>
|
||
<ul>
|
||
<li>Tags power the variety algorithm — they are not cosmetic. Ensure tags are always saved correctly.</li>
|
||
<li>If entered from a planner day slot, offer to assign the recipe to that day after save.</li>
|
||
<li>Steps are optional — recipes without steps can still be planned and cooked from the ingredient list only.</li>
|
||
<li>Form content is NOT in a card on desktop — it sits directly on the page background.</li>
|
||
<li>The tags panel uses <code>surface</code> bg as a section differentiator, not as a card wrapper.</li>
|
||
</ul>
|
||
|
||
<h3>6. Accessibility</h3>
|
||
<ul>
|
||
<li>All form inputs must have associated <code><label></code> elements.</li>
|
||
<li>Ingredient and step lists must support keyboard navigation (add, remove, reorder).</li>
|
||
<li>Chip selections (effort level, category tags) must use proper ARIA attributes: <code>role="radiogroup"</code> for single-select effort, <code>role="group"</code> with <code>aria-pressed</code> for multi-select categories.</li>
|
||
<li>Live preview region should use <code>aria-live="polite"</code> to announce updates.</li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|