Supplemental spec · Bottom sheet recipe picker · Recipe quick actions · Day picker
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).
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.
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.
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.
No full-page navigation for either entry point. The planner or recipe list context stays visible behind the sheet at 40% opacity.
The 216px detail panel switches between states. No modal overlay. The calendar grid or recipe grid remains fully interactive beside the picker.
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.
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.
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.
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.
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.
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.
"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.
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.
/* 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). */
| Element | Value | Notes |
|---|---|---|
| Mobile sheet | ||
| Sheet max-height | 75vh | Drag to dismiss |
| Dim opacity | rgba(28,28,24,.4) | Same as J4 |
| Suggestion sort | variety_delta DESC | Different from J4 (effort ASC) |
| Suggestion badge | 8px, green-tint or yellow-tint | Only in Empfohlen section |
| Write action | PATCH + undo toast 4s | No confirmation dialog |
| Desktop panel | ||
| Active empty tile | solid green border, green-tint bg | Replaces dashed border |
| Panel width | 216px (unchanged) | Same panel, different content state |
| Panel recipe click | PATCH → transition to day-detail | No toast needed |
"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.
"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.
/* 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. */
| Token | Cook btn | Plan btn |
|---|---|---|
| Background | var(--green) | var(--green-tint) |
| Text color | #fff | var(--green-dark) |
| Border | none | 1px var(--green-light) |
| Font size mobile | 10px | 10px |
| Font size desktop | 11px | 11px |
| Radius | var(--radius-md) | var(--radius-md) |
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.
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.
‹ › buttons allow browsing to next/prev week if the current week has no empty slots. Default: shows current week.
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.
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}.
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.
/* 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. */
| State | Border | Background | Confirm btn |
|---|---|---|---|
| empty | dashed green-light | green-tint | — |
| filled | solid color-border | color-surface | — |
| today | solid yellow | yellow-tint | — |
| sel-empty | 2px green-dark | green-tint | green |
| sel-filled | 2px orange-dark | orange-tint | orange + dp-warn |
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 }.
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).
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.
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).
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.