folx-tv/client/src/pages/recipes.tsx
2026-02-28 20:36:50 +00:00

361 lines
21 KiB
TypeScript

import { useState } from "react";
import { Link } from "wouter";
import { ChefHat, Clock, Users, X, ChevronLeft } from "lucide-react";
import Header from "@/components/header";
import Footer from "@/components/footer";
import { InArticleAd } from "@/components/adsense";
interface Recipe {
title: string;
image: string;
time: string;
servings: string;
ingredients: string[];
steps: string[];
description: string;
category: string;
}
interface RecipeRegion {
name: string;
recipes: Recipe[];
}
const RECIPE_REGIONS: RecipeRegion[] = [
{
name: "Österreich",
recipes: [
{
title: "Kaiserschmarrn",
image: "/uploads/recipe-kaiserschmarrn.png",
time: "25 Min.",
servings: "2 Portionen",
category: "Nachspeise",
description: "Der Klassiker der österreichischen Küche -- fluffig, süß und einfach unwiderstehlich.",
ingredients: ["3 Eier", "200 ml Milch", "120 g Mehl", "30 g Zucker", "1 Prise Salz", "50 g Butter", "Rosinen nach Belieben", "Puderzucker"],
steps: ["Eigelb, Milch, Mehl und Salz verrühren.", "Eiweiß mit Zucker steif schlagen und unterheben.", "Butter in der Pfanne erhitzen, Teig eingießen.", "Rosinen darüber streuen, von unten goldbraun backen.", "Mit zwei Gabeln in Stücke reißen.", "Mit Puderzucker bestreut servieren."],
},
{
title: "Wiener Schnitzel",
image: "/uploads/recipe-wiener-schnitzel.png",
time: "30 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Das berühmteste Gericht Wiens -- goldbraun paniert und herrlich knusprig.",
ingredients: ["4 Kalbsschnitzel", "2 Eier", "Mehl", "Semmelbrösel", "Butterschmalz", "Salz", "Zitrone"],
steps: ["Schnitzel dünn klopfen, salzen.", "In Mehl, verquirltem Ei und Semmelbröseln panieren.", "In reichlich heißem Butterschmalz goldbraun backen.", "Auf Küchenpapier abtropfen lassen.", "Mit Zitrone und Petersilienkartoffeln servieren."],
},
{
title: "Apfelstrudel",
image: "/uploads/recipe-apfelstrudel.png",
time: "60 Min.",
servings: "6 Portionen",
category: "Nachspeise",
description: "Dünn ausgezogener Strudelteig mit saftiger Apfelfüllung -- ein Traum aus Omas Küche.",
ingredients: ["250 g Mehl", "1 Ei", "2 EL Öl", "125 ml Wasser", "1 kg Äpfel", "100 g Zucker", "Zimt", "80 g Semmelbrösel", "80 g Butter"],
steps: ["Strudelteig kneten, 30 Min. ruhen lassen.", "Äpfel schälen, in dünne Scheiben schneiden.", "Mit Zucker, Zimt und Rosinen mischen.", "Teig dünn ausziehen, Brösel verteilen.", "Füllung auflegen, einrollen.", "Bei 180°C 40 Min. goldbraun backen."],
},
{
title: "Tiroler Knödel",
image: "/uploads/recipe-tiroler-knoedel.png",
time: "40 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Herzhafte Speckknödel aus Tirol -- perfekt zu einer kräftigen Suppe oder Sauerkraut.",
ingredients: ["300 g Knödelbrot", "200 ml Milch", "3 Eier", "150 g Speck", "1 Zwiebel", "Petersilie", "Salz, Pfeffer", "Mehl"],
steps: ["Knödelbrot in eine Schüssel geben, warme Milch darüber.", "Speck und Zwiebel anbraten.", "Eier, Speck, Petersilie zum Brot geben, mischen.", "30 Min. rasten lassen.", "Knödel formen, in Salzwasser 15 Min. kochen.", "Mit Butter und Schnittlauch servieren."],
},
{
title: "Sachertorte",
image: "/uploads/recipe-sachertorte.png",
time: "90 Min.",
servings: "8 Portionen",
category: "Nachspeise",
description: "Die weltberühmte Wiener Schokoladentorte mit Marillenmarmelade und Glasur.",
ingredients: ["150 g Butter", "110 g Zucker", "6 Eier", "130 g Zartbitterschokolade", "130 g Mehl", "Marillenmarmelade", "200 g Kuvertüre"],
steps: ["Butter und Zucker schaumig rühren.", "Geschmolzene Schokolade und Eigelb unterrühren.", "Eiweiß steif schlagen, mit Mehl unterheben.", "Bei 170°C 50 Min. backen.", "Auskühlen lassen, mit Marmelade bestreichen.", "Mit Schokoladen-Glasur überziehen."],
},
{
title: "Kärntner Kasnudeln",
image: "/uploads/recipe-kaerntner-kasnudeln.png",
time: "50 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Handgemachte Teigtaschen aus Kärnten mit Topfen-Kartoffel-Füllung und frischer Minze.",
ingredients: ["400 g Mehl", "2 Eier", "Wasser", "500 g Topfen", "200 g Kartoffeln", "Minze", "Kerbel", "Butter", "Salz"],
steps: ["Nudelteig aus Mehl, Eiern und Wasser herstellen.", "Kartoffeln kochen und stampfen.", "Mit Topfen, Minze und Kerbel mischen.", "Teig ausrollen, Kreise ausstechen.", "Füllung aufsetzen, Ränder krendeln.", "In Salzwasser kochen, mit Butter servieren."],
},
{
title: "Germknödel",
image: "/uploads/recipe-germknoedel.png",
time: "120 Min.",
servings: "4 Portionen",
category: "Nachspeise",
description: "Fluffige Hefeteig-Knödel mit Powidl-Füllung, Vanillesoße und Mohn-Zucker-Topping.",
ingredients: ["500 g Mehl", "250 ml Milch", "1 Würfel Hefe", "60 g Zucker", "60 g Butter", "2 Eigelb", "Powidl (Pflaumenmus)", "Mohn", "Vanillesoße"],
steps: ["Hefeteig zubereiten und 1 Stunde gehen lassen.", "Teig in Portionen teilen, flach drücken.", "Je 1 TL Powidl in die Mitte geben.", "Zu Knödeln formen, nochmals 20 Min. gehen lassen.", "In Salzwasser oder über Dampf 15 Min. garen.", "Mit Mohn-Zucker und Vanillesoße servieren."],
},
{
title: "Tafelspitz",
image: "/uploads/recipe-tafelspitz.png",
time: "180 Min.",
servings: "6 Portionen",
category: "Hauptspeise",
description: "Zart gekochtes Rindfleisch mit Schnittlauchsoße und Apfelkren -- ein Festmahl der Wiener Küche.",
ingredients: ["1,5 kg Tafelspitz", "Suppengemüse", "Lorbeerblatt", "Pfefferkörner", "Schnittlauch", "Sauerrahm", "Äpfel", "Kren (Meerrettich)"],
steps: ["Fleisch in kaltes Wasser legen, langsam erhitzen.", "Schaum abschöpfen, Gemüse und Gewürze zugeben.", "3 Stunden sanft köcheln lassen.", "Schnittlauchsoße aus Sauerrahm zubereiten.", "Apfelkren frisch reiben und mischen.", "Fleisch aufschneiden, mit Soßen und Gemüse servieren."],
},
],
},
{
name: "Bayern",
recipes: [
{
title: "Schweinshaxe",
image: "/uploads/recipe-schweinshaxe.png",
time: "180 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Knusprig gebratene Schweinshaxe mit krachender Kruste -- das Herzstück jeder bayerischen Wirtschaft.",
ingredients: ["4 Schweinshaxen", "2 Zwiebeln", "2 Karotten", "500 ml Dunkelbier", "Kümmel", "Knoblauch", "Salz, Pfeffer", "Majoran"],
steps: ["Haxen waschen, Schwarte rautenförmig einschneiden.", "Mit Salz, Kümmel und Knoblauch einreiben.", "Mit Gemüse und Bier in die Bratpfanne geben.", "Bei 180°C ca. 2,5 Stunden braten.", "Regelmäßig mit Bratensud übergießen.", "Zum Schluss Grill zuschalten für knusprige Kruste."],
},
{
title: "Obatzda",
image: "/uploads/recipe-obatzda.png",
time: "15 Min.",
servings: "4 Portionen",
category: "Vorspeise",
description: "Der bayerische Biergarten-Klassiker -- würziger Camembert-Aufstrich mit Brezn.",
ingredients: ["200 g reifer Camembert", "100 g Frischkäse", "1 kleine Zwiebel", "1 EL Butter", "Paprikapulver", "Kümmel", "Salz, Pfeffer", "Schnittlauch"],
steps: ["Camembert mit einer Gabel zerdrücken.", "Frischkäse und weiche Butter untermischen.", "Fein gehackte Zwiebel dazugeben.", "Mit Paprika, Kümmel, Salz und Pfeffer würzen.", "Mindestens 1 Stunde durchziehen lassen.", "Mit Schnittlauch bestreut zu frischen Brezn servieren."],
},
{
title: "Dampfnudeln",
image: "/uploads/recipe-dampfnudeln.png",
time: "90 Min.",
servings: "4 Portionen",
category: "Nachspeise",
description: "Bayerische Dampfnudeln mit goldener Kruste und Vanillesoße -- wie bei der Oma auf dem Bauernhof.",
ingredients: ["500 g Mehl", "250 ml Milch", "1 Würfel Hefe", "80 g Zucker", "80 g Butter", "2 Eier", "1 Prise Salz", "Vanillesoße"],
steps: ["Hefe in lauwarmer Milch auflösen.", "Mit Mehl, Zucker, Eiern und Butter zu einem Teig kneten.", "1 Stunde gehen lassen, bis sich das Volumen verdoppelt.", "Kugeln formen und nochmals 20 Min. ruhen lassen.", "In einem geschlossenen Topf mit Milch-Butter-Gemisch dämpfen.", "Servieren, wenn die Kruste goldbraun knistert."],
},
{
title: "Käsespätzle",
image: "/uploads/recipe-kaesespaetzle.png",
time: "45 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Handgeschabte Spätzle mit würzigem Bergkäse und knusprigen Röstzwiebeln -- ein Allgäuer Traum.",
ingredients: ["400 g Mehl", "4 Eier", "200 ml Wasser", "300 g Bergkäse", "3 große Zwiebeln", "Butter", "Salz, Pfeffer", "Muskatnuss"],
steps: ["Mehl, Eier, Wasser und Salz zu einem zähen Teig schlagen.", "Durch ein Spätzlebrett in kochendes Salzwasser schaben.", "Wenn die Spätzle oben schwimmen, abschöpfen.", "Zwiebeln in Butter goldbraun rösten.", "Spätzle und geriebenen Käse schichtweise in eine Form geben.", "Mit Röstzwiebeln krönen und kurz überbacken."],
},
],
},
{
name: "Schwaben & Baden",
recipes: [
{
title: "Maultaschen",
image: "/uploads/recipe-maultaschen.png",
time: "90 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Schwäbische Herrgottsbscheißerle -- gefüllte Teigtaschen, die einst das Fleisch vor Gott versteckten.",
ingredients: ["Nudelteig (400 g Mehl, 4 Eier)", "300 g Hackfleisch", "200 g Spinat", "1 Brötchen", "1 Zwiebel", "2 Eier", "Petersilie", "Muskatnuss, Salz, Pfeffer"],
steps: ["Nudelteig kneten und 30 Min. ruhen lassen.", "Brötchen einweichen, Spinat blanchieren und hacken.", "Hackfleisch, Spinat, Brötchen, Eier und Gewürze mischen.", "Teig dünn ausrollen, Füllung in Häufchen setzen.", "Zuklappen, Taschen ausschneiden, Ränder fest andrücken.", "In kräftiger Brühe 10 Min. ziehen lassen oder anbraten."],
},
{
title: "Zwiebelrostbraten",
image: "/uploads/recipe-zwiebelrostbraten.png",
time: "40 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Saftiges Rostbraten-Stück mit einem Berg goldener Röstzwiebeln -- der schwäbische Sonntagsklassiker.",
ingredients: ["4 Scheiben Roastbeef (je 200 g)", "6 große Zwiebeln", "3 EL Mehl", "Butterschmalz", "200 ml Brühe", "Salz, Pfeffer", "1 Schuss Rotwein"],
steps: ["Zwiebeln in Ringe schneiden, in Mehl wenden.", "In heißem Butterschmalz goldbraun und knusprig frittieren.", "Fleisch salzen, pfeffern und scharf anbraten.", "Fleisch herausnehmen und warm halten.", "Bratensatz mit Rotwein und Brühe ablöschen.", "Fleisch mit Soße und einem Berg Röstzwiebeln servieren."],
},
{
title: "Flammkuchen",
image: "/uploads/recipe-flammkuchen.png",
time: "30 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Hauchdünner elsässisch-badischer Flammkuchen mit Crème fraîche, Speck und Zwiebeln.",
ingredients: ["300 g Mehl", "150 ml Wasser", "3 EL Öl", "200 g Crème fraîche", "200 g Speck", "3 Zwiebeln", "Salz, Pfeffer", "Muskatnuss"],
steps: ["Mehl, Wasser, Öl und Salz zu einem dünnen Teig kneten.", "Sehr dünn ausrollen auf einem bemehlten Blech.", "Crème fraîche gleichmäßig verstreichen.", "Mit dünnen Zwiebelringen und Speckwürfeln belegen.", "Bei 250°C auf unterster Schiene 12-15 Min. backen.", "Sofort heiß servieren, am besten mit einem Glas Weißwein."],
},
],
},
{
name: "Südtirol & Alpen",
recipes: [
{
title: "Schlutzkrapfen",
image: "/uploads/recipe-schlutzkrapfen.png",
time: "60 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Südtiroler Halbmond-Teigtaschen mit Spinat-Ricotta-Füllung und brauner Butter.",
ingredients: ["300 g Roggenmehl", "100 g Weizenmehl", "3 Eier", "Wasser", "400 g Spinat", "200 g Ricotta", "1 Zwiebel", "Butter, Parmesan, Salbei"],
steps: ["Roggen- und Weizenmehl mit Eiern und Wasser verkneten.", "30 Min. ruhen lassen.", "Spinat dünsten, hacken, mit Ricotta und Zwiebel mischen.", "Teig dünn ausrollen, Kreise ausstechen.", "Füllung aufsetzen, zu Halbmonden falten, Ränder fest drücken.", "In Salzwasser kochen, mit brauner Salbeibutter und Parmesan servieren."],
},
{
title: "Sauerbraten",
image: "/uploads/recipe-sauerbraten.png",
time: "240 Min.",
servings: "6 Portionen",
category: "Hauptspeise",
description: "Tagelang marinierter Schmorbraten mit dunkler Soße -- das Geduldsgericht der deutschen Küche.",
ingredients: ["1,5 kg Rindfleisch", "500 ml Rotweinessig", "500 ml Wasser", "2 Zwiebeln", "Lorbeer, Nelken, Piment", "Wacholderbeeren", "3 EL Lebkuchengewürz", "Rosinen"],
steps: ["Fleisch 3-5 Tage in Essig-Wasser-Marinade mit Gewürzen einlegen.", "Fleisch herausnehmen, trocken tupfen, scharf anbraten.", "Mit gefilterter Marinade ablöschen.", "Bei 160°C 3 Stunden schmoren.", "Soße mit Lebkuchen-Bröseln und Rosinen binden.", "Mit Kartoffelklößen und Rotkraut servieren."],
},
{
title: "Schwarzwälder Kirschtorte",
image: "/uploads/recipe-schwarzwaelder-kirschtorte.png",
time: "120 Min.",
servings: "12 Portionen",
category: "Nachspeise",
description: "Die Königin der deutschen Torten -- Schokolade, Kirschen, Sahne und ein Schuss Kirschwasser.",
ingredients: ["6 Eier", "200 g Zucker", "150 g Mehl", "50 g Kakao", "80 g Butter", "1 Glas Sauerkirschen", "600 ml Sahne", "Kirschwasser", "Schokoraspeln"],
steps: ["Biskuit aus Eiern, Zucker, Mehl, Kakao und Butter backen.", "Auskühlen lassen und in 3 Böden schneiden.", "Böden mit Kirschwasser tränken.", "Sahne steif schlagen, zwischen die Böden streichen.", "Kirschen auf die Schichten verteilen.", "Torte mit Sahne, Schokoraspeln und Kirschen dekorieren."],
},
],
},
{
name: "Norddeutschland",
recipes: [
{
title: "Grünkohl mit Pinkel",
image: "/uploads/recipe-gruenkohl.png",
time: "120 Min.",
servings: "6 Portionen",
category: "Hauptspeise",
description: "Norddeutscher Winterklassiker -- deftiger Grünkohl mit geräucherter Pinkelwurst nach dem ersten Frost.",
ingredients: ["1,5 kg frischer Grünkohl", "4 Pinkelwürste", "250 g Kasseler", "250 g durchwachsener Speck", "2 Zwiebeln", "Schmalz", "Haferflocken", "Senf"],
steps: ["Grünkohl waschen, Stiele entfernen und grob hacken.", "Zwiebeln in Schmalz anbraten, Grünkohl zugeben.", "Mit Brühe aufgießen, Speck und Kasseler einlegen.", "90 Min. köcheln lassen, gelegentlich umrühren.", "Pinkelwürste in den letzten 30 Min. mitgaren.", "Mit Haferflocken binden, mit Senf und Bratkartoffeln servieren."],
},
{
title: "Kartoffelpuffer",
image: "/uploads/recipe-kartoffelpuffer.png",
time: "30 Min.",
servings: "4 Portionen",
category: "Hauptspeise",
description: "Goldbraun gebratene Kartoffelreibekuchen -- ob süß mit Apfelmus oder herzhaft mit Lachs.",
ingredients: ["1 kg festkochende Kartoffeln", "1 Zwiebel", "2 Eier", "3 EL Mehl", "Salz, Pfeffer", "Muskatnuss", "Öl zum Braten", "Apfelmus"],
steps: ["Kartoffeln und Zwiebel fein reiben.", "Überschüssige Flüssigkeit gut ausdrücken.", "Mit Eiern, Mehl, Salz und Muskatnuss verrühren.", "In heißem Öl löffelweise flache Puffer braten.", "Von beiden Seiten goldbraun und knusprig backen.", "Auf Küchenpapier abtropfen, mit Apfelmus servieren."],
},
],
},
];
function RecipeModal({ recipe, onClose }: { recipe: Recipe; onClose: () => void }) {
return (
<div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4" onClick={onClose} data-testid="modal-recipe-page">
<div
className="bg-card rounded-xl border border-card-border max-w-lg w-full max-h-[85vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="relative">
<img src={recipe.image} alt={recipe.title} className="w-full h-56 object-cover rounded-t-xl" />
<button onClick={onClose} className="absolute top-3 right-3 bg-black/60 rounded-full p-1.5 text-white hover:bg-black/80" data-testid="button-recipe-modal-close">
<X className="w-4 h-4" />
</button>
</div>
<div className="p-5">
<h2 className="text-xl font-bold text-foreground mb-1">{recipe.title}</h2>
<span className="text-[11px] font-medium text-primary">{recipe.category}</span>
<p className="text-sm text-muted-foreground mb-3 mt-1">{recipe.description}</p>
<div className="flex items-center gap-4 text-sm text-muted-foreground mb-5">
<span className="flex items-center gap-1"><Clock className="w-4 h-4" />{recipe.time}</span>
<span className="flex items-center gap-1"><Users className="w-4 h-4" />{recipe.servings}</span>
</div>
<h3 className="font-semibold text-foreground text-sm mb-2">Zutaten</h3>
<ul className="text-sm text-foreground/80 mb-5 space-y-1">
{recipe.ingredients.map((ing, i) => (
<li key={i} className="flex items-start gap-2">
<span className="text-primary mt-1"></span>{ing}
</li>
))}
</ul>
<h3 className="font-semibold text-foreground text-sm mb-2">Zubereitung</h3>
<ol className="text-sm text-foreground/80 space-y-2">
{recipe.steps.map((step, i) => (
<li key={i} className="flex gap-2">
<span className="font-bold text-primary flex-shrink-0">{i + 1}.</span>{step}
</li>
))}
</ol>
</div>
</div>
</div>
);
}
export default function RecipesPage() {
const [selectedRecipe, setSelectedRecipe] = useState<Recipe | null>(null);
return (
<div className="min-h-screen bg-background">
<Header />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="flex items-center gap-3 mb-2">
<Link href="/">
<button className="text-muted-foreground hover:text-foreground transition-colors" data-testid="button-recipes-back">
<ChevronLeft className="w-5 h-5" />
</button>
</Link>
<h1 className="text-2xl font-bold text-foreground flex items-center gap-2" data-testid="text-recipes-title">
<ChefHat className="w-6 h-6 text-primary" />
Legendäre Bauernküche
</h1>
</div>
<p className="text-muted-foreground text-sm mb-8 ml-8" data-testid="text-recipes-subtitle">
Traditionelle Rezepte aus den germanischen Regionen -- von der Alm bis zur Küste, von der Oma überliefert.
</p>
{RECIPE_REGIONS.map((region, ri) => (
<div key={region.name} data-testid={`section-region-${ri}`}>
<div className="flex items-center gap-3 mb-4 mt-8 first:mt-0">
<div className="h-px flex-1 bg-card-border" />
<h2 className="text-lg font-bold text-foreground px-3" data-testid={`text-region-${ri}`}>{region.name}</h2>
<div className="h-px flex-1 bg-card-border" />
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5 mb-4">
{region.recipes.map((recipe, i) => (
<button
key={recipe.title}
onClick={() => setSelectedRecipe(recipe)}
className="bg-card rounded-xl border border-card-border overflow-hidden text-left group hover:border-primary/50 transition-all hover:shadow-lg hover:shadow-primary/5"
data-testid={`card-recipe-${ri}-${i}`}
>
<div className="relative overflow-hidden">
<img src={recipe.image} alt={recipe.title} className="w-full aspect-video object-cover transition-transform duration-500 group-hover:scale-105" loading="lazy" />
</div>
<div className="p-4">
<h3 className="font-bold text-card-foreground text-base group-hover:text-primary transition-colors">{recipe.title}</h3>
<span className="text-[10px] font-medium text-primary">{recipe.category}</span>
<p className="text-xs text-muted-foreground mt-1 line-clamp-2">{recipe.description}</p>
<div className="flex items-center gap-3 mt-3 text-xs text-muted-foreground">
<span className="flex items-center gap-1"><Clock className="w-3 h-3" />{recipe.time}</span>
<span className="flex items-center gap-1"><Users className="w-3 h-3" />{recipe.servings}</span>
</div>
</div>
</button>
))}
</div>
{ri % 2 === 0 && <InArticleAd />}
</div>
))}
</main>
<Footer />
{selectedRecipe && <RecipeModal recipe={selectedRecipe} onClose={() => setSelectedRecipe(null)} />}
</div>
);
}