Planner Desktop Redesign

Flip Tiles · Final Spec · Route: /planner

Version 1.0
2026-04
Mockup: specs/planner-flip-tiles.html

Der Wochenplaner hat auf Desktop aktuell ~80 % vertikalen Leerraum unterhalb des 7-Spalten-Kalenders. Zusätzlich ist das rechte Panel im Leerlauf nicht genutzt. Dieses Spec beschreibt ein vollständiges Redesign der Desktop-Hauptfläche: Die Kacheln füllen die volle Höhe und Breite, Rezeptdetails werden über einen CSS-3D-Flip direkt in der Kachel angezeigt, und leere Tage zeigen Inline-Vorschläge.

Das rechte Panel entfällt dauerhaft. Der Rezept-Picker öffnet sich als Slide-in-Drawer ausschließlich auf Anfrage (Aktion „Gericht tauschen" auf der Kachel-Rückseite). Der Toolbar-Button „Gericht hinzufügen" entfällt, da jede leere Kachel eine eigene CTA hat.

Seitenstruktur

Desktop-Layout: 2 Spalten. Kein persistentes rechtes Panel mehr.

┌─────────────────────────────────────────────────────────────┐
│  Toolbar (Wochenplaner · 7.–13. Apr  ‹ ›  Heute)           │
├──────────┬──────────────────────────────────────────────────┤
│ Sidebar  │  7-Spalten-Kachelgrid (flex: 1, height: 100%)   │
│ 184 px   │                                                  │
│ Variety  │  Mo    Di    Mi    Do    Fr    Sa    So          │
│ Score    │  ████  ████  ████  ████  ████  ░░░░  ░░░░       │
│          │  ████  ████  ████  ████  ████  ░+░░  ░+░░       │
│          │  ████  ████  ████  ████  ████  ░Vor░  ░Vor░      │
└──────────┴──────────────────────────────────────────────────┘
Entfernt: Das rechte Panel (width: 228px) mit der „Heute Abend"-Karte und dem Leerlauf-Hinweis entfällt vollständig. Koch-Modus ist auf der Kachel-Rückseite zugänglich.

Tile States

Standard (gefüllt)
Vollbild-Farbhintergrund (Gradient nach Zutat/Küche) oder heroImageUrl. Dual-Gradient-Overlay (oben + unten dunkel, Mitte klar). Oben: Tageskürzel + Datumsziffer. Unten: Rezeptname, Kochzeit, Tags.

box-shadow: var(--sh-card) — kein sichtbarer Ring.
Heute (gefüllt)
Identisch wie Standard, aber mit gelbem Ring via box-shadow: 0 0 0 2px var(--yellow), var(--sh-card). Datumsziffer-Badge in --yellow. Tag-Label „Heute" zusätzlich als frosted Tag.
Ausgewählt / Geflippt
Grüner Ring: box-shadow: 0 0 0 2px var(--green), var(--sh-raised). Karte dreht sich 180° (CSS 3D, siehe §04). Alle anderen Kacheln werden auf 38 % Deckkraft gedimmt und sind nicht klickbar.
Leer
Kein Flip. Gestrichelter Rahmen (border: 1.5px dashed var(--color-border)), background: var(--color-surface). Oben: Tageskürzel + Datum. Darunter: + Icon + „Gericht wählen". Rest der Kachel: Inline-Vorschläge (§05).
box-shadow statt border: Statusringe werden via box-shadow gesetzt, nicht via border, um Layout-Shift zu vermeiden. Die Kacheln behalten identische Außenmaße in allen Zuständen.

Ingredient & Cuisine Colors

Wenn heroImageUrl vorhanden ist, wird das echte Foto als background-image gesetzt. Fehlt es, greift die folgende Prioritätskette:

  1. Ersten Tag mit tagType = "protein" finden → Protein-Farbe
  2. Ersten Tag mit tagType = "cuisine" finden → Küchenstil-Farbe
  3. Fallback: background: var(--color-surface) (neutral)

Protein-Farben

Hähnchen
protein-haehnchen
Rind
protein-rind
Fisch
protein-fisch
Tofu
protein-tofu
Vegetarisch
protein-veg
Schwein
protein-schwein
Lamm
protein-lamm
Ei
protein-ei
Hülsen­früchte
protein-huelsenfruechte

Küchenstil-Farben

Italienisch
cuisine-italienisch
Asiatisch
cuisine-asiatisch
Indisch
cuisine-indisch
Mexikanisch
cuisine-mexikanisch
Mediterran
cuisine-mediterran

Die CSS-Klassen (protein-haehnchen, cuisine-asiatisch, …) werden serverseitig aus den Rezept-Tags abgeleitet und als Svelte-Prop übergeben, z.B. colorClass="protein-haehnchen". Das Component setzt die Klasse auf dem Kachel-Wrapper.

CSS 3D Card Flip

Jede gefüllte Kachel besteht aus drei verschachtelten Elementen:

.scene   → perspective: 900px; border-radius: var(--radius-lg); cursor: pointer
  .card  → position: relative; transform-style: preserve-3d
           transition: transform .45s cubic-bezier(.4,0,.2,1)
           .card.flipped → transform: rotateY(180deg)
    .card-front → backface-visibility: hidden; position: absolute; inset: 0
    .card-back  → backface-visibility: hidden; transform: rotateY(180deg)
                   position: absolute; inset: 0; background: var(--color-page)

Vorderseite

Rückseite

AktionStilVerhalten
Koch-Modus startenPrimary (grün ausgefüllt)Navigiert zu /planner/cook/[slotId]
Rezept ansehenSecondary (Rahmen)Navigiert zu /recipes/[recipeId]
Gericht tauschenSecondary (Rahmen)Öffnet Rezept-Picker-Drawer (§06)
EntfernenDanger (roter Text, transparenter BG)Löscht den Slot, Kachel wird leer

Interaction Flow

Kein API-Aufruf beim Flip. Alle dargestellten Daten (Name, Zutaten, Aktionen) sind bereits im vorhandenen slotMap-State vorhanden. Der Flip ist eine rein visuelle Operation.

Empty Tile — Inline Suggestions

Leere Kacheln haben denselben height: 100% wie gefüllte Kacheln. Kein Flip.

┌─────────────────┐
│ Sa     12       │  ← Tageskürzel + Datum
│─────────────────│
│       +         │
│  Gericht wählen │  ← Klick öffnet Rezept-Picker-Drawer
│─────────────────│
│ VORSCHLÄGE      │
│ Ramen mit Ei  [Neues Protein]  │
│ Shakshuka     [Kein Overlap]   │
│ Tacos         [Aufwand: leicht]│
│                                │
│     Alle Rezepte →             │
└────────────────────────────────┘

Vorschlag-Tags (Reasoning)

Anstelle numerischer Score-Deltas (die für leere Slots immer positiv sind und daher keine Information tragen) werden Begründungs-Tags angezeigt:

TagFarbeBedeutung
Neues ProteinGrünProteinquelle kommt diese Woche noch nicht vor
Kein OverlapGrünKeine Zutaten-Überschneidung mit anderen Tagen
Aufwand: leichtGelbKochzeit < 30 Min oder Aufwand = einfach
Aufwand: mittelNeutralMittlerer Aufwand
Datenquelle: Die vorhandene GET /api/suggestions?weekId=&dayOfWeek= API liefert SuggestionItem { recipe, scoreDelta, hasConflict }. Die Reasoning-Tags werden frontend-seitig aus den Rezept-Tags und dem vorhandenen slotMap abgeleitet, kein Backend-Änderungsbedarf.

Recipe Picker Drawer

Der Rezept-Picker öffnet sich als Slide-in-Drawer von rechts — ausschließlich auf explizite Anfrage. Er hat keinen persistenten Platz im Layout mehr.

Trigger

Drawer-Verhalten

Der bestehende RecipePicker-Komponente (aktuell im rechten Panel) wird in einen generischen Drawer gewrappt. Der Drawer-Wrapper ist neu; der Picker selbst bleibt unverändert.

Mobile — Out of Scope

Dieses Spec betrifft ausschließlich die Desktop-Ansicht (≥ 768px). Das mobile Layout (vertikaler Stack, DayMealCard, ActionSheet) bleibt unverändert. CSS-3D-Flips auf Touch-Geräten haben bekannte Rendering-Unterschiede auf älteren Android-Browsern — ein separates Issue sollte die mobile Interaktion (ggf. Slide-up Sheet statt Flip) spezifizieren.

Komponenten-Übersicht

src/routes/(app)/planner/+page.svelte Ändern Rechtes Panel entfernen. Layout auf 2-spaltig (sidebar + main) umstellen. Toolbar-Button entfernen. Grid-Höhe auf 100% setzen.
src/lib/planner/DayMealCard.svelte Ersetzen / umbenennen Zur Flip-Kachel umbauen: .scene → .card → .card-front + .card-back. Farb-Klassen-Prop, Gradient-Overlay, Back-Face mit Aktionen.
src/lib/planner/EmptyDayTile.svelte Neu Leere Kachel: + CTA + Inline-Suggestion-Liste mit Reasoning-Tags. Ersetzt den bisherigen leeren Slot-Platzhalter.
src/lib/planner/RecipePickerDrawer.svelte Neu Drawer-Wrapper um den bestehenden RecipePicker. Slide-in von rechts, Backdrop, Schließ-Logik.
src/lib/planner/RecipePicker.svelte Ändern Aus dem rechten Panel lösen. Bekommt slotId als Prop. Keine Änderung an der Such-/Auswahl-Logik nötig.
src/app.css Ergänzen 14 Farb-Klassen für Protein- und Küchenstil-Gradients hinzufügen (.protein-haehnchen, .cuisine-asiatisch, …).

A11y-Anforderungen