feat(specs): Add-to-Plan flows — screens C4, C5, C6
Specifies three missing interaction surfaces for adding a recipe to the weekly plan (Issue #42): - C4: Recipe picker bottom sheet / desktop panel transformation triggered from the weekly planner's "+" button or empty slot - C5: Recipe card quick actions ("Jetzt kochen" + "Zur Woche +") - C6: Day picker sheet / panel for adding a known recipe to a chosen day Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
913
specs/frontend/j2-add-meal.html
Normal file
913
specs/frontend/j2-add-meal.html
Normal file
@@ -0,0 +1,913 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Recipe App — J2 Add to Plan · Screens C4–C6</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;background:var(--color-page);margin:-48px -40px 48px;padding:48px 40px 28px;border-bottom:1px solid var(--color-border);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;}
|
||||||
|
|
||||||
|
/* 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;}
|
||||||
|
|
||||||
|
/* Journey header */
|
||||||
|
.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-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);}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
.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;display:flex;flex-direction:column;}
|
||||||
|
|
||||||
|
/* Desktop frame */
|
||||||
|
.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;}
|
||||||
|
|
||||||
|
/* Desktop sidebar */
|
||||||
|
.dsb{width:196px;flex-shrink:0;background:var(--color-surface);border-right:1px solid var(--color-border);display:flex;flex-direction:column;}
|
||||||
|
.dsb-logo{padding:16px 14px 12px;border-bottom:1px solid var(--color-border);}
|
||||||
|
.dsb-lm{display:flex;align-items:center;gap:6px;margin-bottom:2px;}.dsb-ic{width:22px;height:22px;border-radius:4px;background:var(--green);display:flex;align-items:center;justify-content:center;font-size:11px;}.dsb-nm{font-family:var(--font-display);font-size:15px;font-weight:500;letter-spacing:-.02em;}.dsb-sub{font-size:10px;color:var(--color-text-muted);padding-left:28px;}
|
||||||
|
.dsb-nav{padding:10px 8px;flex:1;}
|
||||||
|
.dsb-ni{display:flex;align-items:center;gap:6px;padding:6px 6px;border-radius:5px;font-size:12px;color:var(--color-text-muted);margin-bottom:1px;}
|
||||||
|
.dsb-ni.a{background:var(--green-tint);color:var(--green-dark);font-weight:500;}
|
||||||
|
.dsb-nc{font-size:12px;width:16px;text-align:center;}
|
||||||
|
.dsb-var{margin:0 8px 12px;padding:10px 12px;background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-lg);}
|
||||||
|
.dsb-ve{font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--yellow-text);margin-bottom:3px;}
|
||||||
|
.dsb-vn{font-family:var(--font-display);font-size:28px;font-weight:300;line-height:1;color:var(--color-text);}
|
||||||
|
|
||||||
|
/* Desktop main */
|
||||||
|
.d-main{flex:1;display:flex;flex-direction:column;min-width:0;}
|
||||||
|
.d-tb{padding:10px 16px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;flex-shrink:0;}
|
||||||
|
.d-ttitle{font-family:var(--font-display);font-size:16px;font-weight:500;letter-spacing:-.02em;}
|
||||||
|
.d-ab{font-family:var(--font-sans);font-size:12px;font-weight:500;padding:5px 12px;border-radius:4px;background:var(--green);color:#fff;border:none;}
|
||||||
|
.d-content{flex:1;display:flex;overflow:hidden;}
|
||||||
|
.d-cal{flex:1;overflow-y:auto;padding:10px;}
|
||||||
|
.d-cg{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;}
|
||||||
|
.d-cc{display:flex;flex-direction:column;}
|
||||||
|
.d-ch{text-align:center;padding-bottom:6px;margin-bottom:6px;border-bottom:2px solid var(--color-border);}
|
||||||
|
.d-ch.th{border-bottom-color:var(--yellow);}
|
||||||
|
.d-ch.sh{border-bottom-color:var(--green);}
|
||||||
|
.d-dn{font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:3px;}
|
||||||
|
.d-db{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:4px;font-size:11px;font-weight:500;color:var(--color-text);}
|
||||||
|
.d-ch.th .d-db{background:var(--yellow);}
|
||||||
|
.d-ch.sh .d-db{background:var(--green-tint);color:var(--green-dark);}
|
||||||
|
.d-tile{flex:1;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:6px 6px 8px;cursor:pointer;box-shadow:var(--shadow-card);display:flex;flex-direction:column;gap:2px;}
|
||||||
|
.d-tile.tt{border-color:var(--yellow);border-width:2px;background:var(--yellow-tint);}
|
||||||
|
.d-te{font-size:7px;font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted);}
|
||||||
|
.d-tn{font-family:var(--font-display);font-size:10px;font-weight:400;letter-spacing:-.01em;color:var(--color-text);line-height:1.3;}
|
||||||
|
.d-tm{font-size:8px;color:var(--color-text-muted);margin-top:1px;}
|
||||||
|
.d-et{flex:1;border:1px dashed var(--color-border);border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center;min-height:56px;flex-direction:column;gap:2px;cursor:pointer;}
|
||||||
|
.d-et.active{border-style:solid;border-color:var(--green);background:var(--green-tint);}
|
||||||
|
.d-ep{font-size:15px;color:var(--color-border);}
|
||||||
|
.d-el{font-size:8px;color:var(--color-border);}
|
||||||
|
.d-et.active .d-ep,.d-et.active .d-el{color:var(--green-dark);}
|
||||||
|
|
||||||
|
/* Detail panel */
|
||||||
|
.d-dp{width:216px;flex-shrink:0;background:var(--color-surface);border-left:1px solid var(--color-border);display:flex;flex-direction:column;overflow-y:auto;}
|
||||||
|
.d-dph{padding:10px 12px 8px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:flex-start;}
|
||||||
|
.d-dpd{font-family:var(--font-display);font-size:14px;font-weight:500;letter-spacing:-.01em;}
|
||||||
|
.d-dpdt{font-size:9px;color:var(--color-text-muted);margin-top:1px;}
|
||||||
|
.d-dpx{font-size:16px;color:var(--color-text-muted);cursor:pointer;line-height:1;flex-shrink:0;}
|
||||||
|
.d-psearch{padding:8px 10px;border-bottom:1px solid var(--color-subtle);}
|
||||||
|
.d-psi{width:100%;font-family:var(--font-sans);font-size:11px;padding:6px 8px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-page);color:var(--color-text);outline:none;}
|
||||||
|
.d-prsect{font-size:7px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);padding:6px 10px 3px;background:var(--color-subtle);}
|
||||||
|
.d-prec{padding:7px 10px;border-bottom:1px solid var(--color-subtle);cursor:pointer;}
|
||||||
|
.d-prec:last-child{border-bottom:none;}
|
||||||
|
.d-prname{font-family:var(--font-display);font-size:11px;font-weight:400;color:var(--color-text);line-height:1.25;}
|
||||||
|
.d-prmeta{font-size:9px;color:var(--color-text-muted);margin-top:1px;}
|
||||||
|
.d-prbadge{display:inline-block;font-size:8px;font-weight:500;padding:1px 5px;border-radius:3px;background:var(--green-tint);color:var(--green-dark);margin-top:2px;}
|
||||||
|
.d-prbadge.warn{background:var(--yellow-tint);color:var(--yellow-text);}
|
||||||
|
|
||||||
|
/* Bottom tab nav */
|
||||||
|
.mbt{border-top:1px solid var(--color-border);background:var(--color-surface);padding:6px 16px 20px;display:flex;justify-content:space-around;}
|
||||||
|
.mt-i{display:flex;flex-direction:column;align-items:center;gap:2px;}.mt-ic{width:18px;height:18px;border-radius:4px;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:10px;}.mt-i.a .mt-ic{background:var(--green-tint);}.mt-l{font-size:8px;font-weight:500;color:var(--color-text-muted);}.mt-i.a .mt-l{color:var(--green-dark);}
|
||||||
|
|
||||||
|
/* Shared badges */
|
||||||
|
.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);}
|
||||||
|
|
||||||
|
/* Eyebrow */
|
||||||
|
.eye{font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);}
|
||||||
|
|
||||||
|
/* Annotation cards */
|
||||||
|
.ann{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:20px 24px;margin-bottom:12px;}
|
||||||
|
.ann h3{font-size:13px;font-weight:500;color:var(--color-text);margin-bottom:8px;}
|
||||||
|
.ann p{font-size:13px;color:var(--color-text-muted);line-height:1.65;}
|
||||||
|
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px;}
|
||||||
|
.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-top:16px;}
|
||||||
|
.note{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px 20px;}
|
||||||
|
.note h4{font-size:11px;font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:8px;}
|
||||||
|
.note p{font-size:13px;color:var(--color-text-muted);line-height:1.6;}
|
||||||
|
.note.hl{border-color:var(--green-light);background:var(--green-tint);}
|
||||||
|
.note.hl h4{color:var(--green-dark);}
|
||||||
|
.note.hl p{color:var(--green-deeper);}
|
||||||
|
.note.warn{border-color:var(--yellow-light);background:var(--yellow-tint);}
|
||||||
|
.note.warn h4{color:var(--yellow-text);}
|
||||||
|
.note.warn p{color:var(--yellow-text);}
|
||||||
|
|
||||||
|
/* Agent section */
|
||||||
|
.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;}
|
||||||
|
|
||||||
|
/* ── C4: Recipe picker bottom sheet ── */
|
||||||
|
.sheet-host{flex:1;display:flex;flex-direction:column;justify-content:flex-end;min-height:400px;}
|
||||||
|
.sheet-bg{position:relative;flex:1;background:rgba(28,28,24,.4);}
|
||||||
|
.sheet{background:var(--color-page);border-top:1px solid var(--color-border);border-radius:var(--radius-xl) var(--radius-xl) 0 0;box-shadow:0 -4px 20px rgba(0,0,0,.12);display:flex;flex-direction:column;max-height:320px;}
|
||||||
|
.sheet-handle{width:32px;height:4px;border-radius:2px;background:var(--color-border);margin:10px auto 0;flex-shrink:0;}
|
||||||
|
.sheet-hd{padding:8px 14px 8px;border-bottom:1px solid var(--color-subtle);display:flex;justify-content:space-between;align-items:center;flex-shrink:0;}
|
||||||
|
.sheet-ht{font-family:var(--font-display);font-size:14px;font-weight:500;letter-spacing:-.01em;}
|
||||||
|
.sheet-sub{font-size:10px;color:var(--color-text-muted);margin-top:1px;}
|
||||||
|
.sheet-x{font-size:17px;color:var(--color-text-muted);cursor:pointer;line-height:1;}
|
||||||
|
.sheet-search{padding:7px 12px;border-bottom:1px solid var(--color-subtle);flex-shrink:0;}
|
||||||
|
.sheet-si{width:100%;font-family:var(--font-sans);font-size:11px;padding:6px 8px 6px 26px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);outline:none;}
|
||||||
|
.sheet-si-wrap{position:relative;}
|
||||||
|
.sheet-si-icon{position:absolute;left:8px;top:50%;transform:translateY(-50%);font-size:10px;color:var(--color-text-muted);}
|
||||||
|
.sheet-body{overflow-y:auto;flex:1;}
|
||||||
|
.sheet-sect{font-size:7px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);padding:5px 12px 3px;background:var(--color-subtle);}
|
||||||
|
.sheet-row{padding:7px 12px;border-bottom:1px solid var(--color-subtle);display:flex;align-items:center;gap:8px;}
|
||||||
|
.sheet-row:last-child{border-bottom:none;}
|
||||||
|
.sheet-rinfo{flex:1;}
|
||||||
|
.sheet-rn{font-family:var(--font-display);font-size:12px;font-weight:400;color:var(--color-text);line-height:1.25;}
|
||||||
|
.sheet-rm{font-size:9px;color:var(--color-text-muted);margin-top:1px;}
|
||||||
|
.sheet-rbadge{display:inline-block;font-size:8px;font-weight:500;padding:1px 5px;border-radius:3px;background:var(--green-tint);color:var(--green-dark);margin-top:2px;}
|
||||||
|
.sheet-rbadge.warn{background:var(--yellow-tint);color:var(--yellow-text);}
|
||||||
|
.sheet-add{font-family:var(--font-sans);font-size:10px;font-weight:500;padding:4px 8px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;white-space:nowrap;flex-shrink:0;}
|
||||||
|
|
||||||
|
/* ── C5: Recipe quick actions ── */
|
||||||
|
.rc-list{padding:8px 12px;overflow-y:auto;}
|
||||||
|
.rc-card{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:10px 12px;margin-bottom:8px;box-shadow:var(--shadow-card);}
|
||||||
|
.rc-name{font-family:var(--font-display);font-size:14px;font-weight:400;letter-spacing:-.01em;color:var(--color-text);line-height:1.25;margin-bottom:4px;}
|
||||||
|
.rc-tags{display:flex;flex-wrap:wrap;gap:3px;margin-bottom:8px;}
|
||||||
|
.rc-acts{display:flex;gap:5px;}
|
||||||
|
.rc-cook{flex:1;font-family:var(--font-sans);font-size:10px;font-weight:500;padding:5px 6px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;text-align:center;}
|
||||||
|
.rc-plan{flex:1;font-family:var(--font-sans);font-size:10px;font-weight:500;padding:5px 6px;border-radius:var(--radius-md);background:var(--green-tint);color:var(--green-dark);border:1px solid var(--green-light);text-align:center;}
|
||||||
|
/* Desktop recipe grid */
|
||||||
|
.d-rcgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;padding:16px;}
|
||||||
|
.d-rccard{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;box-shadow:var(--shadow-card);}
|
||||||
|
.d-rcname{font-family:var(--font-display);font-size:16px;font-weight:400;letter-spacing:-.01em;color:var(--color-text);margin-bottom:5px;}
|
||||||
|
.d-rcdesc{font-size:12px;color:var(--color-text-muted);line-height:1.5;margin-bottom:10px;}
|
||||||
|
.d-rctags{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px;}
|
||||||
|
.d-rcacts{display:flex;gap:6px;}
|
||||||
|
.d-rccook{flex:1;font-family:var(--font-sans);font-size:11px;font-weight:500;padding:7px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;text-align:center;}
|
||||||
|
.d-rcplan{flex:1;font-family:var(--font-sans);font-size:11px;font-weight:500;padding:7px;border-radius:var(--radius-md);background:var(--green-tint);color:var(--green-dark);border:1px solid var(--green-light);text-align:center;}
|
||||||
|
|
||||||
|
/* ── C6: Day picker ── */
|
||||||
|
.dp-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;padding:8px 12px 5px;}
|
||||||
|
.dp-chip{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 2px;border-radius:5px;border:1px solid transparent;cursor:pointer;}
|
||||||
|
.dp-chip.empty{border-style:dashed;border-color:var(--green-light);background:var(--green-tint);}
|
||||||
|
.dp-chip.filled{border-color:var(--color-border);background:var(--color-surface);}
|
||||||
|
.dp-chip.today{border-color:var(--yellow);background:var(--yellow-tint);}
|
||||||
|
.dp-chip.sel-empty{border:2px solid var(--green-dark);background:var(--green-tint);}
|
||||||
|
.dp-chip.sel-filled{border:2px solid var(--orange-dark);background:var(--orange-tint);}
|
||||||
|
.dp-ca{font-size:7px;font-weight:500;letter-spacing:.05em;text-transform:uppercase;color:var(--color-text-muted);}
|
||||||
|
.dp-chip.empty .dp-ca{color:var(--green-dark);}
|
||||||
|
.dp-chip.today .dp-ca{color:var(--yellow-text);}
|
||||||
|
.dp-chip.sel-empty .dp-ca{color:var(--green-deeper);}
|
||||||
|
.dp-chip.sel-filled .dp-ca{color:var(--orange-dark);}
|
||||||
|
.dp-cn{font-size:11px;font-weight:500;color:var(--color-text);}
|
||||||
|
.dp-dot{width:4px;height:4px;border-radius:50%;background:var(--color-border);margin-top:1px;}
|
||||||
|
.dp-chip.empty .dp-dot{background:transparent;}
|
||||||
|
.dp-chip.filled .dp-dot,.dp-chip.sel-empty .dp-dot{background:var(--green);}
|
||||||
|
.dp-chip.today .dp-dot{background:var(--yellow-text);}
|
||||||
|
.dp-chip.sel-filled .dp-dot{background:var(--orange-dark);}
|
||||||
|
.dp-confirm{padding:8px 12px 6px;}
|
||||||
|
.dp-btn{width:100%;font-family:var(--font-sans);font-size:12px;font-weight:500;padding:9px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;text-align:center;}
|
||||||
|
.dp-btn.replace{background:var(--orange);}
|
||||||
|
.dp-warn{background:var(--orange-tint);border:1px solid #FBCDA4;border-radius:var(--radius-md);padding:6px 10px;margin:0 12px 6px;font-size:10px;color:var(--orange-dark);line-height:1.45;}
|
||||||
|
|
||||||
|
/* LLM section */
|
||||||
|
.llm{background:var(--color-text);color:#E8E8E2;padding:36px 44px;border-radius:var(--radius-lg);margin-top:80px;}
|
||||||
|
.llm h2{font-size:10px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#6B6A63;margin-bottom:16px;}
|
||||||
|
.llm h3{font-size:12px;font-weight:500;color:#9A9990;margin:24px 0 8px;letter-spacing:.04em;text-transform:uppercase;}
|
||||||
|
.llm p,.llm li{font-size:12px;color:#9A9990;line-height:1.7;}
|
||||||
|
.llm ul{margin-left:16px;margin-bottom:8px;}
|
||||||
|
.llm strong{color:#E8E8E2;}
|
||||||
|
.llm code{font-family:var(--font-mono);font-size:10px;background:#1E1E1A;color:#A0A090;padding:1px 5px;border-radius:3px;}
|
||||||
|
|
||||||
|
@media(max-width:900px){.doc{padding:24px 16px 80px;}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="doc">
|
||||||
|
|
||||||
|
<div class="doc-header">
|
||||||
|
<div>
|
||||||
|
<h1>J2 Add to Plan — Screens C4–C6</h1>
|
||||||
|
<p>Supplemental spec · Bottom sheet recipe picker · Recipe quick actions · Day picker</p>
|
||||||
|
</div>
|
||||||
|
<div class="doc-meta">
|
||||||
|
Journey: J2 supplement<br>
|
||||||
|
Screens: C4 · C5 · C6<br>
|
||||||
|
Status: draft<br>
|
||||||
|
Version: 1.0<br>
|
||||||
|
Updated: 2026-04
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="jh jh-y">
|
||||||
|
<div class="jn">J2</div>
|
||||||
|
<div>
|
||||||
|
<h2>Add to plan — supplemental</h2>
|
||||||
|
<p>Three missing flows: picking a recipe for an empty slot (C4), quick actions on recipe cards (C5), and the day picker when the recipe is already known (C6).</p>
|
||||||
|
<div class="fl">Two entry points: C1 "+" / empty slot → C4 · B1 "Zur Woche +" → C6</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- RATIONALE -->
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Design rationale</div>
|
||||||
|
<div class="grid2">
|
||||||
|
<div class="ann">
|
||||||
|
<h3>Entry from planner (C4) — recipe unknown</h3>
|
||||||
|
<p>User taps "+" or an empty slot in C1. The day is known; the recipe isn't. A bottom sheet slides up over the dimmed planner, showing variety-ranked suggestions and a search-filtered full library. On desktop the empty tile highlights and the detail panel transforms to a recipe picker — the calendar grid stays fully visible. No full-page navigation; same pattern as J4 swap.</p>
|
||||||
|
</div>
|
||||||
|
<div class="ann">
|
||||||
|
<h3>Entry from recipe list (C5 → C6) — day unknown</h3>
|
||||||
|
<p>User is browsing recipes and taps "Zur Woche +". The recipe is known; the day isn't. A compact day-picker sheet shows the week's slots. Empty slots have a dashed green border to invite selection. Selecting a filled slot shows an inline replace warning — no modal dialog. "Jetzt kochen" on the same card navigates directly to J3 cook mode.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid3">
|
||||||
|
<div class="note warn">
|
||||||
|
<h4>Add ≠ Swap</h4>
|
||||||
|
<p>J4 Swap starts from a filled slot and shows system-suggested replacements. C4/C6 add starts from an empty slot or a chosen recipe. Different intent — do not reuse the swap sheet component.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note hl">
|
||||||
|
<h4>Mobile: always bottom sheet</h4>
|
||||||
|
<p>No full-page navigation for either entry point. The planner or recipe list context stays visible behind the sheet at 40% opacity.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
<h4>Desktop: panel transformation</h4>
|
||||||
|
<p>The 216px detail panel switches between states. No modal overlay. The calendar grid or recipe grid remains fully interactive beside the picker.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ═══ C4: ADD MEAL FROM PLANNER ═══ -->
|
||||||
|
<div class="scr" id="c4">
|
||||||
|
<div class="scr-head"><h3>Add meal — from planner</h3><span class="scr-id">C4</span></div>
|
||||||
|
<div class="scr-desc">Entry: tap "+" in C1 nav (pre-selects next empty day) or tap any empty slot chip/tile (pre-selects that day). Shows a bottom sheet with search + variety-ranked suggestions + full recipe list. Tapping a recipe immediately fills the slot — no confirmation, undo toast instead.</div>
|
||||||
|
<div class="scr-var"><strong>V1 · Bottom sheet (mobile & tablet)</strong> · <strong>V2 · Panel transformation (desktop)</strong></div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Breakpoint 1 — Mobile · < 768px</div>
|
||||||
|
<div style="display:flex;gap:40px;align-items:flex-start;flex-wrap:wrap;margin-bottom:32px;">
|
||||||
|
|
||||||
|
<div class="phone">
|
||||||
|
<div class="pst"><b>9:41</b><span>●●● WiFi 🔋</span></div>
|
||||||
|
<div class="pb">
|
||||||
|
<!-- Planner context, dimmed -->
|
||||||
|
<div style="opacity:.3;">
|
||||||
|
<div style="padding:8px 12px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div style="font-family:var(--font-display);font-size:16px;font-weight:500;">Diese Woche</div>
|
||||||
|
<div style="display:flex;gap:3px;">
|
||||||
|
<div style="width:22px;height:22px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);display:flex;align-items:center;justify-content:center;font-size:9px;color:var(--color-text-muted);">⟨</div>
|
||||||
|
<div style="width:22px;height:22px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);display:flex;align-items:center;justify-content:center;font-size:9px;color:var(--color-text-muted);">⟩</div>
|
||||||
|
<div style="width:22px;height:22px;border-radius:4px;background:var(--green);display:flex;align-items:center;justify-content:center;font-size:10px;color:#fff;">+</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(7,1fr);gap:2px;padding:5px 10px;">
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Mo</span><span style="font-size:10px;font-weight:500;">31</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;background:var(--yellow-tint);"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--yellow-text);">Di</span><span style="font-size:10px;font-weight:500;">1</span><div style="width:3px;height:3px;border-radius:50%;background:var(--yellow-text);"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Mi</span><span style="font-size:10px;font-weight:500;">2</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Do</span><span style="font-size:10px;font-weight:500;">3</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Fr</span><span style="font-size:10px;font-weight:500;">4</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;border:1px dashed var(--green-light);background:var(--green-tint);"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--green-dark);">Sa</span><span style="font-size:10px;font-weight:500;">5</span><div style="width:3px;height:3px;border-radius:50%;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 1px;border-radius:4px;"><span style="font-size:7px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">So</span><span style="font-size:10px;font-weight:500;">6</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sheet -->
|
||||||
|
<div class="sheet-host">
|
||||||
|
<div class="sheet-bg"></div>
|
||||||
|
<div class="sheet">
|
||||||
|
<div class="sheet-handle"></div>
|
||||||
|
<div class="sheet-hd">
|
||||||
|
<div>
|
||||||
|
<div class="sheet-ht">Rezept wählen</div>
|
||||||
|
<div class="sheet-sub">Samstag, 5. April</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-x">×</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-search">
|
||||||
|
<div class="sheet-si-wrap">
|
||||||
|
<span class="sheet-si-icon">🔍</span>
|
||||||
|
<input class="sheet-si" type="text" placeholder="Rezept suchen…" readonly/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-body">
|
||||||
|
<div class="sheet-sect">Empfohlen · Beste Abwechslung</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo">
|
||||||
|
<div class="sheet-rn">Lachsfilet mit Gemüse</div>
|
||||||
|
<div class="sheet-rm">25 min · Einfach · Fisch</div>
|
||||||
|
<span class="sheet-rbadge">↑ +2 Punkte</span>
|
||||||
|
</div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo">
|
||||||
|
<div class="sheet-rn">Mushroom Risotto</div>
|
||||||
|
<div class="sheet-rm">50 min · Mittel · Vegetarisch</div>
|
||||||
|
<span class="sheet-rbadge">↑ +2 Punkte</span>
|
||||||
|
</div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo">
|
||||||
|
<div class="sheet-rn">Hähnchen-Curry</div>
|
||||||
|
<div class="sheet-rm">35 min · Einfach</div>
|
||||||
|
<span class="sheet-rbadge warn">⚠ Fr ebenfalls Hähnchen</span>
|
||||||
|
</div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-sect">Alle Rezepte</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo"><div class="sheet-rn">Beef Bourguignon</div><div class="sheet-rm">2h 30 · Aufwendig</div></div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo"><div class="sheet-rn">Spaghetti Carbonara</div><div class="sheet-rm">20 min · Einfach</div></div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-row">
|
||||||
|
<div class="sheet-rinfo"><div class="sheet-rn">Tomatensuppe</div><div class="sheet-rm">30 min · Vegetarisch</div></div>
|
||||||
|
<button class="sheet-add">+ Wählen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="flex:1;min-width:240px;display:flex;flex-direction:column;gap:12px;">
|
||||||
|
<div class="note hl">
|
||||||
|
<h4>Sheet structure</h4>
|
||||||
|
<p>Drag handle → title row (day date in muted subtitle) → close × → search input → two sections: "Empfohlen" (2–4 variety-ranked, sorted by variety_delta DESC) + "Alle Rezepte" (full library, filtered by search). Max height ~75vh — 3 suggestions visible without scrolling.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
<h4>Variety badges</h4>
|
||||||
|
<p>Green "↑ +N Punkte" when adding this recipe improves the variety score. Yellow "⚠ [reason]" when it creates a conflict but is still selectable. No badge in the "Alle Rezepte" section.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
<h4>Background</h4>
|
||||||
|
<p>Weekly planner dims to 30% opacity behind the sheet. The week strip is still legible — the empty Sa chip is visible with its dashed border, providing context for which slot is being filled.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note warn">
|
||||||
|
<h4>Immediate write</h4>
|
||||||
|
<p>Tapping "+ Wählen" writes to the slot immediately and dismisses the sheet. An undo toast appears for 4 seconds. No confirmation dialog — same pattern as J4.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Breakpoint 3 — Desktop · > 1024px</div>
|
||||||
|
<div class="ann" style="margin-bottom:16px;">
|
||||||
|
<h3>Panel in recipe-picker mode</h3>
|
||||||
|
<p>Clicking an empty slot tile (or "+" in the toolbar without a day) opens the recipe picker in the right detail panel. The calendar grid remains fully visible and interactive. The empty tile highlights with a solid green border and "Wählen…" label to indicate which slot is being edited.</p>
|
||||||
|
</div>
|
||||||
|
<div style="overflow-x:auto;margin-bottom:20px;">
|
||||||
|
<div class="desk" style="min-height:460px;">
|
||||||
|
<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 class="dsb-ni a"><span class="dsb-nc">📅</span> Planer</div>
|
||||||
|
<div class="dsb-ni"><span class="dsb-nc">📖</span> Rezepte</div>
|
||||||
|
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkauf</div>
|
||||||
|
</div>
|
||||||
|
<div class="dsb-var"><div class="dsb-ve">Variety score</div><div class="dsb-vn">8<span style="font-size:11px;color:var(--color-text-muted);">/10</span></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-main">
|
||||||
|
<div class="d-tb">
|
||||||
|
<div style="display:flex;align-items:center;gap:12px;">
|
||||||
|
<span class="d-ttitle">Wochenplanung</span>
|
||||||
|
<div style="display:flex;gap:4px;align-items:center;">
|
||||||
|
<button style="font-family:var(--font-sans);font-size:10px;padding:3px 7px;border-radius:4px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">‹</button>
|
||||||
|
<span style="font-size:11px;font-weight:500;color:var(--color-text);min-width:120px;text-align:center;">31 März – 6 Apr</span>
|
||||||
|
<button style="font-family:var(--font-sans);font-size:10px;padding:3px 7px;border-radius:4px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">›</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="d-ab">+ Mahlzeit</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-content">
|
||||||
|
<div class="d-cal">
|
||||||
|
<div class="d-cg">
|
||||||
|
<div class="d-cc"><div class="d-ch"><div class="d-dn">Montag</div><div class="d-db">31</div></div><div class="d-tile"><div class="d-te">Abendessen</div><div class="d-tn">Pasta al forno</div><div class="d-tm">30 min</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch th"><div class="d-dn">Dienstag</div><div class="d-db">1</div></div><div class="d-tile tt"><div class="d-te">Heute</div><div class="d-tn">Gegrillter Lachs</div><div class="d-tm">25 min</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch"><div class="d-dn">Mittwoch</div><div class="d-db">2</div></div><div class="d-tile"><div class="d-te">Abendessen</div><div class="d-tn">Tomaten-Pasta</div><div class="d-tm">45 min</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch"><div class="d-dn">Donnerstag</div><div class="d-db">3</div></div><div class="d-tile"><div class="d-te">Abendessen</div><div class="d-tn">Hähnchen-Stir-fry</div><div class="d-tm">25 min</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch"><div class="d-dn">Freitag</div><div class="d-db">4</div></div><div class="d-tile"><div class="d-te">Abendessen</div><div class="d-tn">Hähnchen-Curry</div><div class="d-tm">40 min</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch sh"><div class="d-dn">Samstag</div><div class="d-db">5</div></div><div class="d-et active"><div class="d-ep">+</div><div class="d-el">Wählen…</div></div></div>
|
||||||
|
<div class="d-cc"><div class="d-ch"><div class="d-dn">Sonntag</div><div class="d-db">6</div></div><div class="d-tile"><div class="d-te">Abendessen</div><div class="d-tn">Linsensuppe</div><div class="d-tm">45 min</div></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Detail panel: recipe picker mode -->
|
||||||
|
<div class="d-dp">
|
||||||
|
<div class="d-dph">
|
||||||
|
<div><div class="d-dpd">Sa, 5. April</div><div class="d-dpdt">Rezept wählen</div></div>
|
||||||
|
<div class="d-dpx">×</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-psearch">
|
||||||
|
<input class="d-psi" type="text" placeholder="🔍 Rezept suchen…" readonly/>
|
||||||
|
</div>
|
||||||
|
<div class="d-prsect">Empfohlen</div>
|
||||||
|
<div class="d-prec">
|
||||||
|
<div class="d-prname">Lachsfilet mit Gemüse</div>
|
||||||
|
<div class="d-prmeta">25 min · Einfach · Fisch</div>
|
||||||
|
<span class="d-prbadge">↑ +2 Punkte</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-prec">
|
||||||
|
<div class="d-prname">Mushroom Risotto</div>
|
||||||
|
<div class="d-prmeta">50 min · Mittel · Vegetarisch</div>
|
||||||
|
<span class="d-prbadge">↑ +2 Punkte</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-prec">
|
||||||
|
<div class="d-prname">Hähnchen-Curry</div>
|
||||||
|
<div class="d-prmeta">35 min · Einfach</div>
|
||||||
|
<span class="d-prbadge warn">⚠ Fr ebenfalls Hähnchen</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-prsect">Alle Rezepte</div>
|
||||||
|
<div class="d-prec"><div class="d-prname">Beef Bourguignon</div><div class="d-prmeta">2h 30 · Aufwendig</div></div>
|
||||||
|
<div class="d-prec"><div class="d-prname">Spaghetti Carbonara</div><div class="d-prmeta">20 min · Einfach</div></div>
|
||||||
|
<div class="d-prec"><div class="d-prname">Tomatensuppe</div><div class="d-prmeta">30 min · Vegetarisch</div></div>
|
||||||
|
<div class="d-prec"><div class="d-prname">Rindereintopf</div><div class="d-prmeta">1h 20 · Mittel</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid3">
|
||||||
|
<div class="note hl"><h4>Active empty tile</h4><p>Clicked empty slot: solid green border (replaces dashed), green-tint bg, green-dark "+" icon and "Wählen…" label. Provides clear visual anchor for which slot the panel is operating on.</p></div>
|
||||||
|
<div class="note"><h4>Panel header state</h4><p>"Sa, 5. April" in Fraunces 14px / "Rezept wählen" in 9px muted below. Close × returns panel to idle state. If a filled day was previously selected, × returns to that day's detail view.</p></div>
|
||||||
|
<div class="note"><h4>Clicking a recipe row</h4><p>Immediate PATCH to slot. Panel switches to the day-detail view for the newly filled slot. No undo toast needed on desktop — the panel immediately shows the result with a "Swap" option if the user wants to change it.</p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="agent">
|
||||||
|
<h4>C4 · Add meal from planner — implementation</h4>
|
||||||
|
<pre>/* TWO ENTRY POINTS:
|
||||||
|
* 1. "+" button in C1 nav → pre-selects next empty day in week (Mon–Sun scan).
|
||||||
|
* 2. Empty day slot chip (mobile) / empty tile (desktop) → pre-selects that date.
|
||||||
|
*
|
||||||
|
* MOBILE: bottom sheet slides up, planner dims to 30% opacity behind.
|
||||||
|
* Sheet: drag handle + {day label} header + × + search input + two sections.
|
||||||
|
* "Empfohlen" section: GET /api/suggestions?week={id}&day={date}
|
||||||
|
* → sorted by variety_delta DESC (unlike J4 which sorts by effort ASC).
|
||||||
|
* → 2–4 items. Badge: green "↑ +N Punkte" if delta > 0, yellow "⚠ {reason}" if ≤ 0.
|
||||||
|
* "Alle Rezepte": GET /api/recipes?sort=name — no badge.
|
||||||
|
* Search input: client-side filter of visible list. Does not re-sort.
|
||||||
|
* "+ Wählen" tap: PATCH /api/week-plan/{weekId}/slots/{date} {recipe_id}
|
||||||
|
* → dismiss sheet → undo toast 4s with "Rückgängig" link.
|
||||||
|
*
|
||||||
|
* DESKTOP: tap empty tile → detail panel enters recipe-picker state.
|
||||||
|
* Empty tile visual: solid green border, green-tint bg, "Wählen…" label.
|
||||||
|
* Panel state machine: idle | day-detail | recipe-picker | day-picker
|
||||||
|
* Clicking panel recipe row: PATCH → panel transitions to day-detail for that date.
|
||||||
|
* No undo toast on desktop (panel shows result immediately with Swap option). */</pre>
|
||||||
|
<table class="at"><thead><tr><th>Element</th><th>Value</th><th>Notes</th></tr></thead><tbody>
|
||||||
|
<tr class="grp"><td colspan="3">Mobile sheet</td></tr>
|
||||||
|
<tr><td>Sheet max-height</td><td>75vh</td><td>Drag to dismiss</td></tr>
|
||||||
|
<tr><td>Dim opacity</td><td>rgba(28,28,24,.4)</td><td>Same as J4</td></tr>
|
||||||
|
<tr><td>Suggestion sort</td><td>variety_delta DESC</td><td>Different from J4 (effort ASC)</td></tr>
|
||||||
|
<tr><td>Suggestion badge</td><td>8px, green-tint or yellow-tint</td><td>Only in Empfohlen section</td></tr>
|
||||||
|
<tr><td>Write action</td><td>PATCH + undo toast 4s</td><td>No confirmation dialog</td></tr>
|
||||||
|
<tr class="grp"><td colspan="3">Desktop panel</td></tr>
|
||||||
|
<tr><td>Active empty tile</td><td>solid green border, green-tint bg</td><td>Replaces dashed border</td></tr>
|
||||||
|
<tr><td>Panel width</td><td>216px (unchanged)</td><td>Same panel, different content state</td></tr>
|
||||||
|
<tr><td>Panel recipe click</td><td>PATCH → transition to day-detail</td><td>No toast needed</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ═══ C5: RECIPE QUICK ACTIONS ═══ -->
|
||||||
|
<div class="scr" id="c5">
|
||||||
|
<div class="scr-head"><h3>Recipe card — quick actions</h3><span class="scr-id">C5</span></div>
|
||||||
|
<div class="scr-desc">Recipe list cards (Recipes tab, B1) gain two quick action buttons below the tags row. "Jetzt kochen" navigates directly to J3 cook mode. "Zur Woche +" triggers the C6 day picker. Both buttons are always visible — no hover-only pattern, since touch-capable desktops don't have reliable hover.</div>
|
||||||
|
<div class="scr-var"><strong>V1 · Always-visible quick action row</strong> — mobile list and desktop grid</div>
|
||||||
|
|
||||||
|
<div class="previews">
|
||||||
|
<div class="prev-col">
|
||||||
|
<div class="bp-lbl">Mobile · Recipe list</div>
|
||||||
|
<div class="phone">
|
||||||
|
<div class="pst"><b>9:41</b><span>●●● WiFi 🔋</span></div>
|
||||||
|
<div class="pb">
|
||||||
|
<div style="padding:8px 14px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div style="font-family:var(--font-display);font-size:18px;font-weight:500;">Rezepte</div>
|
||||||
|
<div style="width:26px;height:26px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--color-text-muted);">+</div>
|
||||||
|
</div>
|
||||||
|
<div style="padding:6px 12px;border-bottom:1px solid var(--color-border);">
|
||||||
|
<input style="width:100%;font-family:var(--font-sans);font-size:11px;padding:6px 8px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text-muted);outline:none;" type="text" placeholder="🔍 Rezept suchen…" readonly/>
|
||||||
|
</div>
|
||||||
|
<div class="rc-list">
|
||||||
|
<div class="rc-card">
|
||||||
|
<div class="rc-name">Spaghetti Carbonara</div>
|
||||||
|
<div class="rc-tags"><span class="badge badge-m">20 min</span> <span class="badge badge-g">Einfach</span> <span class="badge badge-m">Nudeln</span></div>
|
||||||
|
<div class="rc-acts"><button class="rc-cook">🍳 Jetzt kochen</button><button class="rc-plan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="rc-card">
|
||||||
|
<div class="rc-name">Mushroom Risotto</div>
|
||||||
|
<div class="rc-tags"><span class="badge badge-m">50 min</span> <span class="badge badge-y">Mittel</span> <span class="badge badge-g">Vegetarisch</span></div>
|
||||||
|
<div class="rc-acts"><button class="rc-cook">🍳 Jetzt kochen</button><button class="rc-plan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="rc-card">
|
||||||
|
<div class="rc-name">Lachsfilet mit Gemüse</div>
|
||||||
|
<div class="rc-tags"><span class="badge badge-m">25 min</span> <span class="badge badge-g">Einfach</span> <span class="badge badge-g">Fisch</span></div>
|
||||||
|
<div class="rc-acts"><button class="rc-cook">🍳 Jetzt kochen</button><button class="rc-plan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mbt">
|
||||||
|
<div class="mt-i"><div class="mt-ic">📅</div><span class="mt-l">Planer</span></div>
|
||||||
|
<div class="mt-i a"><div class="mt-ic">📖</div><span class="mt-l">Rezepte</span></div>
|
||||||
|
<div class="mt-i"><div class="mt-ic">🛒</div><span class="mt-l">Einkauf</span></div>
|
||||||
|
<div class="mt-i"><div class="mt-ic">⚙️</div><span class="mt-l">Settings</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="prev-col">
|
||||||
|
<div class="bp-lbl">Desktop · Recipe grid</div>
|
||||||
|
<div class="desk" style="min-height:400px;">
|
||||||
|
<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 class="dsb-ni"><span class="dsb-nc">📅</span> Planer</div>
|
||||||
|
<div class="dsb-ni a"><span class="dsb-nc">📖</span> Rezepte</div>
|
||||||
|
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkauf</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-main">
|
||||||
|
<div style="padding:10px 18px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div style="font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;">Rezepte</div>
|
||||||
|
<div style="display:flex;gap:8px;align-items:center;">
|
||||||
|
<input style="font-family:var(--font-sans);font-size:11px;padding:5px 8px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text-muted);outline:none;width:160px;" type="text" placeholder="🔍 Suchen…" readonly/>
|
||||||
|
<button style="font-family:var(--font-sans);font-size:11px;font-weight:500;padding:5px 12px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;">+ Neu</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="flex:1;overflow-y:auto;">
|
||||||
|
<div class="d-rcgrid">
|
||||||
|
<div class="d-rccard">
|
||||||
|
<div class="d-rcname">Spaghetti Carbonara</div>
|
||||||
|
<div class="d-rcdesc">Cremige römische Pasta — kein Sahne, nur Ei und Guanciale.</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">20 min</span> <span class="badge badge-g">Einfach</span> <span class="badge badge-m">Nudeln</span></div>
|
||||||
|
<div class="d-rcacts"><button class="d-rccook">🍳 Jetzt kochen</button><button class="d-rcplan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-rccard">
|
||||||
|
<div class="d-rcname">Mushroom Risotto</div>
|
||||||
|
<div class="d-rcdesc">Cremiges Risotto mit Pilzen, Parmesan und frischem Thymian.</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">50 min</span> <span class="badge badge-y">Mittel</span> <span class="badge badge-g">Vegetarisch</span></div>
|
||||||
|
<div class="d-rcacts"><button class="d-rccook">🍳 Jetzt kochen</button><button class="d-rcplan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-rccard">
|
||||||
|
<div class="d-rcname">Lachsfilet mit Gemüse</div>
|
||||||
|
<div class="d-rcdesc">Knusprig gebratener Lachs auf Ofengemüse.</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">25 min</span> <span class="badge badge-g">Einfach</span> <span class="badge badge-g">Fisch</span></div>
|
||||||
|
<div class="d-rcacts"><button class="d-rccook">🍳 Jetzt kochen</button><button class="d-rcplan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid2" style="margin-top:16px;">
|
||||||
|
<div class="note hl">
|
||||||
|
<h4>Two actions, two visual weights</h4>
|
||||||
|
<p>"Jetzt kochen" is filled green (primary). "Zur Woche +" is green-tint bg / green-dark text / green-light border (secondary). Same green family — clearly related, but different priority. Both are 10px mobile / 11px desktop, weight 500, radius-md.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
<h4>Navigation targets</h4>
|
||||||
|
<p>"Jetzt kochen" → navigate to /cook/{recipeId} (J3, no sheet or confirmation). "Zur Woche +" → open C6 day picker (bottom sheet mobile, panel transformation desktop). The Recipes tab stays active.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="agent">
|
||||||
|
<h4>C5 · Recipe quick actions — implementation</h4>
|
||||||
|
<pre>/* Add two buttons to every recipe card in B1 (Recipes tab).
|
||||||
|
* Position: below the tags row, above any description/ingredients.
|
||||||
|
* "Jetzt kochen": navigate to /cook/{recipeId}. No confirmation. Primary style.
|
||||||
|
* "Zur Woche +": open C6 day-picker component. Secondary style.
|
||||||
|
* Both always visible — not hover-gated. Touch-capable desktops need always-visible actions.
|
||||||
|
* Mobile: equal-width flex row, font-size 10px, padding 5px 6px.
|
||||||
|
* Desktop grid: equal-width flex row, font-size 11px, padding 7px. */</pre>
|
||||||
|
<table class="at"><thead><tr><th>Token</th><th>Cook btn</th><th>Plan btn</th></tr></thead><tbody>
|
||||||
|
<tr><td>Background</td><td>var(--green)</td><td>var(--green-tint)</td></tr>
|
||||||
|
<tr><td>Text color</td><td>#fff</td><td>var(--green-dark)</td></tr>
|
||||||
|
<tr><td>Border</td><td>none</td><td>1px var(--green-light)</td></tr>
|
||||||
|
<tr><td>Font size mobile</td><td>10px</td><td>10px</td></tr>
|
||||||
|
<tr><td>Font size desktop</td><td>11px</td><td>11px</td></tr>
|
||||||
|
<tr><td>Radius</td><td>var(--radius-md)</td><td>var(--radius-md)</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ═══ C6: DAY PICKER ═══ -->
|
||||||
|
<div class="scr" id="c6">
|
||||||
|
<div class="scr-head"><h3>Day picker — add from recipe</h3><span class="scr-id">C6</span></div>
|
||||||
|
<div class="scr-desc">Entry: tap "Zur Woche +" on any recipe card (C5). Recipe is already known; user picks the target day. Mobile: compact bottom sheet (~55vh) with week strip. Desktop: detail panel transforms to day picker. Empty slots have dashed green border to invite selection. Selecting a filled slot shows an inline replace warning — no modal dialog.</div>
|
||||||
|
<div class="scr-var"><strong>V1 · Empty slot selected</strong> (green confirm) · <strong>V2 · Filled slot selected</strong> (orange replace confirm)</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Breakpoint 1 — Mobile · Both variants</div>
|
||||||
|
<div class="previews">
|
||||||
|
|
||||||
|
<!-- V1: empty slot -->
|
||||||
|
<div class="prev-col">
|
||||||
|
<div class="bp-lbl">V1 · Empty slot (Sa)</div>
|
||||||
|
<div class="phone">
|
||||||
|
<div class="pst"><b>9:41</b><span>●●● WiFi 🔋</span></div>
|
||||||
|
<div class="pb">
|
||||||
|
<div style="opacity:.28;">
|
||||||
|
<div style="padding:8px 14px;border-bottom:1px solid var(--color-border);font-family:var(--font-display);font-size:16px;font-weight:500;">Rezepte</div>
|
||||||
|
<div style="padding:8px 12px;">
|
||||||
|
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:9px 11px;margin-bottom:5px;font-family:var(--font-display);font-size:12px;">Spaghetti Carbonara</div>
|
||||||
|
<div style="background:var(--green-tint);border:2px solid var(--green);border-radius:var(--radius-lg);padding:9px 11px;font-family:var(--font-display);font-size:12px;">Mushroom Risotto</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-host">
|
||||||
|
<div class="sheet-bg"></div>
|
||||||
|
<div class="sheet" style="max-height:55%;">
|
||||||
|
<div class="sheet-handle"></div>
|
||||||
|
<div class="sheet-hd">
|
||||||
|
<div>
|
||||||
|
<div class="sheet-ht">Mushroom Risotto</div>
|
||||||
|
<div class="sheet-sub">Zu welchem Tag hinzufügen?</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-x">×</div>
|
||||||
|
</div>
|
||||||
|
<div style="padding:6px 12px 2px;display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<span style="font-size:10px;font-weight:500;color:var(--color-text);">31 März – 6 Apr</span>
|
||||||
|
<div style="display:flex;gap:3px;">
|
||||||
|
<span style="font-size:9px;padding:2px 5px;border-radius:3px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">‹</span>
|
||||||
|
<span style="font-size:9px;padding:2px 5px;border-radius:3px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dp-strip">
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Mo</span><span class="dp-cn">31</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled today"><span class="dp-ca">Di</span><span class="dp-cn">1</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Mi</span><span class="dp-cn">2</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Do</span><span class="dp-cn">3</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Fr</span><span class="dp-cn">4</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip sel-empty"><span class="dp-ca">Sa</span><span class="dp-cn">5</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">So</span><span class="dp-cn">6</span><div class="dp-dot"></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="dp-confirm">
|
||||||
|
<button class="dp-btn">Zu Samstag hinzufügen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- V2: filled slot -->
|
||||||
|
<div class="prev-col">
|
||||||
|
<div class="bp-lbl">V2 · Filled slot (Mi) — ersetzen?</div>
|
||||||
|
<div class="phone">
|
||||||
|
<div class="pst"><b>9:41</b><span>●●● WiFi 🔋</span></div>
|
||||||
|
<div class="pb">
|
||||||
|
<div style="opacity:.28;">
|
||||||
|
<div style="padding:8px 14px;border-bottom:1px solid var(--color-border);font-family:var(--font-display);font-size:16px;font-weight:500;">Rezepte</div>
|
||||||
|
<div style="padding:8px 12px;">
|
||||||
|
<div style="background:var(--green-tint);border:2px solid var(--green);border-radius:var(--radius-lg);padding:9px 11px;font-family:var(--font-display);font-size:12px;">Mushroom Risotto</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-host">
|
||||||
|
<div class="sheet-bg"></div>
|
||||||
|
<div class="sheet" style="max-height:60%;">
|
||||||
|
<div class="sheet-handle"></div>
|
||||||
|
<div class="sheet-hd">
|
||||||
|
<div>
|
||||||
|
<div class="sheet-ht">Mushroom Risotto</div>
|
||||||
|
<div class="sheet-sub">Zu welchem Tag hinzufügen?</div>
|
||||||
|
</div>
|
||||||
|
<div class="sheet-x">×</div>
|
||||||
|
</div>
|
||||||
|
<div style="padding:6px 12px 2px;display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<span style="font-size:10px;font-weight:500;color:var(--color-text);">31 März – 6 Apr</span>
|
||||||
|
<div style="display:flex;gap:3px;">
|
||||||
|
<span style="font-size:9px;padding:2px 5px;border-radius:3px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">‹</span>
|
||||||
|
<span style="font-size:9px;padding:2px 5px;border-radius:3px;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);">›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dp-strip">
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Mo</span><span class="dp-cn">31</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled today"><span class="dp-ca">Di</span><span class="dp-cn">1</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip sel-filled"><span class="dp-ca">Mi</span><span class="dp-cn">2</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Do</span><span class="dp-cn">3</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">Fr</span><span class="dp-cn">4</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip empty"><span class="dp-ca">Sa</span><span class="dp-cn">5</span><div class="dp-dot"></div></div>
|
||||||
|
<div class="dp-chip filled"><span class="dp-ca">So</span><span class="dp-cn">6</span><div class="dp-dot"></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="dp-warn">Ersetzt <strong>Tomaten-Pasta</strong> am Mittwoch. Undo möglich.</div>
|
||||||
|
<div class="dp-confirm">
|
||||||
|
<button class="dp-btn replace">Mittwoch ersetzen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display:flex;flex-direction:column;gap:12px;align-self:flex-start;max-width:220px;">
|
||||||
|
<div class="note hl">
|
||||||
|
<h4>Slot states</h4>
|
||||||
|
<p>Empty: dashed green-light border + green-tint bg (invites selection). Filled: solid color-border + surface bg + green dot. Today: yellow-tint border. Selected empty: 2px green-dark. Selected filled: 2px orange-dark + orange-tint → shows replace warning.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note warn">
|
||||||
|
<h4>No replace dialog</h4>
|
||||||
|
<p>The replace warning appears inline below the week strip. The confirm button turns orange. One tap replaces. An undo toast appears for 4 seconds. No modal dialog is shown — consistent with J4 swap.</p>
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
<h4>Week navigation</h4>
|
||||||
|
<p>‹ › buttons allow browsing to next/prev week if the current week has no empty slots. Default: shows current week.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Breakpoint 3 — Desktop · Panel day-picker mode</div>
|
||||||
|
<div style="overflow-x:auto;margin-bottom:20px;">
|
||||||
|
<div class="desk" style="min-height:440px;">
|
||||||
|
<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 class="dsb-ni"><span class="dsb-nc">📅</span> Planer</div>
|
||||||
|
<div class="dsb-ni a"><span class="dsb-nc">📖</span> Rezepte</div>
|
||||||
|
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkauf</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-main">
|
||||||
|
<div style="padding:10px 18px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div style="font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;">Rezepte</div>
|
||||||
|
<input style="font-family:var(--font-sans);font-size:11px;padding:5px 8px;border-radius:var(--radius-md);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text-muted);outline:none;width:160px;" type="text" placeholder="🔍 Suchen…" readonly/>
|
||||||
|
</div>
|
||||||
|
<div style="flex:1;display:flex;overflow:hidden;">
|
||||||
|
<!-- Recipe grid (dimmed, active card highlighted) -->
|
||||||
|
<div style="flex:1;overflow-y:auto;">
|
||||||
|
<div class="d-rcgrid">
|
||||||
|
<div class="d-rccard" style="opacity:.45;">
|
||||||
|
<div class="d-rcname">Spaghetti Carbonara</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">20 min</span> <span class="badge badge-g">Einfach</span></div>
|
||||||
|
<div class="d-rcacts"><button class="d-rccook">🍳 Kochen</button><button class="d-rcplan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-rccard" style="border:2px solid var(--green);background:var(--green-tint);">
|
||||||
|
<div class="d-rcname">Mushroom Risotto</div>
|
||||||
|
<div class="d-rcdesc">Cremiges Risotto mit Pilzen und Parmesan.</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">50 min</span> <span class="badge badge-y">Mittel</span> <span class="badge badge-g">Vegetarisch</span></div>
|
||||||
|
<div class="d-rcacts">
|
||||||
|
<button class="d-rccook">🍳 Kochen</button>
|
||||||
|
<button style="flex:1;font-family:var(--font-sans);font-size:11px;font-weight:500;padding:7px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;text-align:center;">📅 Tag wählen…</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-rccard" style="opacity:.45;">
|
||||||
|
<div class="d-rcname">Lachsfilet</div>
|
||||||
|
<div class="d-rctags"><span class="badge badge-m">25 min</span> <span class="badge badge-g">Einfach</span></div>
|
||||||
|
<div class="d-rcacts"><button class="d-rccook">🍳 Kochen</button><button class="d-rcplan">📅 Zur Woche +</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Detail panel: day picker mode -->
|
||||||
|
<div class="d-dp">
|
||||||
|
<div class="d-dph">
|
||||||
|
<div><div class="d-dpd">Mushroom Risotto</div><div class="d-dpdt">Tag für diese Woche wählen</div></div>
|
||||||
|
<div class="d-dpx">×</div>
|
||||||
|
</div>
|
||||||
|
<!-- Mini week strip in panel -->
|
||||||
|
<div style="padding:8px 10px 4px;">
|
||||||
|
<div style="font-size:9px;font-weight:500;color:var(--color-text-muted);margin-bottom:5px;">31 März – 6 Apr</div>
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(7,1fr);gap:3px;">
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Mo</span><span style="font-size:9px;font-weight:500;">31</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--yellow);background:var(--yellow-tint);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--yellow-text);">Di</span><span style="font-size:9px;font-weight:500;">1</span><div style="width:3px;height:3px;border-radius:50%;background:var(--yellow-text);margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Mi</span><span style="font-size:9px;font-weight:500;">2</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Do</span><span style="font-size:9px;font-weight:500;">3</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">Fr</span><span style="font-size:9px;font-weight:500;">4</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:2px solid var(--green-dark);background:var(--green-tint);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--green-deeper);">Sa</span><span style="font-size:9px;font-weight:500;">5</span><div style="width:3px;height:3px;border-radius:50%;background:transparent;margin-top:1px;"></div></div>
|
||||||
|
<div style="display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 2px;border-radius:4px;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;"><span style="font-size:6px;font-weight:500;text-transform:uppercase;color:var(--color-text-muted);">So</span><span style="font-size:9px;font-weight:500;">6</span><div style="width:3px;height:3px;border-radius:50%;background:var(--green);margin-top:1px;"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Selected day + confirm -->
|
||||||
|
<div style="padding:6px 10px;border-top:1px solid var(--color-subtle);">
|
||||||
|
<div style="font-size:9px;color:var(--color-text-muted);margin-bottom:5px;">Samstag, 5. April · leer</div>
|
||||||
|
<button style="width:100%;font-family:var(--font-sans);font-size:11px;font-weight:500;padding:7px;border-radius:var(--radius-md);background:var(--green);color:#fff;border:none;text-align:center;">Zu Samstag hinzufügen</button>
|
||||||
|
</div>
|
||||||
|
<!-- Variety preview (desktop only) -->
|
||||||
|
<div style="padding:8px 10px;border-top:1px solid var(--color-subtle);">
|
||||||
|
<div style="font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:5px;">Variety-Vorschau</div>
|
||||||
|
<div style="background:var(--green-tint);border:1px solid var(--green-light);border-radius:var(--radius-md);padding:6px 8px;font-size:10px;color:var(--green-dark);">↑ Score: 8 → 9 · Neues Protein</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid3">
|
||||||
|
<div class="note hl"><h4>Active card highlight</h4><p>The card whose day picker is open: 2px green border, green-tint bg, "Zur Woche +" button becomes green filled "Tag wählen…". Other cards at 45% opacity to keep focus on the active recipe.</p></div>
|
||||||
|
<div class="note"><h4>Variety preview (desktop only)</h4><p>Below the confirm button the panel shows the projected score change and reason: "↑ Score: 8 → 9 · Neues Protein". Omitted on mobile to keep the sheet compact. Calls GET /api/variety/preview?add={recipeId}&date={date}.</p></div>
|
||||||
|
<div class="note warn"><h4>Replace on desktop</h4><p>Same V2 pattern: clicking a filled day chip turns the confirm button orange and shows inline warning "Ersetzt [recipe] am [day]." Panel width is enough to show both elements without overlap.</p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="agent">
|
||||||
|
<h4>C6 · Day picker — implementation</h4>
|
||||||
|
<pre>/* Entry: tap "Zur Woche +" on recipe card. Recipe ID is known; date is unknown.
|
||||||
|
* Mobile: compact bottom sheet (~55vh). Background: recipe list at 28% opacity.
|
||||||
|
* Sheet: drag handle + recipe name header + week label + ‹ › week nav + 7-day strip + confirm.
|
||||||
|
*
|
||||||
|
* DAY CHIP STATES (7 chips, current week):
|
||||||
|
* .empty → dashed green-light border, green-tint bg (invite selection)
|
||||||
|
* .filled → solid color-border, surface bg, green dot below date number
|
||||||
|
* .today → solid yellow border, yellow-tint bg, yellow-text label
|
||||||
|
* .sel-empty → 2px green-dark border, green-tint bg → confirm btn = green
|
||||||
|
* .sel-filled → 2px orange-dark border, orange-tint bg → show dp-warn → confirm btn = orange
|
||||||
|
*
|
||||||
|
* Confirm empty: PATCH /api/week-plan/{weekId}/slots/{date} {recipe_id}
|
||||||
|
* → dismiss sheet → undo toast 4s "Rückgängig"
|
||||||
|
* Confirm filled: same PATCH (server replaces existing recipe_id)
|
||||||
|
* → dismiss sheet → undo toast 4s "Rückgängig"
|
||||||
|
*
|
||||||
|
* Desktop panel state: 'day-picker'
|
||||||
|
* Active recipe card: 2px green border, green-tint bg, button text "Tag wählen…" (green filled)
|
||||||
|
* Other cards: opacity 0.45
|
||||||
|
* Panel adds variety-preview section below confirm: GET /api/variety/preview?add={id}&date={date}
|
||||||
|
* Confirm → panel transitions to day-detail for newly filled date.
|
||||||
|
*
|
||||||
|
* Week navigation: ‹ › loads prev/next week's slots from GET /api/week-plan/{weekId±1}
|
||||||
|
* Default: current week. If current week fully filled, auto-advance to next week. */</pre>
|
||||||
|
<table class="at"><thead><tr><th>State</th><th>Border</th><th>Background</th><th>Confirm btn</th></tr></thead><tbody>
|
||||||
|
<tr><td>empty</td><td>dashed green-light</td><td>green-tint</td><td>—</td></tr>
|
||||||
|
<tr><td>filled</td><td>solid color-border</td><td>color-surface</td><td>—</td></tr>
|
||||||
|
<tr><td>today</td><td>solid yellow</td><td>yellow-tint</td><td>—</td></tr>
|
||||||
|
<tr><td>sel-empty</td><td>2px green-dark</td><td>green-tint</td><td>green</td></tr>
|
||||||
|
<tr><td>sel-filled</td><td>2px orange-dark</td><td>orange-tint</td><td>orange + dp-warn</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ═══ LLM INSTRUCTIONS ═══ -->
|
||||||
|
<div class="llm">
|
||||||
|
<h2>LLM Implementation Notes — J2 Add to Plan (C4–C6)</h2>
|
||||||
|
|
||||||
|
<h3>1. Screens and entry points</h3>
|
||||||
|
<p><strong>C4</strong>: User knows the day, not the recipe. Entry: "+" or empty slot tap in C1. <strong>C5</strong>: Recipe card in B1 gains two quick action buttons. <strong>C6</strong>: User knows the recipe, not the day. Entry: "Zur Woche +" on C5 card. All three flows share the same backend write: <code>PATCH /api/week-plan/{weekId}/slots/{date} { recipe_id }</code>.</p>
|
||||||
|
|
||||||
|
<h3>2. C4 vs J4 — different sort, same sheet pattern</h3>
|
||||||
|
<p>Both use a bottom sheet over dimmed content. The difference: J4 swap suggestions are sorted <strong>effort ASC</strong> (easiest first, because mid-week changes happen under stress). C4 suggestions are sorted <strong>variety_delta DESC</strong> (best variety impact first, because this is deliberate weekly planning).</p>
|
||||||
|
|
||||||
|
<h3>3. Panel state machine (desktop)</h3>
|
||||||
|
<p>The 216px right panel can be in four states: <strong>idle</strong> (no selection) → <strong>day-detail</strong> (filled day selected in C1) → <strong>recipe-picker</strong> (C4 mode) → <strong>day-picker</strong> (C6 mode). The "×" close button always returns to the previous state. Successful pick transitions to day-detail for the affected date.</p>
|
||||||
|
|
||||||
|
<h3>4. Tap counts</h3>
|
||||||
|
<ul>
|
||||||
|
<li><strong>C4 via empty slot:</strong> 2 taps (slot → pick recipe)</li>
|
||||||
|
<li><strong>C4 via "+" button:</strong> 2 taps ("+" → pick recipe, day pre-selected as next empty)</li>
|
||||||
|
<li><strong>C6 empty slot:</strong> 2 taps ("Zur Woche +" → pick day)</li>
|
||||||
|
<li><strong>C6 filled slot:</strong> 3 taps ("Zur Woche +" → pick day → confirm replace)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>5. Undo</h3>
|
||||||
|
<p>All flows use <code>DELETE /api/week-plan/{weekId}/slots/{date}</code> when "Rückgängig" is tapped in the 4-second toast. Toast is dismissed on navigation. On desktop, no toast for C4 (panel shows result immediately with Swap option in the day-detail view).</p>
|
||||||
|
|
||||||
|
<h3>6. C5 "Jetzt kochen" — no back-stack issue</h3>
|
||||||
|
<p>Navigating to <code>/cook/{recipeId}</code> from the recipe list is a standard route push. The recipe list is available via the back button or bottom nav. Do not open cook mode in a sheet or modal — it is a full-screen experience per J3 spec.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user