From 6efee2b848818ed3fe4b118fb01fa15db59a58a9 Mon Sep 17 00:00:00 2001 From: LordSchmackes Date: Thu, 21 May 2026 16:20:23 +0200 Subject: [PATCH] feat: implement Phase 5 Swipe Discovery Carousel --- .agents/TODO.md | 26 ++++---- assets/style.css | 131 +++++++++++++++++++++++++++++++++++++++ index.php | 155 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+), 13 deletions(-) diff --git a/.agents/TODO.md b/.agents/TODO.md index 9e0f04d..953b718 100644 --- a/.agents/TODO.md +++ b/.agents/TODO.md @@ -24,7 +24,7 @@ Dieses Dokument enthΓ€lt den aktuellen Entwicklungsstand und detaillierte Aufgab - Admin-Erweiterung fΓΌr Step-Videos - Fullscreen Cooking-Mode Overlay (mit Lenis scroll lock) - Timers & Looping Video Players pro Zubereitungsschritt -- [ ] **Phase 5: Sleek Swipe Discovery (Personalisiertes Empfehlungskarussell)** +- [x] **Phase 5: Sleek Swipe Discovery (Personalisiertes Empfehlungskarussell)** - Touch-Swipe-Karussell direkt auf index.php (unter Landing-Page) - Filteralgorithmus nach Benutzer-ErnΓ€hrungszielen - Mikro-Animationen & Quick-Save Funktion @@ -123,18 +123,18 @@ Ein immersiver Kochmodus, der Anwendern Schritt-fΓΌr-Schritt durch die Zubereitu ### 🎑 Phase 5: Sleek Swipe Discovery (Empfehlungskarussell) Ein hochgradig interaktives, touch-freundliches Karussell direkt auf der Startseite, das Nutzern Rezepte basierend auf ihren Zielen empfiehlt. -- [ ] **Karussell-Architektur & Integration** - - [ ] Touch-Swipe Karussell Container direkt unter der Landing-Page (vor `#basics`) auf `index.php` einbetten - - [ ] CSS-Klammern (`clamp()`) fΓΌr responsive Skalierung der Karten - - [ ] FlΓΌssiges Einblenden per Scroll-Reveal (`reveal-target`) mit Anbindung an `LenisSmoothScroll` -- [ ] **Personalisiertes Goal-Matching** - - [ ] Falls der Benutzer eingeloggt ist, sein ErnΓ€hrungsziel aus den Firebase-Profildaten abrufen - - [ ] Rezepte dynamisch filtern (z.B. High-Protein Rezepte bei Ziel "Muskelaufbau", Low-Carb Rezepte bei Ziel "Abnehmen") - - [ ] Personalisierte "FΓΌr dich empfohlen"-Badge auf den Karten anzeigen -- [ ] **Mikro-Interaktionen & Quick-Save** - - [ ] Touch-Gesten-UnterstΓΌtzung (Wischen zum BlΓ€ttern mit sanftem TrΓ€gheits-Feedback) - - [ ] Quick-Save Button direkt auf den Karussell-Karten (Herzeffekt mit direktem Firebase Firestore Sync) - - [ ] Hover-Reveal-Effekte fΓΌr Rezeptdetails (Zutaten-Vorschau oder Kochzeit-Highlight schiebt sich weich hoch) +- [x] **Karussell-Architektur & Integration** + - [x] Touch-Swipe Karussell Container direkt unter der Landing-Page (vor `#basics`) auf `index.php` einbetten + - [x] CSS-Klammern (`clamp()`) fΓΌr responsive Skalierung der Karten + - [x] FlΓΌssiges Einblenden per Scroll-Reveal (`reveal-target`) mit Anbindung an `LenisSmoothScroll` +- [x] **Personalisiertes Goal-Matching** + - [x] Falls der Benutzer eingeloggt ist, sein ErnΓ€hrungsziel aus den Firebase-Profildaten abrufen + - [x] Rezepte dynamisch filtern (z.B. High-Protein Rezepte bei Ziel "Muskelaufbau", Low-Carb Rezepte bei Ziel "Abnehmen") + - [x] Personalisierte "FΓΌr dich empfohlen"-Badge auf den Karten anzeigen +- [x] **Mikro-Interaktionen & Quick-Save** + - [x] Touch-Gesten-UnterstΓΌtzung (Wischen zum BlΓ€ttern mit sanftem TrΓ€gheits-Feedback) + - [x] Quick-Save Button direkt auf den Karussell-Karten (Herzeffekt mit direktem Firebase Firestore Sync) + - [x] Hover-Reveal-Effekte fΓΌr Rezeptdetails (Zutaten-Vorschau oder Kochzeit-Highlight schiebt sich weich hoch) --- diff --git a/assets/style.css b/assets/style.css index 66813bc..b6172b3 100644 --- a/assets/style.css +++ b/assets/style.css @@ -2213,3 +2213,134 @@ body.nav-open { overflow: hidden; } opacity: 0.3; cursor: not-allowed; } + +/* ── 23. PHASE 5: SWIPE DISCOVERY CAROUSEL ────────────────────── */ +.swipe-discovery { + padding: clamp(2rem, 5vw, 4rem) 0; + overflow: hidden; + background: var(--surface-2); +} +.swipe-discovery__header { + margin-bottom: 2.5rem; + align-items: center; + text-align: center; + padding: 0 var(--grid-margin); +} +.eyebrow-goal { + color: var(--color-accent-gold); + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.15em; + font-size: 0.75rem; +} +.swipe-track { + display: flex; + gap: var(--grid-gap); + padding: 0 var(--grid-margin) 2rem var(--grid-margin); + overflow-x: auto; + scroll-snap-type: x mandatory; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + cursor: grab; +} +.swipe-track::-webkit-scrollbar { + display: none; +} +.swipe-track.active { + cursor: grabbing; +} +.swipe-card { + flex: 0 0 clamp(280px, 60vw, 400px); + scroll-snap-align: center; + position: relative; + border-radius: var(--radius); + overflow: hidden; + background: var(--surface); + box-shadow: var(--shadow); + transition: transform 0.4s var(--ease-out-expo); + display: flex; + flex-direction: column; +} +.swipe-card__image { + position: relative; + width: 100%; + aspect-ratio: 4/3; + overflow: hidden; + display: block; +} +.swipe-card__image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.6s var(--ease-out-expo); +} +.swipe-card:hover .swipe-card__image img { + transform: scale(1.05); +} +.swipe-card__image .btn-favorite { + position: absolute; + top: 1rem; + right: 1rem; + z-index: 10; + background: rgba(255, 255, 255, 0.9); + border: none; + border-radius: 50%; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0,0,0,0.1); + transition: transform 0.3s var(--ease-overshoot), background 0.3s; +} +[data-theme="dark"] .swipe-card__image .btn-favorite { + background: rgba(0, 0, 0, 0.6); +} +.swipe-card__image .btn-favorite svg { + width: 20px; + height: 20px; + color: var(--muted); + transition: fill 0.3s, color 0.3s; +} +.swipe-card__image .btn-favorite.active svg { + fill: var(--color-terracotta); + color: var(--color-terracotta); +} +.swipe-card__body { + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + background: var(--surface); + position: relative; + z-index: 2; +} +.swipe-card__badge { + display: inline-flex; + align-items: center; + gap: 0.4rem; + background: var(--accent-soft); + color: var(--color-accent-gold); + padding: 0.25rem 0.75rem; + border-radius: 20px; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + margin-bottom: 0.5rem; + width: fit-content; +} +.swipe-card__body h3 { + font-size: clamp(1.2rem, 2vw, 1.5rem); + line-height: 1.2; +} +.swipe-card__body h3 a { + text-decoration: none; + color: var(--ink); +} +.swipe-card__body h3 a::before { + content: ''; + position: absolute; + inset: 0; +} diff --git a/index.php b/index.php index 1a4a3b5..ed2c95a 100644 --- a/index.php +++ b/index.php @@ -341,6 +341,18 @@ include __DIR__ . '/partials/head.php'; + + +
@@ -495,6 +507,29 @@ include __DIR__ . '/partials/head.php'; + $r['slug'], + 'title' => $r['title'], + 'hero' => $r['hero'], + 'difficulty' => $r['difficulty'], + 'total_time' => (int)($r['total_time'] ?? 0), + 'url' => '/recipe.php?slug=' . urlencode($r['slug']) . '&lang=' . $lang, + 'tags' => $r['tags'] ?? [], + 'category' => $r['category'] ?? '' + ]; +}, $localizedAll))); +?> +