- Store hero image as base64 data URI in text column (V023 migration) - Add file upload UI to RecipeForm with FileReader preview - Remove isChildFriendly from RecipeCreateRequest (no form field) - Fix 500 on save: effort values now lowercase, serves/cookTimeMin changed from primitive short to nullable Integer to survive omitted fields - Fix empty categories panel: removed stale tagType=category filter - Group category tags by type with German headings in recipe form - Split SuggestionResponse.SuggestionRecipe (no image) from SlotRecipe - Seed 11 HelloFresh recipes with ingredients, steps and tags (V101) - Add frontend e2e scaffold, specs and dev yml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
774 lines
38 KiB
HTML
774 lines
38 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Planner — Full-Bleed Tiles</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@300;400&family=DM+Sans:wght@400;500;600&family=DM+Mono&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root {
|
||
--page: #fafaf7;
|
||
--surface: #f5f4ee;
|
||
--subtle: #edecea;
|
||
--border: #d8d7d0;
|
||
--text: #1c1c18;
|
||
--muted: #6b6a63;
|
||
--gt: #e8f5ea; --gl: #aedcb0; --g: #3d8c4a; --gd: #2e6e39;
|
||
--yt: #fdf6d8; --yl: #f9e08a; --y: #f2c12e; --yx: #8a6800;
|
||
--pt: #eeedfe; --p: #534ab7;
|
||
--ot: #fef0e6; --od: #b46820;
|
||
--err: #dc4c3e;
|
||
--r-sm: 4px; --r-md: 6px; --r-lg: 10px; --r-xl: 16px; --r-full: 9999px;
|
||
--sh-card: 0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);
|
||
--sh-raised: 0 6px 18px rgba(28,28,24,.14),0 2px 6px rgba(28,28,24,.08);
|
||
--fd: 'Fraunces', Georgia, serif;
|
||
--fs: 'DM Sans', system-ui, sans-serif;
|
||
--fm: 'DM Mono', monospace;
|
||
}
|
||
*{box-sizing:border-box;margin:0;padding:0;}
|
||
body{font-family:var(--fs);background:#dddcd7;color:var(--text);padding:40px 24px 80px;line-height:1.4;}
|
||
|
||
.eyebrow{font-family:var(--fs);font-size:11px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;}
|
||
.title{font-family:var(--fd);font-size:34px;font-weight:300;margin-bottom:6px;}
|
||
.sub{font-family:var(--fs);font-size:14px;color:var(--muted);max-width:700px;line-height:1.65;margin-bottom:44px;}
|
||
|
||
.block{margin-bottom:56px;}
|
||
.block-label{display:flex;align-items:baseline;gap:10px;margin-bottom:12px;}
|
||
.bl-num{font-family:var(--fm);font-size:11px;background:var(--subtle);color:var(--muted);padding:3px 8px;border-radius:var(--r-sm);}
|
||
.bl-name{font-family:var(--fd);font-size:22px;font-weight:300;}
|
||
.bl-when{font-family:var(--fs);font-size:12px;color:var(--muted);margin-left:auto;}
|
||
.note{font-family:var(--fs);font-size:12px;color:var(--muted);border-left:3px solid var(--border);padding:10px 14px;margin-top:14px;line-height:1.6;}
|
||
.note strong{color:var(--text);font-weight:500;}
|
||
|
||
/* ── Desktop frame ─── */
|
||
.frame{display:flex;flex-direction:column;background:var(--page);border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-raised);}
|
||
.tb{display:flex;align-items:center;gap:7px;padding:11px 18px;border-bottom:1px solid var(--border);background:var(--page);flex-shrink:0;}
|
||
.tb-h1{font-family:var(--fd);font-size:17px;font-weight:300;}
|
||
.tb-range{font-family:var(--fs);font-size:11px;color:var(--muted);}
|
||
.tb-arr{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:var(--r-md);font-size:13px;color:var(--muted);}
|
||
.tb-btn{height:28px;padding:0 10px;border:1px solid var(--border);border-radius:var(--r-md);font-family:var(--fs);font-size:11px;font-weight:500;letter-spacing:.04em;color:var(--text);background:var(--page);}
|
||
.tb-ml{margin-left:auto;}
|
||
.tb-pri{background:var(--gd);color:#fff;border:none;}
|
||
.body{display:flex;flex:1;overflow:hidden;}
|
||
|
||
/* Sidebar */
|
||
.sb{width:184px;flex-shrink:0;border-right:1px solid var(--border);background:var(--surface);padding:13px;display:flex;flex-direction:column;gap:13px;}
|
||
.sb-lbl{font-family:var(--fs);font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:5px;}
|
||
.score-box{background:var(--yt);border:1px solid var(--yl);border-radius:var(--r-md);padding:10px;}
|
||
.sc-big{font-family:var(--fd);font-size:27px;font-weight:300;line-height:1;}
|
||
.sc-den{font-family:var(--fs);font-size:11px;color:var(--muted);}
|
||
.pbar{height:4px;border-radius:var(--r-full);overflow:hidden;margin-top:6px;}
|
||
.pb-y{background:var(--yl);} .pb-t{background:var(--border);}
|
||
.pb-fill{height:100%;border-radius:var(--r-full);}
|
||
.pb-fg-y{background:var(--y);} .pb-fg-g{background:var(--g);}
|
||
.sr{display:flex;align-items:center;gap:6px;margin-top:6px;}
|
||
.sr-l{font-family:var(--fs);font-size:10px;color:var(--muted);width:68px;flex-shrink:0;}
|
||
.sr-b{flex:1;height:3px;border-radius:var(--r-full);background:var(--border);overflow:hidden;}
|
||
.sr-f{height:100%;border-radius:var(--r-full);}
|
||
.sr-v{font-family:var(--fm);font-size:9px;color:var(--muted);width:18px;text-align:right;}
|
||
.w-item{font-family:var(--fs);font-size:10px;color:var(--yx);margin-top:4px;line-height:1.4;}
|
||
.dp{display:flex;gap:2px;margin-top:5px;}
|
||
.dp-s{flex:1;height:4px;border-radius:var(--r-full);}
|
||
.sb-link{font-family:var(--fs);font-size:10px;font-weight:500;color:var(--yx);display:block;margin-top:8px;}
|
||
|
||
/* Right panel */
|
||
.rp{width:228px;flex-shrink:0;border-left:1px solid var(--border);background:var(--page);padding:13px;display:flex;flex-direction:column;overflow-y:auto;}
|
||
.rp-lbl{font-family:var(--fs);font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:7px;}
|
||
.rp-btn{display:block;width:100%;padding:7px;border-radius:var(--r-md);border:1px solid var(--border);background:var(--page);font-family:var(--fs);font-size:11px;font-weight:500;letter-spacing:.04em;text-align:center;color:var(--text);margin-top:5px;}
|
||
.rp-pri{background:var(--gd);color:#fff;border:none;}
|
||
.rp-err{color:var(--err);border-color:var(--err);background:transparent;}
|
||
.hr{height:1px;background:var(--border);margin:10px 0;}
|
||
.picker-search{display:flex;align-items:center;gap:6px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);padding:6px 9px;margin-bottom:9px;}
|
||
.pick-item{display:flex;align-items:center;gap:7px;padding:7px 0;border-bottom:1px solid var(--subtle);cursor:pointer;}
|
||
.pick-item:last-child{border-bottom:none;}
|
||
.pick-name{font-family:var(--fd);font-size:12px;font-weight:300;flex:1;line-height:1.3;}
|
||
.pick-meta{font-family:var(--fs);font-size:10px;color:var(--muted);}
|
||
.pick-top{font-family:var(--fm);font-size:9px;background:var(--gt);color:var(--gd);padding:2px 5px;border-radius:2px;}
|
||
|
||
/* Main */
|
||
.main{flex:1;overflow-y:auto;padding:12px;}
|
||
|
||
/* ════════════════════════════════════════════
|
||
FULL-BLEED TILE SYSTEM
|
||
════════════════════════════════════════════ */
|
||
.grid7{display:grid;grid-template-columns:repeat(7,1fr);gap:7px;}
|
||
|
||
/* The tile is a positioned container — image is the background */
|
||
.tile{
|
||
position:relative;
|
||
border-radius:var(--r-lg);
|
||
overflow:hidden;
|
||
cursor:pointer;
|
||
box-shadow:var(--sh-card);
|
||
transition:box-shadow .15s, transform .1s;
|
||
/* Image fills entire tile */
|
||
background-size:cover;
|
||
background-position:center;
|
||
}
|
||
.tile:hover{box-shadow:var(--sh-raised);transform:translateY(-1px);}
|
||
|
||
/* State borders — use box-shadow to avoid layout shift with border:2px */
|
||
.tile-default{}
|
||
.tile-today{box-shadow:0 0 0 2px var(--y), var(--sh-card);}
|
||
.tile-today:hover{box-shadow:0 0 0 2px var(--y), var(--sh-raised);}
|
||
.tile-sel{box-shadow:0 0 0 2px var(--g), var(--sh-raised);}
|
||
.tile-faded{opacity:.42;pointer-events:none;}
|
||
|
||
/* Full-height gradient overlay: dark at bottom for text, subtle at top for day label */
|
||
.tile-overlay{
|
||
position:absolute;inset:0;
|
||
background:
|
||
linear-gradient(to bottom,
|
||
rgba(0,0,0,.32) 0%,
|
||
rgba(0,0,0,0) 30%,
|
||
rgba(0,0,0,0) 45%,
|
||
rgba(0,0,0,.55) 100%
|
||
);
|
||
border-radius:inherit;
|
||
}
|
||
|
||
/* Day header — top of tile, over image */
|
||
.tile-head{
|
||
position:absolute;top:0;left:0;right:0;
|
||
display:flex;align-items:center;justify-content:space-between;
|
||
padding:7px 8px;
|
||
z-index:2;
|
||
}
|
||
.tile-day-abbr{
|
||
font-family:var(--fs);font-size:9px;text-transform:uppercase;
|
||
letter-spacing:.06em;color:rgba(255,255,255,.85);font-weight:500;
|
||
}
|
||
.tile-day-num{
|
||
width:20px;height:20px;border-radius:var(--r-full);
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-family:var(--fs);font-size:10px;font-weight:500;
|
||
color:rgba(255,255,255,.9);
|
||
background:rgba(255,255,255,.22);
|
||
}
|
||
.dn-today{background:var(--y) !important;color:#fff !important;}
|
||
.dn-sel{background:var(--g) !important;color:#fff !important;}
|
||
|
||
/* Recipe info — bottom of tile, over image */
|
||
.tile-info{
|
||
position:absolute;bottom:0;left:0;right:0;
|
||
padding:8px 9px 9px;
|
||
z-index:2;
|
||
}
|
||
.tile-name{
|
||
font-family:var(--fd);font-size:13px;font-weight:300;
|
||
color:#fff;line-height:1.3;
|
||
text-shadow:0 1px 3px rgba(0,0,0,.4);
|
||
}
|
||
.tile-meta{
|
||
font-family:var(--fs);font-size:10px;
|
||
color:rgba(255,255,255,.75);
|
||
margin-top:2px;
|
||
}
|
||
.tile-tags{display:flex;gap:3px;flex-wrap:wrap;margin-top:5px;}
|
||
.tag{
|
||
font-family:var(--fs);font-size:8px;font-weight:500;
|
||
padding:2px 5px;border-radius:2px;
|
||
background:rgba(255,255,255,.2);
|
||
color:rgba(255,255,255,.92);
|
||
backdrop-filter:blur(2px);
|
||
}
|
||
/* State-specific tag tints */
|
||
.tag-today{background:rgba(242,193,46,.35);}
|
||
.tag-sel{background:rgba(61,140,74,.45);}
|
||
|
||
/* ── EMPTY TILE ────────────────────────────── */
|
||
/* Empty tile: no image, dashed border, suggestion list fills height */
|
||
.tile-empty{
|
||
border-radius:var(--r-lg);
|
||
border:1.5px dashed var(--border);
|
||
background:var(--surface);
|
||
cursor:pointer;
|
||
display:flex;flex-direction:column;
|
||
overflow:hidden;
|
||
box-shadow:var(--sh-card);
|
||
}
|
||
.tile-empty-sel{
|
||
border:2px dashed var(--g);
|
||
background:rgba(232,245,234,.5);
|
||
}
|
||
.tile-empty-faded{opacity:.3;pointer-events:none;}
|
||
|
||
.empty-head{
|
||
display:flex;align-items:center;justify-content:space-between;
|
||
padding:7px 8px 0;flex-shrink:0;
|
||
}
|
||
.empty-day-abbr{font-family:var(--fs);font-size:9px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);}
|
||
.empty-day-num{font-family:var(--fs);font-size:10px;font-weight:500;color:var(--muted);}
|
||
|
||
.empty-cta{
|
||
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||
padding:8px 6px 6px;
|
||
gap:2px;flex-shrink:0;
|
||
border-bottom:1px solid var(--border);
|
||
}
|
||
.empty-plus{font-size:18px;color:var(--border);}
|
||
.empty-label{font-family:var(--fs);font-size:9px;color:var(--muted);}
|
||
.empty-sel-label{color:var(--gd);}
|
||
.empty-arr{font-size:9px;color:var(--gd);margin-top:1px;}
|
||
|
||
/* Inline suggestion list */
|
||
.sug-list{
|
||
display:flex;flex-direction:column;
|
||
padding:5px 7px 6px;flex:1;overflow:hidden;
|
||
}
|
||
.sug-hd{
|
||
font-family:var(--fs);font-size:8px;font-weight:500;
|
||
letter-spacing:.07em;text-transform:uppercase;
|
||
color:var(--muted);padding:3px 0 5px;
|
||
border-bottom:1px solid var(--subtle);
|
||
margin-bottom:2px;
|
||
}
|
||
.sug-row{
|
||
display:flex;align-items:center;gap:4px;
|
||
padding:5px 0;border-bottom:1px solid var(--subtle);
|
||
cursor:pointer;
|
||
}
|
||
.sug-row:last-of-type{border-bottom:none;}
|
||
.sug-row:hover .sug-name{color:var(--gd);}
|
||
.sug-name{font-family:var(--fd);font-size:11px;font-weight:300;color:var(--text);flex:1;line-height:1.2;}
|
||
.sug-tag{
|
||
font-family:var(--fs);font-size:8px;font-weight:500;
|
||
padding:1px 4px;border-radius:2px;white-space:nowrap;flex-shrink:0;
|
||
}
|
||
.st-g{background:var(--gt);color:var(--gd);}
|
||
.st-y{background:var(--yt);color:var(--yx);}
|
||
.sug-more{
|
||
font-family:var(--fs);font-size:9px;font-weight:500;
|
||
color:var(--yx);text-align:center;padding-top:5px;margin-top:auto;
|
||
}
|
||
|
||
/* ── EXPANSION ─────────────────────────────── */
|
||
.expand-wrap{position:relative;margin-top:3px;}
|
||
.exp-arrows{
|
||
display:grid;grid-template-columns:repeat(7,1fr);gap:7px;
|
||
position:absolute;top:-8px;left:0;right:0;pointer-events:none;
|
||
}
|
||
.exp-arr{display:flex;justify-content:center;}
|
||
.arr{width:12px;height:12px;border-left:2px solid var(--g);border-top:2px solid var(--g);transform:rotate(45deg);}
|
||
.arr-fill{background:var(--gt);}
|
||
.arr-empty{background:rgba(232,245,234,.5);}
|
||
.expand{
|
||
border:2px solid var(--g);border-radius:var(--r-lg);
|
||
background:var(--gt);padding:14px;display:flex;gap:14px;
|
||
}
|
||
.exp-left{flex:1;}
|
||
.exp-ctx{font-family:var(--fs);font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--gd);margin-bottom:4px;}
|
||
.exp-name{font-family:var(--fd);font-size:22px;font-weight:300;line-height:1.25;}
|
||
.exp-meta{font-family:var(--fs);font-size:12px;color:var(--muted);margin-top:4px;}
|
||
.ing-wrap{display:flex;flex-wrap:wrap;gap:4px;margin-top:10px;}
|
||
.ing{font-family:var(--fs);font-size:10px;background:#fff;border:1px solid var(--border);border-radius:var(--r-full);padding:2px 8px;color:var(--text);}
|
||
.ing-s{background:var(--subtle);border-color:var(--subtle);color:var(--muted);}
|
||
.exp-bdgs{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;}
|
||
.ebdg{font-family:var(--fs);font-size:10px;font-weight:500;padding:3px 7px;border-radius:2px;}
|
||
.ebdg-e{background:var(--gt);color:var(--gd);}
|
||
.ebdg-p{background:var(--pt);color:var(--p);}
|
||
.ebdg-sc{background:var(--gt);color:var(--gd);}
|
||
.exp-right{display:flex;flex-direction:column;gap:5px;width:116px;flex-shrink:0;}
|
||
.exp-btn{padding:7px;border-radius:var(--r-md);border:1px solid var(--border);background:#fff;font-family:var(--fs);font-size:11px;font-weight:500;text-align:center;cursor:pointer;letter-spacing:.04em;}
|
||
.exp-pri{background:var(--gd);color:#fff;border:none;}
|
||
.exp-err{color:var(--err);border-color:var(--err);background:transparent;}
|
||
|
||
/* Right panel: idle today card */
|
||
.today-card{background:var(--yt);border:1px solid var(--yl);border-radius:var(--r-md);padding:10px;margin-bottom:10px;}
|
||
.tc-lbl{font-family:var(--fs);font-size:9px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--yx);margin-bottom:4px;}
|
||
.tc-name{font-family:var(--fd);font-size:14px;font-weight:300;line-height:1.3;}
|
||
.tc-meta{font-family:var(--fs);font-size:10px;color:var(--muted);margin-top:2px;}
|
||
|
||
/* ── CLOSE-UP SPECIMENS ─────────────────────── */
|
||
.specimen-row{display:flex;gap:14px;margin-bottom:32px;flex-wrap:wrap;}
|
||
.specimen{flex-shrink:0;}
|
||
.specimen-label{font-family:var(--fs);font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-bottom:6px;text-align:center;}
|
||
|
||
/* Image colour palettes for each recipe (placeholder for heroImageUrl) */
|
||
.img-curry{background:linear-gradient(160deg,#d4923a 0%,#a85e1a 40%,#7a3d0c 100%);}
|
||
.img-pasta{background:linear-gradient(160deg,#c04545 0%,#8b2020 40%,#5a1010 100%);}
|
||
.img-stirfry{background:linear-gradient(160deg,#5fa85e 0%,#2e7031 40%,#1a4a1e 100%);}
|
||
.img-lachs{background:linear-gradient(160deg,#5b9fd4 0%,#2868a0 40%,#10406e 100%);}
|
||
.img-pizza{background:linear-gradient(160deg,#d4a832 0%,#a07010 40%,#6e4a00 100%);}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<p class="eyebrow">Mealplan · Planer · Full-Bleed Tiles</p>
|
||
<h1 class="title">Vollflächige Kacheln</h1>
|
||
<p class="sub">
|
||
Das Bild füllt die gesamte Kachelhöhe. Text und Tags werden über einen Gradienten am unteren Rand eingeblendet.
|
||
Kein leerer Bereich mehr — jeder Pixel der Kachel ist Bild.
|
||
Leere Kacheln behalten die Vorschlagsliste von innen.
|
||
</p>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<!-- CLOSE-UP: Tile variants -->
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<div class="block">
|
||
<div class="block-label">
|
||
<span class="bl-num">Nahaufnahme</span>
|
||
<span class="bl-name">Kachel-Varianten</span>
|
||
</div>
|
||
|
||
<div class="specimen-row">
|
||
|
||
<!-- Filled: default -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Gefüllt — Standard</div>
|
||
<div class="tile img-curry" style="width:140px;height:220px;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head">
|
||
<span class="tile-day-abbr">Mo</span>
|
||
<span class="tile-day-num">7</span>
|
||
</div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Hähnchen-Curry</div>
|
||
<div class="tile-meta">35 Min · mittel</div>
|
||
<div class="tile-tags">
|
||
<span class="tag">Hähnchen</span>
|
||
<span class="tag">4 Port.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Filled: today -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Gefüllt — Heute</div>
|
||
<div class="tile tile-today img-pasta" style="width:140px;height:220px;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head">
|
||
<span class="tile-day-abbr">Di</span>
|
||
<span class="tile-day-num dn-today">8</span>
|
||
</div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Pasta Bolognese</div>
|
||
<div class="tile-meta">45 Min · mittel</div>
|
||
<div class="tile-tags">
|
||
<span class="tag tag-today">Rind</span>
|
||
<span class="tag tag-today">4 Port.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Filled: selected -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Gefüllt — Ausgewählt</div>
|
||
<div class="tile tile-sel img-stirfry" style="width:140px;height:220px;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head">
|
||
<span class="tile-day-abbr">Mi</span>
|
||
<span class="tile-day-num dn-sel">9</span>
|
||
</div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Gemüse-Stir-fry</div>
|
||
<div class="tile-meta">20 Min · einfach</div>
|
||
<div class="tile-tags">
|
||
<span class="tag tag-sel">Tofu</span>
|
||
<span class="tag tag-sel">2 Port.</span>
|
||
</div>
|
||
<div style="text-align:center;font-size:9px;color:rgba(255,255,255,.7);margin-top:4px;">▼</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Filled: faded -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Gefüllt — Gedimmt</div>
|
||
<div class="tile tile-faded img-lachs" style="width:140px;height:220px;pointer-events:auto;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head">
|
||
<span class="tile-day-abbr">Do</span>
|
||
<span class="tile-day-num">10</span>
|
||
</div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Lachs mit Kartoffeln</div>
|
||
<div class="tile-meta">30 Min · einfach</div>
|
||
<div class="tile-tags"><span class="tag">Fisch</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Empty with suggestions -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Leer — Vorschläge</div>
|
||
<div class="tile-empty" style="width:140px;height:220px;">
|
||
<div class="empty-head">
|
||
<span class="empty-day-abbr">Sa</span>
|
||
<span class="empty-day-num">12</span>
|
||
</div>
|
||
<div class="empty-cta">
|
||
<div class="empty-plus">+</div>
|
||
<div class="empty-label">Gericht wählen</div>
|
||
</div>
|
||
<div class="sug-list">
|
||
<div class="sug-hd">Vorschläge</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Ramen mit Ei</span>
|
||
<span class="sug-tag st-g">Neu</span>
|
||
</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Shakshuka</span>
|
||
<span class="sug-tag st-g">Kein Overlap</span>
|
||
</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Tacos</span>
|
||
<span class="sug-tag st-y">Leicht</span>
|
||
</div>
|
||
<div class="sug-more">Alle →</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Empty selected -->
|
||
<div class="specimen">
|
||
<div class="specimen-label">Leer — Ausgewählt</div>
|
||
<div class="tile-empty tile-empty-sel" style="width:140px;height:220px;">
|
||
<div class="empty-head">
|
||
<span class="empty-day-abbr" style="color:var(--gd);">Sa</span>
|
||
<span class="empty-day-num" style="color:var(--gd);">12</span>
|
||
</div>
|
||
<div class="empty-cta" style="border-bottom-color:var(--gl);">
|
||
<div class="empty-plus" style="color:var(--gl);">+</div>
|
||
<div class="empty-label empty-sel-label">Gericht wählen</div>
|
||
<div class="empty-arr">▼</div>
|
||
</div>
|
||
<div class="sug-list">
|
||
<div class="sug-hd">Vorschläge</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Ramen mit Ei</span>
|
||
<span class="sug-tag st-g">Neu</span>
|
||
</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Shakshuka</span>
|
||
<span class="sug-tag st-g">Kein Overlap</span>
|
||
</div>
|
||
<div class="sug-row">
|
||
<span class="sug-name">Tacos</span>
|
||
<span class="sug-tag st-y">Leicht</span>
|
||
</div>
|
||
<div class="sug-more">Alle →</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="note">
|
||
<strong>Gradient-Overlay:</strong> Dunkel oben (30% → 0%) für den Tages-Header, dunkel unten (0% → 55%) für den Text.
|
||
Der mittlere Bereich ist transparent — das Bild ist klar zu sehen.
|
||
Text-Shadow auf dem Rezeptnamen sichert Lesbarkeit auch bei hellen Bildern.
|
||
Tags nutzen <code>rgba(255,255,255,.2)</code> als Glasmorphismus-Hintergrund.
|
||
Zustands-Borders werden per <code>box-shadow</code> umgesetzt (kein Layout-Shift durch border:2px).
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<!-- ZUSTAND 1 — VOLLSTÄNDIGE SEITENANSICHT -->
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<div class="block">
|
||
<div class="block-label">
|
||
<span class="bl-num">01</span>
|
||
<span class="bl-name">Kein Tag ausgewählt — volle Seite</span>
|
||
<span class="bl-when">Kacheln füllen die Viewport-Höhe komplett</span>
|
||
</div>
|
||
|
||
<div class="frame" style="height:560px;">
|
||
<div class="tb">
|
||
<span class="tb-h1">Wochenplaner</span>
|
||
<span class="tb-range">7.–13. Apr</span>
|
||
<div class="tb-arr">‹</div><div class="tb-arr">›</div>
|
||
<button class="tb-btn">Heute</button>
|
||
<button class="tb-btn tb-ml tb-pri">+ Gericht hinzufügen</button>
|
||
</div>
|
||
<div class="body">
|
||
|
||
<div class="sb">
|
||
<div class="score-box">
|
||
<div class="sb-lbl">Abwechslungs-Score</div>
|
||
<div style="display:flex;align-items:baseline;gap:4px;"><span class="sc-big">7.8</span><span class="sc-den">/10</span></div>
|
||
<div class="pbar pb-y"><div class="pb-fill pb-fg-y" style="width:78%;"></div></div>
|
||
<div class="sr"><span class="sr-l">Protein</span><div class="sr-b"><div class="sr-f" style="width:80%;background:var(--g);"></div></div><span class="sr-v">8.0</span></div>
|
||
<div class="sr"><span class="sr-l">Zutaten</span><div class="sr-b"><div class="sr-f" style="width:72%;background:var(--y);"></div></div><span class="sr-v">7.2</span></div>
|
||
<div class="sr"><span class="sr-l">Aufwand</span><div class="sr-b"><div class="sr-f" style="width:82%;background:var(--g);"></div></div><span class="sr-v">8.2</span></div>
|
||
<a class="sb-link">Variety-Analyse →</a>
|
||
</div>
|
||
<div>
|
||
<div class="sb-lbl">Überschneidungen</div>
|
||
<div class="w-item">⚠ Hähnchen an Mo + Do</div>
|
||
<div class="w-item">⚠ Tomaten an Di + Do</div>
|
||
</div>
|
||
<div>
|
||
<div class="sb-lbl">Geplant</div>
|
||
<div style="display:flex;align-items:baseline;gap:3px;"><span style="font-family:var(--fd);font-size:20px;font-weight:300;">5</span><span style="font-family:var(--fs);font-size:10px;color:var(--muted);">/ 7 Tage</span></div>
|
||
<div class="dp" style="margin-top:5px;">
|
||
<div class="dp-s" style="background:var(--g);"></div><div class="dp-s" style="background:var(--g);"></div><div class="dp-s" style="background:var(--g);"></div><div class="dp-s" style="background:var(--g);"></div><div class="dp-s" style="background:var(--g);"></div><div class="dp-s" style="background:var(--border);"></div><div class="dp-s" style="background:var(--border);"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="main" style="padding:12px;">
|
||
<!-- Grid fills full height of main -->
|
||
<div class="grid7" style="height:100%;">
|
||
|
||
<div class="tile img-curry" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Mo</span><span class="tile-day-num">7</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Hähnchen-Curry</div>
|
||
<div class="tile-meta">35 Min · mittel</div>
|
||
<div class="tile-tags"><span class="tag">Hähnchen</span><span class="tag">4 Port.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile tile-today img-pasta" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Di</span><span class="tile-day-num dn-today">8</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Pasta Bolognese</div>
|
||
<div class="tile-meta">45 Min · mittel</div>
|
||
<div class="tile-tags"><span class="tag tag-today">Rind</span><span class="tag tag-today">Heute</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile img-stirfry" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Mi</span><span class="tile-day-num">9</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Gemüse-Stir-fry</div>
|
||
<div class="tile-meta">20 Min · einfach</div>
|
||
<div class="tile-tags"><span class="tag">Tofu</span><span class="tag">2 Port.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile img-lachs" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Do</span><span class="tile-day-num">10</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Lachs mit Kartoffeln</div>
|
||
<div class="tile-meta">30 Min · einfach</div>
|
||
<div class="tile-tags"><span class="tag">Fisch</span><span class="tag">2 Port.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile img-pizza" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Fr</span><span class="tile-day-num">11</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Pizza Margherita</div>
|
||
<div class="tile-meta">50 Min · aufwändig</div>
|
||
<div class="tile-tags"><span class="tag">vegetarisch</span><span class="tag">4 Port.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile-empty" style="height:100%;">
|
||
<div class="empty-head"><span class="empty-day-abbr">Sa</span><span class="empty-day-num">12</span></div>
|
||
<div class="empty-cta">
|
||
<div class="empty-plus">+</div>
|
||
<div class="empty-label">Gericht wählen</div>
|
||
</div>
|
||
<div class="sug-list">
|
||
<div class="sug-hd">Vorschläge</div>
|
||
<div class="sug-row"><span class="sug-name">Ramen mit Ei</span><span class="sug-tag st-g">Neues Protein</span></div>
|
||
<div class="sug-row"><span class="sug-name">Shakshuka</span><span class="sug-tag st-g">Kein Overlap</span></div>
|
||
<div class="sug-row"><span class="sug-name">Tacos</span><span class="sug-tag st-y">Aufwand: leicht</span></div>
|
||
<div class="sug-more">Alle Rezepte →</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile-empty" style="height:100%;">
|
||
<div class="empty-head"><span class="empty-day-abbr">So</span><span class="empty-day-num">13</span></div>
|
||
<div class="empty-cta">
|
||
<div class="empty-plus">+</div>
|
||
<div class="empty-label">Gericht wählen</div>
|
||
</div>
|
||
<div class="sug-list">
|
||
<div class="sug-hd">Vorschläge</div>
|
||
<div class="sug-row"><span class="sug-name">Pho Bo</span><span class="sug-tag st-g">Neues Protein</span></div>
|
||
<div class="sug-row"><span class="sug-name">Avocado-Bowl</span><span class="sug-tag st-g">Kein Overlap</span></div>
|
||
<div class="sug-row"><span class="sug-name">Kürbissuppe</span><span class="sug-tag st-g">Kein Overlap</span></div>
|
||
<div class="sug-more">Alle Rezepte →</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="rp">
|
||
<div class="today-card">
|
||
<div class="tc-lbl">Heute Abend</div>
|
||
<div class="tc-name">Pasta Bolognese</div>
|
||
<div class="tc-meta">Dienstag · 45 Min · mittel</div>
|
||
<button class="rp-btn rp-pri" style="margin-top:8px;padding:6px;font-size:11px;">Koch-Modus starten</button>
|
||
</div>
|
||
<div class="hr"></div>
|
||
<div style="flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:6px;padding:16px;">
|
||
<div style="font-family:var(--fs);font-size:12px;color:var(--text);">Tag auswählen</div>
|
||
<div style="font-family:var(--fs);font-size:11px;color:var(--muted);max-width:152px;line-height:1.5;">Klicke eine Kachel um Details zu sehen oder ein Gericht zu planen</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="note">
|
||
<strong>Kein leerer Bereich.</strong> Das Grid nimmt die volle Höhe ein (<code>height:100%</code> auf Kacheln und Grid).
|
||
Gefüllte Kacheln: Bild von oben bis unten, Text per Overlay am unteren Rand.
|
||
Leere Kacheln: dieselbe Höhe, oben "+ Gericht wählen", darunter die Vorschlagsliste.
|
||
Da Mo–Fr alle Bilder haben, entsteht ein visuell abwechslungsreicher Kalender ohne Blank Space.
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<!-- ZUSTAND 2 — REZEPT AUSGEWÄHLT (Mi), EXPANSION UNTEN -->
|
||
<!-- ══════════════════════════════════════════════════════════════ -->
|
||
<div class="block">
|
||
<div class="block-label">
|
||
<span class="bl-num">02</span>
|
||
<span class="bl-name">Tag mit Rezept angeklickt</span>
|
||
<span class="bl-when">Mi — Expansion öffnet sich unter dem Grid</span>
|
||
</div>
|
||
|
||
<div class="frame" style="height:680px;">
|
||
<div class="tb">
|
||
<span class="tb-h1">Wochenplaner</span>
|
||
<span class="tb-range">7.–13. Apr</span>
|
||
<div class="tb-arr">‹</div><div class="tb-arr">›</div>
|
||
<button class="tb-btn">Heute</button>
|
||
<button class="tb-btn tb-ml tb-pri">+ Gericht hinzufügen</button>
|
||
</div>
|
||
<div class="body">
|
||
<div class="sb">
|
||
<div class="score-box">
|
||
<div class="sb-lbl">Abwechslungs-Score</div>
|
||
<div style="display:flex;align-items:baseline;gap:4px;"><span class="sc-big">7.8</span><span class="sc-den">/10</span></div>
|
||
<div class="pbar pb-y"><div class="pb-fill pb-fg-y" style="width:78%;"></div></div>
|
||
<div class="sr"><span class="sr-l">Protein</span><div class="sr-b"><div class="sr-f" style="width:80%;background:var(--g);"></div></div><span class="sr-v">8.0</span></div>
|
||
<div class="sr"><span class="sr-l">Zutaten</span><div class="sr-b"><div class="sr-f" style="width:72%;background:var(--y);"></div></div><span class="sr-v">7.2</span></div>
|
||
<div class="sr"><span class="sr-l">Aufwand</span><div class="sr-b"><div class="sr-f" style="width:82%;background:var(--g);"></div></div><span class="sr-v">8.2</span></div>
|
||
<a class="sb-link">Variety-Analyse →</a>
|
||
</div>
|
||
<div>
|
||
<div class="sb-lbl">Überschneidungen</div>
|
||
<div class="w-item">⚠ Hähnchen an Mo + Do</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="main">
|
||
<!-- Tiles: shorter when expansion open -->
|
||
<div class="grid7" style="height:290px;">
|
||
|
||
<div class="tile tile-faded img-curry" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Mo</span><span class="tile-day-num">7</span></div>
|
||
<div class="tile-info"><div class="tile-name">Hähnchen-Curry</div><div class="tile-meta">35 Min</div></div>
|
||
</div>
|
||
|
||
<div class="tile tile-today tile-faded img-pasta" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Di</span><span class="tile-day-num dn-today">8</span></div>
|
||
<div class="tile-info"><div class="tile-name">Pasta Bolognese</div><div class="tile-meta">45 Min</div></div>
|
||
</div>
|
||
|
||
<!-- Mi selected -->
|
||
<div class="tile tile-sel img-stirfry" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr" style="color:rgba(255,255,255,.9);">Mi</span><span class="tile-day-num dn-sel">9</span></div>
|
||
<div class="tile-info">
|
||
<div class="tile-name">Gemüse-Stir-fry</div>
|
||
<div class="tile-meta">20 Min · einfach</div>
|
||
<div class="tile-tags"><span class="tag tag-sel">Tofu</span></div>
|
||
<div style="text-align:center;font-size:9px;color:rgba(255,255,255,.7);margin-top:4px;">▼</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tile tile-faded img-lachs" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Do</span><span class="tile-day-num">10</span></div>
|
||
<div class="tile-info"><div class="tile-name">Lachs mit Kartoffeln</div><div class="tile-meta">30 Min</div></div>
|
||
</div>
|
||
|
||
<div class="tile tile-faded img-pizza" style="height:100%;">
|
||
<div class="tile-overlay"></div>
|
||
<div class="tile-head"><span class="tile-day-abbr">Fr</span><span class="tile-day-num">11</span></div>
|
||
<div class="tile-info"><div class="tile-name">Pizza Margherita</div><div class="tile-meta">50 Min</div></div>
|
||
</div>
|
||
|
||
<div class="tile-empty tile-empty-faded" style="height:100%;">
|
||
<div class="empty-head"><span class="empty-day-abbr">Sa</span><span class="empty-day-num">12</span></div>
|
||
<div class="empty-cta"><div class="empty-plus">+</div></div>
|
||
</div>
|
||
|
||
<div class="tile-empty tile-empty-faded" style="height:100%;">
|
||
<div class="empty-head"><span class="empty-day-abbr">So</span><span class="empty-day-num">13</span></div>
|
||
<div class="empty-cta"><div class="empty-plus">+</div></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Expansion -->
|
||
<div class="expand-wrap">
|
||
<div class="exp-arrows">
|
||
<div></div><div></div>
|
||
<div class="exp-arr"><div class="arr arr-fill"></div></div>
|
||
<div></div><div></div><div></div><div></div>
|
||
</div>
|
||
<div class="expand">
|
||
<div class="exp-left">
|
||
<div class="exp-ctx">Mittwoch, 9. Apr · Abendessen</div>
|
||
<div class="exp-name">Gemüse-Stir-fry</div>
|
||
<div class="exp-meta">20 Min · einfach · 2 Portionen</div>
|
||
<div class="ing-wrap">
|
||
<span class="ing">Tofu</span><span class="ing">Paprika</span><span class="ing">Brokkoli</span>
|
||
<span class="ing">Karotten</span><span class="ing">Zucchini</span><span class="ing">Ingwer</span>
|
||
<span class="ing-s">Sesamöl</span><span class="ing-s">Sojasauce</span><span class="ing-s">Knoblauch</span>
|
||
</div>
|
||
<div class="exp-bdgs">
|
||
<span class="ebdg ebdg-e">einfach</span>
|
||
<span class="ebdg ebdg-p">Protein: Tofu</span>
|
||
<span class="ebdg ebdg-sc">Score ▲ +0.4</span>
|
||
</div>
|
||
</div>
|
||
<div class="exp-right">
|
||
<button class="exp-btn exp-pri">Koch-Modus</button>
|
||
<button class="exp-btn">Rezept ansehen</button>
|
||
<button class="exp-btn">Gericht tauschen</button>
|
||
<button class="exp-btn exp-err">Entfernen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="rp">
|
||
<div class="rp-lbl">Mittwoch, 9. Apr</div>
|
||
<div style="font-family:var(--fs);font-size:11px;color:var(--muted);margin-bottom:10px;">Wie wirkt dieses Gericht?</div>
|
||
<div style="display:flex;align-items:baseline;gap:4px;margin-bottom:4px;">
|
||
<span style="font-family:var(--fd);font-size:22px;font-weight:300;">7.8</span>
|
||
<span style="font-family:var(--fs);font-size:11px;color:var(--muted);">/10</span>
|
||
<span style="font-family:var(--fs);font-size:11px;color:var(--gd);font-weight:500;margin-left:6px;">▲ +0.4</span>
|
||
</div>
|
||
<div class="pbar pb-t" style="margin-bottom:12px;"><div class="pb-fill pb-fg-g" style="width:78%;"></div></div>
|
||
<div class="hr"></div>
|
||
<div style="display:flex;flex-direction:column;gap:6px;">
|
||
<div style="font-family:var(--fs);font-size:11px;color:var(--gd);">✓ Kein Protein-Overlap</div>
|
||
<div style="font-family:var(--fs);font-size:11px;color:var(--gd);">✓ Neue Zutaten</div>
|
||
<div style="font-family:var(--fs);font-size:11px;color:var(--yx);">~ Tofu zum 2. Mal</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="note">
|
||
<strong>Beim Klick auf eine gefüllte Kachel</strong> werden alle anderen auf 42% Deckkraft gedimmt
|
||
(gefüllte <em>und</em> leere). Die Tiles bleiben in ihrer Höhe, die Expansion wächst darunter.
|
||
Da das Bild jetzt die volle Kachelhöhe einnimmt, wirkt das Dimmen als echter Fokus-Effekt —
|
||
wie eine Lupe auf das ausgewählte Gericht.
|
||
</div>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|