feat(phase-1): Premium design system, CapitoliumPreloader, IndexSectionIndicator, Recipe Showcase Stage

- Full CSS rewrite: Warm Ivory/Gold/Steinkohle design tokens, Floema grid, easing library
- AuraMarbleBackground: fixed grain texture layer
- CapitoliumPreloader: fullscreen counter animation with slide-up exit
- LiquidOverlayMenu: fixed hamburger → fullscreen clip-path overlay with SlideUpTextHover nav links
- IndexSectionIndicator: fixed left-side section tracker with animated fill line
- Recipe Showcase Stage: GSAP ScrollTrigger pinned stage (images enter from right, exit left)
  with parallax inner-image effect, intro title, progress dots, hint line
- LenisSmoothScroll: CDN integration synced with GSAP ticker
- CapitoliumRevealButton: scaleY fill reveal on hover for all CTAs
- SlideUpTextHover: overlay nav links
- UnderlineExpandHover: footer + overlay footer links
- head.php: GSAP 3.12.5 + ScrollTrigger + Lenis 1.0.42 CDN; Playfair Display + Manrope fonts
- recipe.php: updated to new design system (btn-reveal, pill--gold, Lenis init)
- impressum.php / datenschutz.php: migrated to shared head.php partial
This commit is contained in:
2026-05-21 11:52:40 +02:00
parent 025f41fd18
commit 6c00e1a00d
8 changed files with 2145 additions and 1176 deletions
+80 -57
View File
@@ -4,59 +4,50 @@ require __DIR__ . '/helpers.php';
$lang = (isset($_GET['lang']) && strtolower($_GET['lang']) === 'de') ? 'de' : 'en';
$copy = [
'en' => [
'home' => 'Home',
'latest' => 'Latest',
'basics' => 'Basics',
'not_found' => 'Recipe not found',
'not_found' => 'Recipe not found',
'not_found_sub' => 'Try searching for something else.',
'back_home' => '← Back to all recipes',
'ingredients' => 'Ingredients',
'utensils' => 'Utensils',
'steps' => 'Steps',
'also_tasty' => 'Also tasty',
'more_dishes' => 'More dishes to keep you cooking.',
'prep' => 'Prep',
'cook' => 'Cook',
'total' => 'Total',
'serves' => 'Serves',
'level' => 'Level',
'back_home' => '← Back to all recipes',
'ingredients' => 'Ingredients',
'utensils' => 'Utensils',
'steps' => 'Steps',
'also_tasty' => 'Also tasty',
'more_dishes' => 'More dishes to keep you cooking.',
'prep' => 'Prep',
'cook' => 'Cook',
'total' => 'Total',
'serves' => 'Serves',
'level' => 'Level',
],
'de' => [
'home' => 'Start',
'latest' => 'Neueste',
'basics' => 'Basics',
'not_found' => 'Rezept nicht gefunden',
'not_found' => 'Rezept nicht gefunden',
'not_found_sub' => 'Versuche eine andere Suche.',
'back_home' => '← Zurück zu allen Rezepten',
'ingredients' => 'Zutaten',
'utensils' => 'Küchenwerkzeug',
'steps' => 'Schritte',
'also_tasty' => 'Auch lecker',
'more_dishes' => 'Noch mehr zum Nachkochen.',
'prep' => 'Vorbereitung',
'cook' => 'Garen',
'total' => 'Gesamt',
'serves' => 'Portionen',
'level' => 'Level',
'back_home' => '← Zurück zu allen Rezepten',
'ingredients' => 'Zutaten',
'utensils' => 'Küchenwerkzeug',
'steps' => 'Schritte',
'also_tasty' => 'Auch lecker',
'more_dishes' => 'Noch mehr zum Nachkochen.',
'prep' => 'Vorbereitung',
'cook' => 'Garen',
'total' => 'Gesamt',
'serves' => 'Portionen',
'level' => 'Level',
],
];
$t = $copy[$lang];
$allRecipes = load_recipes();
$slug = isset($_GET['slug']) ? trim($_GET['slug']) : '';
$recipeRaw = $slug ? find_recipe_by_slug($allRecipes, $slug) : null;
$recipe = $recipeRaw ? localize_recipe($recipeRaw, $lang) : null;
$allRecipesLocalized = localize_recipes($allRecipes, $lang);
$allRecipes = load_recipes();
$slug = isset($_GET['slug']) ? trim($_GET['slug']) : '';
$recipeRaw = $slug ? find_recipe_by_slug($allRecipes, $slug) : null;
$recipe = $recipeRaw ? localize_recipe($recipeRaw, $lang) : null;
$allRecipesLocal = localize_recipes($allRecipes, $lang);
$langSwitchLabel = $lang === 'de' ? 'EN' : 'DE';
$langSwitchHref = lang_url($lang === 'de' ? 'en' : 'de');
$navHome = $t['home'];
$navLatest = $t['latest'];
$navBasics = $t['basics'];
$langSwitchHref = lang_url($lang === 'de' ? 'en' : 'de');
if (!$recipe) {
http_response_code(404);
$pageTitle = $t['not_found'] . ' | FlixCooks';
$pageTitle = $t['not_found'] . ' | FlixCooks';
$description = $t['not_found_sub'];
include __DIR__ . '/partials/head.php';
include __DIR__ . '/partials/header.php';
@@ -64,14 +55,17 @@ if (!$recipe) {
<main class="not-found">
<h1><?php echo e($t['not_found']); ?></h1>
<p><?php echo e($t['not_found_sub']); ?></p>
<a class="button" href="/index.php?lang=<?php echo e($lang); ?>#recipes-start"><?php echo e($t['back_home']); ?></a>
<a class="btn-reveal" href="/index.php?lang=<?php echo e($lang); ?>#recipes-start">
<span class="btn-reveal-text"><?php echo e($t['back_home']); ?></span>
<span class="btn-reveal-arrow">→</span>
</a>
</main>
<?php
include __DIR__ . '/partials/footer.php';
exit;
}
$pageTitle = e($recipe['title']) . ' | FlixCooks';
$pageTitle = e($recipe['title']) . ' | FlixCooks';
$description = $recipe['description'] ?? '';
include __DIR__ . '/partials/head.php';
include __DIR__ . '/partials/header.php';
@@ -81,17 +75,22 @@ include __DIR__ . '/partials/header.php';
<div class="recipe__hero">
<img src="<?php echo e($recipe['hero']); ?>" alt="<?php echo e($recipe['title']); ?>">
<div class="recipe__hero__copy">
<p class="pill pill--ghost"><?php echo e($recipe['category']); ?></p>
<?php if (!empty($recipe['category'])): ?>
<p class="pill pill--gold"><?php echo e($recipe['category']); ?></p>
<?php endif; ?>
<h1><?php echo e($recipe['title']); ?></h1>
<p class="lede"><?php echo e($recipe['description']); ?></p>
<div class="meta meta--row">
<span><?php echo e($t['prep']); ?>: <?php echo format_minutes((int) $recipe['prep_time']); ?></span>
<span><?php echo e($t['cook']); ?>: <?php echo format_minutes((int) $recipe['cook_time']); ?></span>
<span><?php echo e($t['total']); ?>: <?php echo format_minutes((int) $recipe['total_time']); ?></span>
<span><?php echo e($t['prep']); ?>: <?php echo format_minutes((int)$recipe['prep_time']); ?></span>
<span><?php echo e($t['cook']); ?>: <?php echo format_minutes((int)$recipe['cook_time']); ?></span>
<span><?php echo e($t['total']); ?>: <?php echo format_minutes((int)$recipe['total_time']); ?></span>
<span><?php echo e($t['serves']); ?>: <?php echo e($recipe['servings']); ?></span>
<span><?php echo e($t['level']); ?>: <?php echo e($recipe['difficulty']); ?></span>
</div>
<a class="button" href="/index.php?lang=<?php echo e($lang); ?>#recipes-start"><?php echo e($t['back_home']); ?></a>
<a class="btn-reveal" href="/index.php?lang=<?php echo e($lang); ?>#recipes-start">
<span class="btn-reveal-text"><?php echo e($t['back_home']); ?></span>
<span class="btn-reveal-arrow">←</span>
</a>
</div>
</div>
@@ -127,19 +126,24 @@ include __DIR__ . '/partials/header.php';
</div>
<section class="more">
<div class="section-header">
<h3><?php echo e($t['also_tasty']); ?></h3>
<p><?php echo e($t['more_dishes']); ?></p>
<div class="section-header section-header--stack">
<p class="eyebrow"><?php echo e($t['also_tasty']); ?></p>
<h3><?php echo e($t['more_dishes']); ?></h3>
</div>
<div class="grid grid--tight">
<?php foreach ($allRecipesLocalized as $other): ?>
<?php foreach ($allRecipesLocal as $other): ?>
<?php if ($other['slug'] === $recipe['slug'] || !empty($other['coming_soon'])) continue; ?>
<article class="card card--bare">
<h4><a href="/recipe.php?<?php echo http_build_query(['slug' => $other['slug'], 'lang' => $lang]); ?>"><?php echo e($other['title']); ?></a></h4>
<p><?php echo e($other['description']); ?></p>
<div class="meta">
<span>⏱ <?php echo format_minutes((int) ($other['total_time'] ?? 0)); ?></span>
<span>🙂 <?php echo e($other['difficulty']); ?></span>
<article class="card card--bare reveal-target">
<a href="/recipe.php?<?php echo http_build_query(['slug' => $other['slug'], 'lang' => $lang]); ?>" class="card__image">
<img src="<?php echo e($other['hero']); ?>" alt="<?php echo e($other['title']); ?>" loading="lazy">
</a>
<div class="card__body">
<h4><a href="/recipe.php?<?php echo http_build_query(['slug' => $other['slug'], 'lang' => $lang]); ?>"><?php echo e($other['title']); ?></a></h4>
<p><?php echo e($other['description']); ?></p>
<div class="meta">
<span>⏱ <?php echo format_minutes((int)($other['total_time'] ?? 0)); ?></span>
<span>🙂 <?php echo e($other['difficulty']); ?></span>
</div>
</div>
</article>
<?php endforeach; ?>
@@ -148,3 +152,22 @@ include __DIR__ . '/partials/header.php';
</article>
<?php include __DIR__ . '/partials/footer.php'; ?>
<script>
// Scroll reveal on recipe page
if ('IntersectionObserver' in window) {
var obs = new IntersectionObserver(function(entries) {
entries.forEach(function(e) {
if (e.isIntersecting) { e.target.classList.add('revealed'); obs.unobserve(e.target); }
});
}, { threshold: 0.08 });
document.querySelectorAll('.reveal-target').forEach(function(el) { obs.observe(el); });
}
// Lenis init for recipe page
if (typeof Lenis !== 'undefined') {
var lenis = new Lenis({ duration: 1.2, smooth: true, smoothTouch: false });
window.lenis = lenis;
function raf(time) { lenis.raf(time); requestAnimationFrame(raf); }
requestAnimationFrame(raf);
}
</script>