J2 Add to Plan — Screens C4–C6

Supplemental spec · Bottom sheet recipe picker · Recipe quick actions · Day picker

Journey: J2 supplement
Screens: C4 · C5 · C6
Status: draft
Version: 1.0
Updated: 2026-04
J2

Add to plan — supplemental

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).

Two entry points: C1 "+" / empty slot → C4 · B1 "Zur Woche +" → C6
Design rationale

Entry from planner (C4) — recipe unknown

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.

Entry from recipe list (C5 → C6) — day unknown

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.

Add ≠ Swap

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.

Mobile: always bottom sheet

No full-page navigation for either entry point. The planner or recipe list context stays visible behind the sheet at 40% opacity.

Desktop: panel transformation

The 216px detail panel switches between states. No modal overlay. The calendar grid or recipe grid remains fully interactive beside the picker.

Add meal — from planner

C4
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.
V1 · Bottom sheet (mobile & tablet) · V2 · Panel transformation (desktop)
Breakpoint 1 — Mobile · < 768px
9:41●●● WiFi 🔋
Diese Woche
+
Mo31
Di1
Mi2
Do3
Fr4
Sa5
So6
Rezept wählen
Samstag, 5. April
×
Empfohlen · Beste Abwechslung
Lachsfilet mit Gemüse
25 min · Einfach · Fisch
↑ +2 Punkte
Mushroom Risotto
50 min · Mittel · Vegetarisch
↑ +2 Punkte
Hähnchen-Curry
35 min · Einfach
⚠ Fr ebenfalls Hähnchen
Alle Rezepte
Beef Bourguignon
2h 30 · Aufwendig
Spaghetti Carbonara
20 min · Einfach
Tomatensuppe
30 min · Vegetarisch

Sheet structure

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.

Variety badges

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.

Background

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.

Immediate write

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.

Breakpoint 3 — Desktop · > 1024px

Panel in recipe-picker mode

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.

📅 Planer
📖 Rezepte
🛒 Einkauf
Variety score
8/10
Wochenplanung
31 März – 6 Apr
Montag
31
Abendessen
Pasta al forno
30 min
Dienstag
1
Heute
Gegrillter Lachs
25 min
Mittwoch
2
Abendessen
Tomaten-Pasta
45 min
Donnerstag
3
Abendessen
Hähnchen-Stir-fry
25 min
Freitag
4
Abendessen
Hähnchen-Curry
40 min
Samstag
5
+
Wählen…
Sonntag
6
Abendessen
Linsensuppe
45 min
Sa, 5. April
Rezept wählen
×
Empfohlen
Lachsfilet mit Gemüse
25 min · Einfach · Fisch
↑ +2 Punkte
Mushroom Risotto
50 min · Mittel · Vegetarisch
↑ +2 Punkte
Hähnchen-Curry
35 min · Einfach
⚠ Fr ebenfalls Hähnchen
Alle Rezepte
Beef Bourguignon
2h 30 · Aufwendig
Spaghetti Carbonara
20 min · Einfach
Tomatensuppe
30 min · Vegetarisch
Rindereintopf
1h 20 · Mittel

Active empty tile

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.

Panel header state

"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.

Clicking a recipe row

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.

C4 · Add meal from planner — implementation

/* 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). */
ElementValueNotes
Mobile sheet
Sheet max-height75vhDrag to dismiss
Dim opacityrgba(28,28,24,.4)Same as J4
Suggestion sortvariety_delta DESCDifferent from J4 (effort ASC)
Suggestion badge8px, green-tint or yellow-tintOnly in Empfohlen section
Write actionPATCH + undo toast 4sNo confirmation dialog
Desktop panel
Active empty tilesolid green border, green-tint bgReplaces dashed border
Panel width216px (unchanged)Same panel, different content state
Panel recipe clickPATCH → transition to day-detailNo toast needed

Recipe card — quick actions

C5
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.
V1 · Always-visible quick action row — mobile list and desktop grid
Mobile · Recipe list
9:41●●● WiFi 🔋
Rezepte
+
Spaghetti Carbonara
20 min Einfach Nudeln
Mushroom Risotto
50 min Mittel Vegetarisch
Lachsfilet mit Gemüse
25 min Einfach Fisch
📅
Planer
📖
Rezepte
🛒
Einkauf
⚙️
Settings
Desktop · Recipe grid
📅 Planer
📖 Rezepte
🛒 Einkauf
Rezepte
Spaghetti Carbonara
Cremige römische Pasta — kein Sahne, nur Ei und Guanciale.
20 min Einfach Nudeln
Mushroom Risotto
Cremiges Risotto mit Pilzen, Parmesan und frischem Thymian.
50 min Mittel Vegetarisch
Lachsfilet mit Gemüse
Knusprig gebratener Lachs auf Ofengemüse.
25 min Einfach Fisch

Two actions, two visual weights

"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.

Navigation targets

"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.

C5 · Recipe quick actions — implementation

/* 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. */
TokenCook btnPlan btn
Backgroundvar(--green)var(--green-tint)
Text color#fffvar(--green-dark)
Bordernone1px var(--green-light)
Font size mobile10px10px
Font size desktop11px11px
Radiusvar(--radius-md)var(--radius-md)

Day picker — add from recipe

C6
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.
V1 · Empty slot selected (green confirm) · V2 · Filled slot selected (orange replace confirm)
Breakpoint 1 — Mobile · Both variants
V1 · Empty slot (Sa)
9:41●●● WiFi 🔋
Rezepte
Spaghetti Carbonara
Mushroom Risotto
Mushroom Risotto
Zu welchem Tag hinzufügen?
×
31 März – 6 Apr
Mo31
Di1
Mi2
Do3
Fr4
Sa5
So6
V2 · Filled slot (Mi) — ersetzen?
9:41●●● WiFi 🔋
Rezepte
Mushroom Risotto
Mushroom Risotto
Zu welchem Tag hinzufügen?
×
31 März – 6 Apr
Mo31
Di1
Mi2
Do3
Fr4
Sa5
So6
Ersetzt Tomaten-Pasta am Mittwoch. Undo möglich.

Slot states

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.

No replace dialog

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.

Week navigation

‹ › buttons allow browsing to next/prev week if the current week has no empty slots. Default: shows current week.

Breakpoint 3 — Desktop · Panel day-picker mode
📅 Planer
📖 Rezepte
🛒 Einkauf
Rezepte
Spaghetti Carbonara
20 min Einfach
Mushroom Risotto
Cremiges Risotto mit Pilzen und Parmesan.
50 min Mittel Vegetarisch
Lachsfilet
25 min Einfach
Mushroom Risotto
Tag für diese Woche wählen
×
31 März – 6 Apr
Mo31
Di1
Mi2
Do3
Fr4
Sa5
So6
Samstag, 5. April · leer
Variety-Vorschau
↑ Score: 8 → 9 · Neues Protein

Active card highlight

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.

Variety preview (desktop only)

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}.

Replace on desktop

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.

C6 · Day picker — implementation

/* 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. */
StateBorderBackgroundConfirm btn
emptydashed green-lightgreen-tint
filledsolid color-bordercolor-surface
todaysolid yellowyellow-tint
sel-empty2px green-darkgreen-tintgreen
sel-filled2px orange-darkorange-tintorange + dp-warn

LLM Implementation Notes — J2 Add to Plan (C4–C6)

1. Screens and entry points

C4: User knows the day, not the recipe. Entry: "+" or empty slot tap in C1. C5: Recipe card in B1 gains two quick action buttons. C6: User knows the recipe, not the day. Entry: "Zur Woche +" on C5 card. All three flows share the same backend write: PATCH /api/week-plan/{weekId}/slots/{date} { recipe_id }.

2. C4 vs J4 — different sort, same sheet pattern

Both use a bottom sheet over dimmed content. The difference: J4 swap suggestions are sorted effort ASC (easiest first, because mid-week changes happen under stress). C4 suggestions are sorted variety_delta DESC (best variety impact first, because this is deliberate weekly planning).

3. Panel state machine (desktop)

The 216px right panel can be in four states: idle (no selection) → day-detail (filled day selected in C1) → recipe-picker (C4 mode) → day-picker (C6 mode). The "×" close button always returns to the previous state. Successful pick transitions to day-detail for the affected date.

4. Tap counts

5. Undo

All flows use DELETE /api/week-plan/{weekId}/slots/{date} 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).

6. C5 "Jetzt kochen" — no back-stack issue

Navigating to /cook/{recipeId} 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.