Add new regional recipes and enhance the horoscope page functionality

Introduce a new /rezepte page with 21 regional recipes featuring AI-generated images. Enhance the /horoskop page with element colors, star ratings, and navigation. Update navigation, routing, and widgets to support these new features.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 413891e8-d784-4bea-b9f5-91a5a68316b4
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ca8c12e6-1e00-476d-86cc-c529591779ac
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/413891e8-d784-4bea-b9f5-91a5a68316b4/oYq1Msd
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
sebastjanartic 2026-02-28 19:58:23 +00:00
parent d0ee926b35
commit 4963edd636
34 changed files with 970 additions and 534 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -10,6 +10,7 @@ import CategoryPage from "@/pages/category";
import VideosPage from "@/pages/videos";
import GalleryPageWrapper from "@/pages/gallery";
import HoroscopePage from "@/pages/horoscope";
import RecipesPage from "@/pages/recipes";
function Router() {
return (
@ -20,6 +21,8 @@ function Router() {
<Route path="/videos" component={VideosPage} />
<Route path="/gallery" component={GalleryPageWrapper} />
<Route path="/horoskop" component={HoroscopePage} />
<Route path="/horoskop/:sign" component={HoroscopePage} />
<Route path="/rezepte" component={RecipesPage} />
<Route component={NotFound} />
</Switch>
);

View File

@ -30,6 +30,16 @@ export default function Footer() {
<span className="text-muted-foreground cursor-pointer hover:text-primary transition-colors" data-testid="link-footer-gallery">Fotogalerie</span>
</Link>
</li>
<li>
<Link href="/horoskop">
<span className="text-muted-foreground cursor-pointer hover:text-primary transition-colors" data-testid="link-footer-horoskop">Horoskop</span>
</Link>
</li>
<li>
<Link href="/rezepte">
<span className="text-muted-foreground cursor-pointer hover:text-primary transition-colors" data-testid="link-footer-rezepte">Rezepte</span>
</Link>
</li>
</ul>
</div>
<div>

View File

@ -10,6 +10,7 @@ const navItems = [
{ label: "Video", href: "/videos" },
{ label: "Galerie", href: "/gallery" },
{ label: "Horoskop", href: "/horoskop" },
{ label: "Rezepte", href: "/rezepte" },
];
export default function Header() {

View File

@ -1,90 +1,14 @@
import { useState, useEffect, useCallback } from "react";
import { useLocation } from "wouter";
import { Star } from "lucide-react";
const SIGNS = [
{ name: "Widder", symbol: "♈", date: "21.03 19.04", element: "Feuer" },
{ name: "Stier", symbol: "♉", date: "20.04 20.05", element: "Erde" },
{ name: "Zwillinge", symbol: "♊", date: "21.05 20.06", element: "Luft" },
{ name: "Krebs", symbol: "♋", date: "21.06 22.07", element: "Wasser" },
{ name: "Löwe", symbol: "♌", date: "23.07 22.08", element: "Feuer" },
{ name: "Jungfrau", symbol: "♍", date: "23.08 22.09", element: "Erde" },
{ name: "Waage", symbol: "♎", date: "23.09 22.10", element: "Luft" },
{ name: "Skorpion", symbol: "♏", date: "23.10 21.11", element: "Wasser" },
{ name: "Schütze", symbol: "♐", date: "22.11 21.12", element: "Feuer" },
{ name: "Steinbock", symbol: "♑", date: "22.12 19.01", element: "Erde" },
{ name: "Wassermann", symbol: "♒", date: "20.01 18.02", element: "Luft" },
{ name: "Fische", symbol: "♓", date: "19.02 20.03", element: "Wasser" },
];
const DAILY_TEXTS = [
"Ein wunderbarer Tag für neue Begegnungen. Die Sterne stehen günstig für spontane Entscheidungen.",
"Heute ist Geduld gefragt. Lassen Sie sich Zeit und genießen Sie die kleinen Freuden des Alltags.",
"Kommunikation steht im Vordergrund. Ein gutes Gespräch kann heute Wunder wirken.",
"Vertrauen Sie auf Ihre Intuition. Ihr Bauchgefühl weist Ihnen den richtigen Weg.",
"Kreativität und Mut werden heute belohnt. Zeigen Sie, was in Ihnen steckt!",
"Ordnung und Struktur bringen heute den Erfolg. Nutzen Sie die Energie für wichtige Aufgaben.",
"Harmonie und Ausgeglichenheit bestimmen den Tag. Genießen Sie die Zeit mit Ihren Liebsten.",
"Tiefgründige Erkenntnisse warten auf Sie. Nehmen Sie sich Zeit für Reflexion.",
"Abenteuerlust liegt in der Luft! Planen Sie etwas Besonderes für heute.",
"Disziplin und Ausdauer zahlen sich aus. Bleiben Sie an Ihren Zielen dran.",
"Originelle Ideen kommen heute von ganz allein. Lassen Sie Ihrer Fantasie freien Lauf.",
"Einfühlungsvermögen und Mitgefühl stärken heute Ihre Beziehungen.",
];
function getDailyText(signIndex: number): string {
const dayOfYear = Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0).getTime()) / 86400000);
return DAILY_TEXTS[(signIndex + dayOfYear) % DAILY_TEXTS.length];
}
function HoroscopeModal({ onClose, initialSign }: { onClose: () => void; initialSign: number }) {
const [selected, setSelected] = useState(initialSign);
import { Star, Heart, Briefcase, TrendingUp, ChevronLeft, ChevronRight } from "lucide-react";
import { SIGNS, ELEMENT_COLORS, getHoroscope, getRating } from "@/lib/horoscope-data";
function MiniStars({ count, max = 5 }: { count: number; max?: number }) {
return (
<div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4" onClick={onClose} data-testid="modal-horoscope">
<div
className="bg-card rounded-xl border border-card-border max-w-lg w-full max-h-[80vh] overflow-y-auto p-6"
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-bold text-foreground flex items-center gap-2">
<Star className="w-5 h-5 text-primary" />
Tageshoroskop
</h2>
<button onClick={onClose} className="text-muted-foreground hover:text-foreground" data-testid="button-horoscope-close">
<X className="w-5 h-5" />
</button>
</div>
<div className="grid grid-cols-4 sm:grid-cols-6 gap-2 mb-6">
{SIGNS.map((sign, i) => (
<button
key={sign.name}
onClick={() => setSelected(i)}
className={`flex flex-col items-center p-2 rounded-lg transition-colors ${
i === selected ? "bg-primary/20 border border-primary" : "hover:bg-muted border border-transparent"
}`}
data-testid={`button-sign-${sign.name}`}
>
<span className="text-2xl">{sign.symbol}</span>
<span className="text-[10px] text-muted-foreground mt-1">{sign.name}</span>
</button>
))}
</div>
<div className="bg-muted/50 rounded-lg p-4">
<div className="flex items-center gap-2 mb-2">
<span className="text-3xl">{SIGNS[selected].symbol}</span>
<div>
<h3 className="font-bold text-foreground">{SIGNS[selected].name}</h3>
<p className="text-xs text-muted-foreground">{SIGNS[selected].date} · {SIGNS[selected].element}</p>
</div>
</div>
<p className="text-sm text-foreground/80 leading-relaxed mt-3">
{getDailyText(selected)}
</p>
</div>
</div>
<div className="flex gap-px">
{Array.from({ length: max }).map((_, i) => (
<div key={i} className={`w-1.5 h-1.5 rounded-full ${i < count ? "bg-amber-400" : "bg-white/10"}`} />
))}
</div>
);
}
@ -95,6 +19,7 @@ export function HoroscopeWidget() {
const [paused, setPaused] = useState(false);
const next = useCallback(() => setIndex((i) => (i + 1) % SIGNS.length), []);
const prev = useCallback(() => setIndex((i) => (i - 1 + SIGNS.length) % SIGNS.length), []);
useEffect(() => {
if (paused) return;
@ -103,30 +28,76 @@ export function HoroscopeWidget() {
}, [paused, next]);
const sign = SIGNS[index];
const horoscope = getHoroscope(index);
return (
<div
className="bg-card rounded-lg border border-card-border overflow-hidden h-full w-full cursor-pointer group hover:border-primary/50 transition-colors flex flex-col"
className="rounded-lg border border-card-border overflow-hidden h-full w-full cursor-pointer group hover:border-primary/50 transition-colors flex flex-col"
style={{ background: "linear-gradient(135deg, hsl(250 30% 14%), hsl(270 25% 10%))" }}
onMouseEnter={() => setPaused(true)}
onMouseLeave={() => setPaused(false)}
onClick={() => navigate("/horoskop")}
data-testid="widget-horoscope"
>
<div className="p-3 flex items-center gap-2 border-b border-card-border flex-shrink-0">
<Star className="w-4 h-4 text-primary" />
<h3 className="font-bold text-card-foreground text-sm">Horoskop</h3>
<div className="p-3 flex items-center justify-between border-b border-white/10 flex-shrink-0">
<div className="flex items-center gap-2">
<Star className="w-4 h-4 text-amber-400" />
<h3 className="font-bold text-white text-sm">Horoskop</h3>
</div>
<div className="flex gap-1">
<button
onClick={(e) => { e.stopPropagation(); prev(); }}
className="w-5 h-5 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors"
data-testid="button-horoscope-prev"
>
<ChevronLeft className="w-3 h-3 text-white/70" />
</button>
<button
onClick={(e) => { e.stopPropagation(); next(); }}
className="w-5 h-5 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors"
data-testid="button-horoscope-next"
>
<ChevronRight className="w-3 h-3 text-white/70" />
</button>
</div>
</div>
<div className="p-5 flex-1 flex flex-col justify-center items-center text-center">
<span className="text-7xl mb-4 transition-all duration-500 block">{sign.symbol}</span>
<p className="font-bold text-card-foreground text-lg">{sign.name}</p>
<p className="text-xs text-muted-foreground mt-1">{sign.date}</p>
<p className="text-sm text-muted-foreground mt-4 leading-relaxed">{getDailyText(index)}</p>
<div className="flex justify-center gap-1 mt-5">
<div className="flex-1 flex flex-col">
<div className="p-4 flex items-center gap-3">
<div className="w-14 h-14 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center flex-shrink-0">
<span className="text-3xl">{sign.symbol}</span>
</div>
<div className="flex-1 min-w-0">
<p className="font-bold text-lg text-white">{sign.name}</p>
<p className="text-[10px] text-white/50">{sign.date}</p>
</div>
</div>
<div className="grid grid-cols-3 gap-1 px-3 py-1.5 border-t border-b border-white/5">
<div className="flex flex-col items-center gap-0.5">
<Heart className="w-3 h-3 text-rose-400" />
<MiniStars count={getRating(index, "love")} />
</div>
<div className="flex flex-col items-center gap-0.5">
<Briefcase className="w-3 h-3 text-amber-400" />
<MiniStars count={getRating(index, "career")} />
</div>
<div className="flex flex-col items-center gap-0.5">
<TrendingUp className="w-3 h-3 text-emerald-400" />
<MiniStars count={getRating(index, "health")} />
</div>
</div>
<div className="px-3 pb-3 pt-2 flex-1 flex flex-col justify-between">
<p className="text-xs text-white/60 leading-relaxed line-clamp-5">{horoscope.general}</p>
<p className="text-[10px] text-amber-400 mt-2 group-hover:underline">Mehr lesen</p>
</div>
<div className="flex justify-center gap-1 pb-3">
{SIGNS.map((_, i) => (
<button
key={i}
onClick={(e) => { e.stopPropagation(); setIndex(i); }}
className={`w-1.5 h-1.5 rounded-full transition-all ${i === index ? "bg-primary w-3" : "bg-muted-foreground/30 hover:bg-muted-foreground/50"}`}
className={`w-1.5 h-1.5 rounded-full transition-all ${i === index ? "bg-amber-400 w-3" : "bg-white/15 hover:bg-white/30"}`}
data-testid={`button-horoscope-dot-${i}`}
/>
))}

View File

@ -1,144 +1,57 @@
import { useState } from "react";
import { ChefHat, X, Clock, Users } from "lucide-react";
import { useLocation } from "wouter";
import { ChefHat, Clock, Users } from "lucide-react";
interface Recipe {
interface WidgetRecipe {
title: string;
image: string;
time: string;
servings: string;
ingredients: string[];
steps: string[];
}
const RECIPES: Recipe[] = [
{
title: "Kaiserschmarrn",
image: "https://images.unsplash.com/photo-1621939514649-280e2ee25f60?w=400&h=300&fit=crop",
time: "25 Min.",
servings: "2 Portionen",
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: "https://images.unsplash.com/photo-1599921841143-819065a55cc6?w=400&h=300&fit=crop",
time: "30 Min.",
servings: "4 Portionen",
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: "https://images.unsplash.com/photo-1535920527002-b35e96722eb9?w=400&h=300&fit=crop",
time: "60 Min.",
servings: "6 Portionen",
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: "https://images.unsplash.com/photo-1548940740-204726a19be3?w=400&h=300&fit=crop",
time: "40 Min.",
servings: "4 Portionen",
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: "https://images.unsplash.com/photo-1578985545062-69928b1d9587?w=400&h=300&fit=crop",
time: "90 Min.",
servings: "8 Portionen",
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: "https://images.unsplash.com/photo-1551183053-bf91a1d81141?w=400&h=300&fit=crop",
time: "50 Min.",
servings: "4 Portionen",
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."],
},
const WIDGET_RECIPES: WidgetRecipe[] = [
{ title: "Kaiserschmarrn", image: "/uploads/recipe-kaiserschmarrn.png", time: "25 Min.", servings: "2" },
{ title: "Wiener Schnitzel", image: "/uploads/recipe-wiener-schnitzel.png", time: "30 Min.", servings: "4" },
{ title: "Apfelstrudel", image: "/uploads/recipe-apfelstrudel.png", time: "60 Min.", servings: "6" },
{ title: "Schweinshaxe", image: "/uploads/recipe-schweinshaxe.png", time: "180 Min.", servings: "4" },
{ title: "Käsespätzle", image: "/uploads/recipe-kaesespaetzle.png", time: "45 Min.", servings: "4" },
{ title: "Sachertorte", image: "/uploads/recipe-sachertorte.png", time: "90 Min.", servings: "8" },
{ title: "Maultaschen", image: "/uploads/recipe-maultaschen.png", time: "90 Min.", servings: "4" },
{ title: "Schlutzkrapfen", image: "/uploads/recipe-schlutzkrapfen.png", time: "60 Min.", servings: "4" },
];
function RecipeModal({ recipe, onClose }: { recipe: Recipe; onClose: () => void }) {
export function RecipeWidget() {
const [, navigate] = useLocation();
const dayIndex = Math.floor(Date.now() / 86400000) % WIDGET_RECIPES.length;
const recipe = WIDGET_RECIPES[dayIndex];
return (
<div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4" onClick={onClose} data-testid="modal-recipe">
<div
className="bg-card rounded-xl border border-card-border max-w-lg w-full max-h-[80vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="relative">
<img src={recipe.image} alt={recipe.title} className="w-full h-48 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-close">
<X className="w-4 h-4" />
</button>
</div>
<div className="p-5">
<h2 className="text-xl font-bold text-foreground mb-2">{recipe.title}</h2>
<div className="flex items-center gap-4 text-sm text-muted-foreground mb-4">
<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-4 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>
<button
onClick={() => navigate("/rezepte")}
className="bg-card rounded-lg border border-card-border overflow-hidden h-full w-full text-left cursor-pointer group hover:border-primary/50 transition-colors flex flex-col"
data-testid="widget-recipe"
>
<div className="p-3 flex items-center gap-2 border-b border-card-border flex-shrink-0">
<ChefHat className="w-4 h-4 text-primary" />
<h3 className="font-bold text-card-foreground text-sm">Rezept des Tages</h3>
</div>
<div className="relative flex-1">
<img
src={recipe.image}
alt={recipe.title}
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent" />
<div className="absolute bottom-0 left-0 right-0 p-3">
<h4 className="text-white font-bold text-base">{recipe.title}</h4>
<p className="text-white/60 text-xs mt-0.5 flex items-center gap-2">
<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>
</p>
<p className="text-[10px] text-primary mt-1 group-hover:underline">Alle Rezepte ansehen</p>
</div>
</div>
</div>
);
}
export function RecipeWidget() {
const [showRecipe, setShowRecipe] = useState<Recipe | null>(null);
const dayIndex = Math.floor(Date.now() / 86400000) % RECIPES.length;
const recipe = RECIPES[dayIndex];
return (
<>
<button
onClick={() => setShowRecipe(recipe)}
className="bg-card rounded-lg border border-card-border overflow-hidden h-full w-full text-left cursor-pointer group hover:border-primary/50 transition-colors flex flex-col"
data-testid="widget-recipe"
>
<div className="p-3 flex items-center gap-2 border-b border-card-border flex-shrink-0">
<ChefHat className="w-4 h-4 text-primary" />
<h3 className="font-bold text-card-foreground text-sm">Rezept des Tages</h3>
</div>
<div className="relative flex-1">
<img
src={recipe.image}
alt={recipe.title}
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent" />
<div className="absolute bottom-0 left-0 right-0 p-3">
<h4 className="text-white font-bold text-base">{recipe.title}</h4>
<p className="text-white/60 text-xs mt-0.5 flex items-center gap-2">
<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>
</p>
</div>
</div>
</button>
{showRecipe && <RecipeModal recipe={showRecipe} onClose={() => setShowRecipe(null)} />}
</>
</button>
);
}

View File

@ -0,0 +1,222 @@
export const ELEMENT_COLORS: Record<string, { bg: string; border: string; text: string; glow: string }> = {
Feuer: { bg: "bg-red-500/10", border: "border-red-500/30", text: "text-red-400", glow: "shadow-red-500/20" },
Erde: { bg: "bg-emerald-500/10", border: "border-emerald-500/30", text: "text-emerald-400", glow: "shadow-emerald-500/20" },
Luft: { bg: "bg-violet-500/10", border: "border-violet-500/30", text: "text-violet-400", glow: "shadow-violet-500/20" },
Wasser: { bg: "bg-blue-500/10", border: "border-blue-500/30", text: "text-blue-400", glow: "shadow-blue-500/20" },
};
export const SIGNS = [
{ name: "Widder", symbol: "♈", date: "21.03 19.04", element: "Feuer", planet: "Mars", color: "Rot", stone: "Diamant", compatible: ["Löwe", "Schütze", "Zwillinge"] },
{ name: "Stier", symbol: "♉", date: "20.04 20.05", element: "Erde", planet: "Venus", color: "Grün", stone: "Smaragd", compatible: ["Jungfrau", "Steinbock", "Krebs"] },
{ name: "Zwillinge", symbol: "♊", date: "21.05 20.06", element: "Luft", planet: "Merkur", color: "Gelb", stone: "Achat", compatible: ["Waage", "Wassermann", "Widder"] },
{ name: "Krebs", symbol: "♋", date: "21.06 22.07", element: "Wasser", planet: "Mond", color: "Silber", stone: "Mondstein", compatible: ["Skorpion", "Fische", "Stier"] },
{ name: "Löwe", symbol: "♌", date: "23.07 22.08", element: "Feuer", planet: "Sonne", color: "Gold", stone: "Rubin", compatible: ["Widder", "Schütze", "Waage"] },
{ name: "Jungfrau", symbol: "♍", date: "23.08 22.09", element: "Erde", planet: "Merkur", color: "Braun", stone: "Saphir", compatible: ["Stier", "Steinbock", "Skorpion"] },
{ name: "Waage", symbol: "♎", date: "23.09 22.10", element: "Luft", planet: "Venus", color: "Rosa", stone: "Opal", compatible: ["Zwillinge", "Wassermann", "Löwe"] },
{ name: "Skorpion", symbol: "♏", date: "23.10 21.11", element: "Wasser", planet: "Pluto", color: "Dunkelrot", stone: "Topas", compatible: ["Krebs", "Fische", "Jungfrau"] },
{ name: "Schütze", symbol: "♐", date: "22.11 21.12", element: "Feuer", planet: "Jupiter", color: "Violett", stone: "Türkis", compatible: ["Widder", "Löwe", "Wassermann"] },
{ name: "Steinbock", symbol: "♑", date: "22.12 19.01", element: "Erde", planet: "Saturn", color: "Schwarz", stone: "Granat", compatible: ["Stier", "Jungfrau", "Fische"] },
{ name: "Wassermann", symbol: "♒", date: "20.01 18.02", element: "Luft", planet: "Uranus", color: "Blau", stone: "Amethyst", compatible: ["Zwillinge", "Waage", "Schütze"] },
{ name: "Fische", symbol: "♓", date: "19.02 20.03", element: "Wasser", planet: "Neptun", color: "Meeresblau", stone: "Aquamarin", compatible: ["Krebs", "Skorpion", "Steinbock"] },
];
export const DAILY_HOROSCOPES = [
{
general: "Ein wunderbarer Tag für neue Begegnungen. Die Sterne stehen günstig für spontane Entscheidungen. Sie spüren eine besondere Energie, die Sie antreibt, Neues zu wagen. Nutzen Sie diese Kraft und gehen Sie auf Menschen zu unerwartete Gespräche könnten Ihr Leben bereichern. Ihr natürlicher Optimismus strahlt heute besonders hell und zieht positive Situationen an.",
love: "In der Liebe zeigt sich heute eine besondere Verbindung. Singles könnten jemand Besonderen treffen halten Sie die Augen offen! Paare erleben einen harmonischen Tag voller Zärtlichkeit. Ein romantisches Abendessen oder ein gemeinsamer Spaziergang stärkt Ihre Beziehung.",
career: "Beruflich stehen die Zeichen auf Erfolg. Ein neues Projekt könnte sich anbieten, das Ihre Fähigkeiten perfekt zur Geltung bringt. Zeigen Sie Initiative und Ihr Vorgesetzter wird beeindruckt sein. Finanzielle Entscheidungen sollten heute wohlüberlegt getroffen werden.",
health: "Ihre Vitalität ist heute auf einem Höhepunkt. Nutzen Sie die Energie für sportliche Aktivitäten oder einen langen Spaziergang in der Natur. Achten Sie darauf, ausreichend Wasser zu trinken und gönnen Sie sich am Abend eine entspannende Auszeit.",
tip: "Tragen Sie heute etwas Rotes es verstärkt Ihre natürliche Ausstrahlung und zieht positive Energie an.",
weekly: "Diese Woche steht im Zeichen des Neuanfangs. Am Montag und Dienstag sollten Sie wichtige Gespräche führen. Mittwoch bringt eine überraschende Wendung in finanziellen Angelegenheiten. Das Wochenende eignet sich perfekt für romantische Unternehmungen und Familientreffen.",
monthly: "Der Monat beginnt mit einer Phase der Kreativität und neuer Ideen. Ab Mitte des Monats rückt die Karriere in den Vordergrund nutzen Sie die Chance für berufliche Veränderungen. Ende des Monats bringt Venus harmonische Energien für Ihre Beziehungen."
},
{
general: "Heute ist Geduld gefragt. Lassen Sie sich Zeit und genießen Sie die kleinen Freuden des Alltags. Nicht alles muss sofort erledigt werden manchmal bringt ein langsameres Tempo bessere Ergebnisse. Die Sterne empfehlen Ihnen, sich auf das Wesentliche zu konzentrieren und unnötigen Stress zu vermeiden. Am Nachmittag lichtet sich der Nebel und Sie sehen klarer.",
love: "Die Liebe braucht heute besondere Aufmerksamkeit. Nehmen Sie sich Zeit für tiefgründige Gespräche mit Ihrem Partner. Singles sollten nicht zu schnell urteilen der erste Eindruck kann täuschen. Ein zweiter Blick lohnt sich, denn wahre Schönheit zeigt sich erst bei näherem Kennenlernen.",
career: "Im Beruf ist Beharrlichkeit der Schlüssel zum Erfolg. Ein schwieriges Projekt erfordert Ihre volle Konzentration. Lassen Sie sich nicht von Rückschlägen entmutigen Ihr Durchhaltevermögen wird sich langfristig auszahlen. Finanziell ist Sparsamkeit angesagt.",
health: "Achten Sie heute besonders auf Ihre Ernährung. Frisches Obst und Gemüse geben Ihrem Körper die nötigen Vitamine. Eine kurze Meditation am Morgen oder Abend hilft Ihnen, innere Ruhe zu finden und den Alltagsstress abzubauen.",
tip: "Kochen Sie heute Ihr Lieblingsgericht es nährt nicht nur den Körper, sondern auch die Seele.",
weekly: "Geduld ist diese Woche Ihre Stärke. Anfang der Woche klären sich finanzielle Fragen. Donnerstag und Freitag sind ideal für wichtige Verhandlungen. Am Wochenende belohnen Sie sich für Ihre harte Arbeit mit einem besonderen Genuss.",
monthly: "Dieser Monat fördert Ihre materielle Sicherheit. Saturn unterstützt langfristige Investitionen. In der Monatsmitte stärkt ein Vollmond Ihre emotionalen Beziehungen. Gegen Ende des Monats ergeben sich neue berufliche Perspektiven."
},
{
general: "Kommunikation steht im Vordergrund. Ein gutes Gespräch kann heute Wunder wirken. Ihre Worte haben besondere Kraft und können Brücken bauen. Nutzen Sie diese Gabe, um Missverständnisse zu klären oder neue Kontakte zu knüpfen. Am Abend erwartet Sie eine überraschende Nachricht, die Ihre Stimmung hebt.",
love: "Reden Sie über Ihre Gefühle! Heute ist der perfekte Tag, um Ihrem Partner oder einer besonderen Person mitzuteilen, was Sie empfinden. Offenheit wird belohnt und kann Ihre Beziehung auf ein neues Level heben. Singles sollten gesellige Orte aufsuchen.",
career: "Ein wichtiges Meeting oder Telefonat könnte heute den Durchbruch bringen. Bereiten Sie sich gut vor und präsentieren Sie Ihre Ideen selbstbewusst. Teamarbeit steht unter einem guten Stern gemeinsam erreichen Sie mehr als allein.",
health: "Soziale Kontakte sind heute Ihre beste Medizin. Ein Treffen mit Freunden oder ein anregendes Gespräch mit einem Kollegen hebt Ihre Stimmung und stärkt Ihr Wohlbefinden. Achten Sie auf ausreichend Schlaf Ihr Geist braucht Erholung.",
tip: "Schreiben Sie jemandem, den Sie schon lange nicht mehr kontaktiert haben es wird beiden guttun.",
weekly: "Eine kommunikationsreiche Woche erwartet Sie. Montag und Dienstag bringen wichtige Nachrichten. Am Mittwoch ist ein guter Zeitpunkt für kreative Projekte. Das Wochenende lädt zu geselligen Aktivitäten und neuen Bekanntschaften ein.",
monthly: "Merkur verleiht Ihnen diesen Monat besondere Überzeugungskraft. Berufliche Präsentationen und Verhandlungen gelingen mühelos. Ab der Monatsmitte rücken Reisen und Weiterbildung in den Fokus. Ende des Monats bringt spannende soziale Ereignisse."
},
{
general: "Vertrauen Sie auf Ihre Intuition. Ihr Bauchgefühl weist Ihnen den richtigen Weg. Heute spüren Sie besonders deutlich, was richtig und was falsch ist. Lassen Sie sich nicht von der Meinung anderer beirren Ihre innere Stimme kennt die Antwort. Am Abend finden Sie Ruhe und Klarheit.",
love: "Emotionale Tiefe prägt heute Ihre Beziehungen. Sie spüren intuitiv, was Ihr Partner braucht, und können liebevoll darauf eingehen. Singles erkennen sofort, ob jemand zu ihnen passt. Vertrauen Sie diesem Gefühl es wird Sie nicht täuschen.",
career: "Kreative Lösungen sind heute gefragt. Verlassen Sie ausgetretene Pfade und denken Sie um die Ecke. Ihre Intuition führt Sie zu innovativen Ansätzen, die andere beeindrucken werden. Finanzielle Entscheidungen sollten aus dem Bauch heraus getroffen werden.",
health: "Hören Sie heute besonders auf Ihren Körper. Wenn er Ruhe fordert, gönnen Sie sie ihm. Ein warmes Bad, beruhigende Musik oder eine Tasse Kräutertee können Wunder wirken. Yoga oder leichte Dehnübungen harmonisieren Körper und Geist.",
tip: "Zünden Sie am Abend eine Kerze an und nehmen Sie sich zehn Minuten nur für sich Meditation oder einfaches Stillsein.",
weekly: "Eine intuitive Woche, in der Sie Ihrem Bauchgefühl folgen sollten. Dienstag bringt emotionale Klarheit. Donnerstag und Freitag sind günstig für familiäre Angelegenheiten. Am Wochenende finden Sie Erholung am Wasser oder in der Natur.",
monthly: "Der Mond schenkt Ihnen diesen Monat besondere emotionale Stärke. Familiäre Bindungen vertiefen sich in der ersten Monatshälfte. Ab Mitte des Monats rückt Ihr häusliches Umfeld in den Fokus ideale Zeit für Renovierungen. Monatsende bringt romantische Überraschungen."
},
{
general: "Kreativität und Mut werden heute belohnt. Zeigen Sie, was in Ihnen steckt! Die kosmische Energie unterstützt alle künstlerischen und kreativen Vorhaben. Ob Musik, Malerei oder ein neues Projekt jetzt ist die Zeit, Ihre Talente zu zeigen. Ihre Begeisterung ist ansteckend und inspiriert auch andere.",
love: "Romantik liegt in der Luft! Überraschen Sie Ihren Partner mit einer liebevollen Geste oder einem spontanen Ausflug. Singles strahlen heute eine besondere Anziehungskraft aus nutzen Sie das! Ein Flirt beim Konzert oder Festival könnte der Beginn von etwas Schönem sein.",
career: "Ihre kreative Seite ist heute Ihr größtes Kapital. Neue Ideen sprudeln nur so aus Ihnen heraus und finden Anerkennung bei Kollegen und Vorgesetzten. Ein Moment im Rampenlicht steht bevor genießen Sie ihn! Finanziell könnten sich neue Möglichkeiten ergeben.",
health: "Bewegung und Aktivität tun Ihnen heute besonders gut. Tanzen Sie zu Ihrer Lieblingsmusik, gehen Sie schwimmen oder machen Sie einen Ausflug in die Berge. Ihre Energie ist grenzenlos nutzen Sie sie für Aktivitäten, die Ihnen Freude bereiten.",
tip: "Hören Sie heute bewusst Volksmusik oder besuchen Sie ein Konzert Musik nährt die Seele.",
weekly: "Eine glamouröse Woche voller Möglichkeiten! Am Montag starten Sie mit Energie durch. Mittwoch bringt kreative Inspiration. Freitag und Samstag sind perfekt für gesellschaftliche Ereignisse, bei denen Sie im Mittelpunkt stehen.",
monthly: "Die Sonne stärkt Ihr Selbstbewusstsein den ganzen Monat über. Kreative Projekte gelingen in der ersten Woche besonders gut. Mitte des Monats bringt beruflichen Aufstieg. Ende des Monats eignet sich für große romantische Gesten und Feiern."
},
{
general: "Ordnung und Struktur bringen heute den Erfolg. Nutzen Sie die Energie für wichtige Aufgaben. Ein gut organisierter Tag bringt mehr Ergebnisse als hektisches Multitasking. Erstellen Sie eine Prioritätenliste und arbeiten Sie sie Schritt für Schritt ab. Am Ende des Tages werden Sie stolz auf das Erreichte sein.",
love: "Kleine Aufmerksamkeiten machen heute den Unterschied in der Liebe. Ein liebevoll zubereitetes Frühstück, eine handgeschriebene Nachricht oder ein unerwartetes Kompliment es sind die Details, die zählen. Singles sollten ihre Ansprüche nicht zu hoch schrauben.",
career: "Perfektion ist heute Ihr Markenzeichen. Nutzen Sie Ihren Blick fürs Detail, um ein wichtiges Projekt zu vervollständigen. Kollegen schätzen Ihre Zuverlässigkeit und Gründlichkeit. Ein Gespräch mit dem Chef könnte positive Entwicklungen anstoßen.",
health: "Strukturieren Sie Ihre Mahlzeiten und achten Sie auf regelmäßige Pausen. Ein aufgeräumter Arbeitsplatz und ein ordentliches Zuhause tragen zu Ihrem Wohlbefinden bei. Am Abend sorgt ein gutes Buch für die nötige Entspannung.",
tip: "Räumen Sie heute eine Schublade oder einen Schrank auf äußere Ordnung schafft innere Klarheit.",
weekly: "Diese Woche ist ideal für Planung und Organisation. Anfang der Woche setzen Sie Prioritäten. Mittwoch und Donnerstag bringen Fortschritte bei wichtigen Projekten. Das Wochenende eignet sich für Gesundheitsvorsorge und Wellness.",
monthly: "Merkur fördert Ihre analytischen Fähigkeiten den ganzen Monat. Gesundheitliche Verbesserungen zeigen sich ab der zweiten Woche. Berufliche Anerkennung kommt zur Monatsmitte. Ende des Monats bringt finanzielle Klarheit und neue Sparmöglichkeiten."
},
{
general: "Harmonie und Ausgeglichenheit bestimmen den Tag. Genießen Sie die Zeit mit Ihren Liebsten. Die Sterne schenken Ihnen heute ein besonderes Gespür für Schönheit und Ästhetik. Umgeben Sie sich mit angenehmen Dingen und Menschen, die Ihnen guttun. Konflikte lassen sich heute leicht lösen.",
love: "Ein Tag wie geschaffen für die Liebe! Paare erleben eine Phase tiefer Verbundenheit und gegenseitigen Verständnisses. Gemeinsame Aktivitäten stärken die Beziehung. Singles sollten sich schick machen und ausgehen Venus begünstigt neue Begegnungen.",
career: "Diplomatie ist heute Ihre Stärke. Vermitteln Sie geschickt zwischen verschiedenen Positionen und finden Sie Kompromisse, mit denen alle zufrieden sind. Ihre soziale Kompetenz wird anerkannt und könnte zu einer Beförderung führen.",
health: "Gönnen Sie sich heute etwas Besonderes einen Wellness-Tag, ein entspannendes Bad oder eine Massage. Ihr Körper und Geist verdienen Verwöhnung. Schöne Musik und gutes Essen tragen zu Ihrem Wohlbefinden bei.",
tip: "Besuchen Sie heute ein Museum, eine Ausstellung oder einen schönen Garten Schönheit nährt die Seele.",
weekly: "Venus schenkt Ihnen eine harmonische Woche. Montag und Dienstag sind ideal für Partnerschaftsgespräche. Donnerstag bringt eine kreative Überraschung. Am Wochenende genießen Sie Kultur, Kunst und gute Gesellschaft.",
monthly: "Dieser Monat steht unter dem Zeichen der Harmonie. Beziehungen vertiefen sich in den ersten zwei Wochen. Kreative Projekte blühen zur Monatsmitte auf. Ende des Monats bringt gesellschaftliche Höhepunkte und neue Freundschaften."
},
{
general: "Tiefgründige Erkenntnisse warten auf Sie. Nehmen Sie sich Zeit für Reflexion. Heute können Sie unter die Oberfläche schauen und verborgene Wahrheiten entdecken. Ihre analytische Kraft ist besonders stark nutzen Sie sie, um wichtige Lebensfragen zu beantworten. Transformation und Wandel liegen in der Luft.",
love: "Intensive Emotionen prägen heute Ihre Beziehungen. Tiefe Gespräche über Wünsche und Sehnsüchte bringen Sie und Ihren Partner näher zusammen. Singles könnten eine magnetische Anziehung zu einer bestimmten Person spüren lassen Sie sich darauf ein.",
career: "Forschen Sie heute tiefer ob bei der Arbeit oder in persönlichen Projekten. Ihre Fähigkeit, Zusammenhänge zu erkennen, die anderen verborgen bleiben, macht Sie heute unverzichtbar. Finanzielle Angelegenheiten erfordern gründliche Analyse.",
health: "Emotionale Reinigung steht an. Lassen Sie alte Verletzungen los und vergeben Sie sich selbst und anderen. Ein Tagebucheintrag oder ein Gespräch mit einer Vertrauensperson kann befreiend wirken. Achten Sie auf ausreichend Schlaf.",
tip: "Schreiben Sie heute Ihre Gedanken und Gefühle auf das Aufschreiben wirkt klärend und befreiend.",
weekly: "Eine transformative Woche erwartet Sie. Dienstag bringt wichtige Erkenntnisse. Donnerstag ist günstig für finanzielle Entscheidungen. Am Wochenende können Sie alte Muster loslassen und Platz für Neues schaffen.",
monthly: "Pluto fördert tiefgreifende Veränderungen in diesem Monat. Die erste Woche bringt emotionale Durchbrüche. Finanzen verbessern sich zur Monatsmitte. Ende des Monats stärkt Ihre Willenskraft und Entschlossenheit für neue Ziele."
},
{
general: "Abenteuerlust liegt in der Luft! Planen Sie etwas Besonderes für heute. Die Sterne wecken Ihre Reiselust und den Wunsch nach neuen Erfahrungen. Ob ein Tagesausflug in die Berge, ein neues Restaurant oder ein spannendes Buch erweitern Sie Ihren Horizont! Optimismus und Lebensfreude begleiten Sie durch den Tag.",
love: "Abenteuer zu zweit stärken die Beziehung. Planen Sie etwas Ungewöhnliches mit Ihrem Partner ein spontaner Ausflug oder ein gemeinsames Hobby. Singles finden die Liebe an unerwarteten Orten vielleicht bei einer Wanderung oder auf einem Volksfest.",
career: "Denken Sie heute groß! Neue berufliche Chancen könnten sich am Horizont zeigen. Internationale Kontakte oder Weiterbildungen stehen unter einem guten Stern. Ihre Begeisterungsfähigkeit öffnet Türen, die anderen verschlossen bleiben.",
health: "Bewegung an der frischen Luft ist heute das beste Rezept für Körper und Seele. Eine Wanderung, Radtour oder ein Spaziergang durch die Natur laden Ihre Batterien auf. Probieren Sie ein neues Gericht aus einer anderen Kultur es bereichert Ihren Speiseplan.",
tip: "Machen Sie heute etwas, das Sie noch nie gemacht haben neue Erfahrungen halten jung und vital.",
weekly: "Eine abenteuerliche Woche! Montag startet mit Reiselust. Mittwoch und Donnerstag bringen Lernmöglichkeiten. Freitag ist ideal für kulturelle Erlebnisse. Am Wochenende zieht es Sie in die Ferne folgen Sie dem Ruf!",
monthly: "Jupiter erweitert Ihren Horizont diesen Monat. Reisemöglichkeiten ergeben sich in der ersten Hälfte. Weiterbildung und neue Kenntnisse stehen ab der Monatsmitte im Fokus. Ende des Monats bringt philosophische Erkenntnisse und spirituelles Wachstum."
},
{
general: "Disziplin und Ausdauer zahlen sich aus. Bleiben Sie an Ihren Zielen dran. Die kosmische Energie unterstützt heute alle langfristigen Pläne und ambitionierten Vorhaben. Setzen Sie sich realistische Ziele und arbeiten Sie konsequent darauf hin. Geduld ist Ihre Stärke Erfolg kommt Schritt für Schritt.",
love: "Stabilität und Verlässlichkeit sind heute die Pfeiler Ihrer Beziehung. Zeigen Sie Ihrem Partner, dass er sich auf Sie verlassen kann. Gemeinsame Zukunftspläne zu schmieden stärkt Ihre Verbindung. Singles sollten nach jemandem Ausschau halten, der ihre Werte teilt.",
career: "Heute ist der Tag für wichtige berufliche Entscheidungen. Ihre Erfahrung und Kompetenz werden anerkannt. Führungsqualitäten kommen zum Vorschein und ebnen den Weg für einen Aufstieg. Finanzielle Disziplin zahlt sich langfristig aus.",
health: "Regelmäßigkeit ist heute der Schlüssel zu Ihrem Wohlbefinden. Halten Sie sich an Ihre Routinen regelmäßige Mahlzeiten, Bewegung und ausreichend Schlaf. Ihre Knochen und Gelenke freuen sich über sanfte Dehnübungen.",
tip: "Setzen Sie sich heute ein kleines Ziel und erreichen Sie es Erfolgserlebnisse stärken das Selbstvertrauen.",
weekly: "Eine disziplinierte Woche, die Ergebnisse bringt. Anfang der Woche setzen Sie berufliche Meilensteine. Mittwoch ist günstig für Finanzplanung. Donnerstag und Freitag bringen Anerkennung. Das Wochenende eignet sich für Familientraditionen.",
monthly: "Saturn belohnt Ihre Ausdauer in diesem Monat. Beruflicher Aufstieg zeichnet sich in der ersten Woche ab. Finanzielle Stabilität festigt sich zur Monatsmitte. Ende des Monats bringt Anerkennung und verdiente Erfolge in allen Lebensbereichen."
},
{
general: "Originelle Ideen kommen heute von ganz allein. Lassen Sie Ihrer Fantasie freien Lauf. Die Sterne begünstigen unkonventionelles Denken und innovative Lösungen. Sie sehen Dinge aus einer einzigartigen Perspektive, die andere inspiriert. Gemeinschaftliche Aktivitäten und Freundschaften stehen unter einem besonders guten Stern.",
love: "Freiheit und Nähe in Balance zu halten ist heute das Thema in der Liebe. Geben Sie Ihrem Partner Raum und genießen Sie gleichzeitig die gemeinsame Zeit. Singles treffen heute interessante Menschen in Gruppen oder bei Vereinsaktivitäten.",
career: "Innovation ist heute gefragt! Ihre unkonventionellen Ideen fallen auf fruchtbaren Boden. Teamarbeit bringt heute die besten Ergebnisse tauschen Sie sich mit Gleichgesinnten aus. Technologische Neuerungen könnten Ihre Arbeit revolutionieren.",
health: "Gruppenaktivitäten wie Sport im Verein, Wandergruppen oder gemeinsames Kochen tun Ihnen heute besonders gut. Der soziale Aspekt stärkt nicht nur den Körper, sondern auch die Seele. Probieren Sie eine neue Sportart oder Entspannungstechnik aus.",
tip: "Engagieren Sie sich heute für eine gute Sache Altruismus macht glücklich und erfüllt.",
weekly: "Eine innovative Woche! Montag und Dienstag bringen kreative Durchbrüche. Mittwoch ist ideal für Teamarbeit. Freitag überrascht mit unerwarteten Möglichkeiten. Am Wochenende pflegen Sie Freundschaften und soziale Netzwerke.",
monthly: "Uranus bringt überraschende Wendungen in diesem Monat. Technologische Neuerungen eröffnen Chancen in der ersten Hälfte. Freundschaften vertiefen sich zur Monatsmitte. Ende des Monats bringt humanitäre Projekte und Gemeinschaftsgeist."
},
{
general: "Einfühlungsvermögen und Mitgefühl stärken heute Ihre Beziehungen. Die Sterne schärfen Ihre Sensibilität und Ihr Gespür für die Gefühle anderer. Kreative und spirituelle Aktivitäten stehen unter einem besonders guten Stern. Musik, Kunst und Natur sind heute Ihre Kraftquellen.",
love: "Romantische Träume können heute wahr werden. Ihre einfühlsame Art berührt andere Menschen tief. Paare erleben Momente tiefer emotionaler Verbundenheit. Singles könnten eine fast schicksalhafte Begegnung haben bei einem Konzert, am Wasser oder in einer kreativen Umgebung.",
career: "Kreative Berufe profitieren heute besonders von der kosmischen Energie. Musiker, Künstler und alle, die mit Menschen arbeiten, haben einen glücklichen Tag. Lassen Sie sich von Ihrer Intuition leiten sie führt Sie zu den richtigen Entscheidungen.",
health: "Wasser ist heute Ihr Element ob ein Besuch am See, ein langes Bad oder einfach genug trinken. Meditation und Entspannungsübungen harmonisieren Körper und Geist. Gönnen Sie sich Musik, die Ihre Seele berührt Volksmusik oder klassische Klänge wirken heilsam.",
tip: "Setzen Sie sich heute an einen ruhigen Ort in der Natur und lauschen Sie die Stille hat heilende Kraft.",
weekly: "Eine spirituelle und kreative Woche. Montag und Dienstag bringen künstlerische Inspiration. Mittwoch eignet sich für Meditation und innere Einkehr. Freitag überrascht mit einer romantischen Begegnung. Am Wochenende finden Sie Heilung am Wasser.",
monthly: "Neptun verstärkt Ihre Intuition den ganzen Monat. Kreative Projekte blühen in der ersten Woche auf. Spirituelles Wachstum zeigt sich zur Monatsmitte. Ende des Monats bringt traumhafte romantische Momente und künstlerische Erfolge."
},
];
export interface AstroEvent {
title: string;
description: string;
dateRange: string;
icon: string;
affectedSigns: string[];
type: "retrograde" | "moon" | "transit" | "season";
}
export const ASTRO_EVENTS: AstroEvent[] = [
{
title: "Merkur Retrograde",
description: "Merkur ist rückläufig und sorgt für Verzögerungen in Kommunikation und Technik. Verträge und wichtige Entscheidungen sollten verschoben werden. Nutzen Sie die Zeit für Reflexion und das Überdenken alter Pläne.",
dateRange: "25. Februar 20. März 2026",
icon: "mercury",
affectedSigns: ["Zwillinge", "Jungfrau", "Fische", "Schütze"],
type: "retrograde",
},
{
title: "Vollmond im Zeichen Jungfrau",
description: "Der Vollmond in der Jungfrau bringt Klarheit in Gesundheits- und Arbeitsfragen. Ein guter Zeitpunkt, um Ordnung zu schaffen und alte Gewohnheiten zu überdenken. Emotionale Themen kommen ans Licht.",
dateRange: "1. März 2026",
icon: "moon",
affectedSigns: ["Jungfrau", "Fische", "Zwillinge", "Schütze"],
type: "moon",
},
{
title: "Venus im Widder",
description: "Venus im Widder bringt Leidenschaft und Spontaneität in die Liebe. Neue Beziehungen können sich blitzschnell entwickeln. Singles sind besonders mutig bei der Partnersuche.",
dateRange: "27. Februar 23. März 2026",
icon: "venus",
affectedSigns: ["Widder", "Löwe", "Schütze", "Waage"],
type: "transit",
},
{
title: "Fische-Saison",
description: "Die Sonne im Zeichen Fische fördert Intuition, Kreativität und Mitgefühl. Eine Zeit für spirituelle Entwicklung und künstlerische Projekte. Träume sind jetzt besonders aussagekräftig.",
dateRange: "19. Februar 20. März 2026",
icon: "sun",
affectedSigns: ["Fische", "Krebs", "Skorpion", "Steinbock"],
type: "season",
},
{
title: "Saturn im Widder",
description: "Saturn fordert Disziplin und Verantwortung in neuen Projekten. Langfristige Ziele brauchen jetzt eine solide Grundlage. Geduld und Ausdauer werden belohnt.",
dateRange: "ab 25. Mai 2025",
icon: "saturn",
affectedSigns: ["Widder", "Krebs", "Waage", "Steinbock"],
type: "transit",
},
{
title: "Neumond im Zeichen Fische",
description: "Der Neumond in den Fischen ist ideal für neue Anfänge im spirituellen und kreativen Bereich. Setzen Sie Intentionen für Mitgefühl und innere Heilung. Meditation und Rückzug werden empfohlen.",
dateRange: "14. März 2026",
icon: "newmoon",
affectedSigns: ["Fische", "Krebs", "Skorpion", "Jungfrau"],
type: "moon",
},
];
export function getDayOfYear(): number {
return Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0).getTime()) / 86400000);
}
export function getHoroscope(signIndex: number) {
const day = getDayOfYear();
return DAILY_HOROSCOPES[(signIndex + day) % DAILY_HOROSCOPES.length];
}
export function getRating(signIndex: number, category: string): number {
const day = getDayOfYear();
const hash = (signIndex * 7 + day * 3 + category.length) % 5;
return Math.max(3, hash + 3);
}
export function getLuckyNumbers(signIndex: number): number[] {
const day = getDayOfYear();
const nums: number[] = [];
for (let i = 0; i < 3; i++) {
nums.push(((signIndex * 13 + day * 7 + i * 11) % 49) + 1);
}
return [...new Set(nums)];
}
export function getDailyColor(signIndex: number): string {
const colors = ["Rot", "Blau", "Grün", "Gold", "Silber", "Violett", "Orange", "Rosa", "Türkis", "Weiß", "Bernstein", "Indigo"];
const day = getDayOfYear();
return colors[(signIndex + day) % colors.length];
}

View File

@ -3,11 +3,11 @@ import { Link } from "wouter";
import { type Article } from "@shared/schema";
import { format } from "date-fns";
import { de } from "date-fns/locale";
import { Eye, Play, ChevronRight, Images } from "lucide-react";
import { Eye, Play, Images } from "lucide-react";
import { Skeleton } from "@/components/ui/skeleton";
import Header from "@/components/header";
import Footer from "@/components/footer";
import AdSense, { ArticleCardAd } from "@/components/adsense";
import AdSense from "@/components/adsense";
import { PhotoGalleryWidget } from "@/components/photo-gallery";
import { HoroscopeWidget } from "@/components/horoscope-widget";
import { RecipeWidget } from "@/components/recipe-widget";
@ -129,37 +129,6 @@ function MediumCard({ article }: { article: Article }) {
);
}
function GalleryMediumCard({ images }: { images: GalleryImage[] }) {
const [idx, setIdx] = useState(0);
useEffect(() => {
const timer = setInterval(() => setIdx((i) => (i + 1) % images.length), 5000);
return () => clearInterval(timer);
}, [images.length]);
return (
<Link href="/gallery">
<div className="relative group cursor-pointer rounded-lg overflow-hidden h-full bg-card border border-card-border" data-testid="card-medium-gallery">
<div className="relative">
<div className="overflow-hidden">
<img src={images[idx].large || images[idx].thumb} alt={images[idx].fileName} className="w-full aspect-video object-cover transition-opacity duration-700" style={{ objectPosition: "center 25%" }} loading="lazy" />
</div>
<div className="absolute bottom-2 right-2 bg-black/60 rounded px-1.5 py-0.5 flex items-center gap-1">
<Images className="w-3 h-3 text-white/80" />
<span className="text-[10px] text-white/80">{images.length}</span>
</div>
</div>
<div className="p-3.5">
<div className="flex items-center gap-2 mb-1.5">
<span className="text-[10px] font-medium text-primary">Fotogalerie</span>
</div>
<h3 className="font-semibold text-card-foreground text-sm leading-snug line-clamp-2 group-hover:text-primary transition-colors">Exklusive Backstage-Fotos</h3>
</div>
</div>
</Link>
);
}
function NativeAdCard() {
return (
<div className="relative rounded-lg overflow-hidden h-full bg-card border border-card-border" data-testid="card-native-ad">
@ -269,16 +238,6 @@ function FeaturedCarousel({ articles, popular, galleryImages }: { articles: Arti
);
}
function SectionLink({ href, label }: { href: string; label: string }) {
return (
<Link href={href}>
<span className="flex items-center gap-1 text-xs text-primary hover:underline cursor-pointer mt-2">
{label} <ChevronRight className="w-3 h-3" />
</span>
</Link>
);
}
function BentoSkeleton() {
return (
<div className="space-y-4">
@ -318,9 +277,10 @@ export default function Home() {
);
}
const row2Articles = articles.slice(0, 4);
const row3Articles = articles.slice(4, 7);
const row4Articles = articles.slice(7, 10);
const row2Left = articles.slice(0, 2);
const row3Middle = articles.slice(2, 4);
const row4Articles = articles.slice(4, 7);
const row5Articles = articles.slice(7, 10);
return (
<div className="min-h-screen bg-background">
@ -329,44 +289,42 @@ export default function Home() {
<FeaturedCarousel articles={articles} popular={popular} galleryImages={galleryImages} />
{row2Articles.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row2Articles.map((a) => (
<MediumCard key={a.id} article={a} />
))}
</div>
)}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 auto-rows-fr">
<div className="aspect-[4/5]">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row2Left.map((a) => (
<MediumCard key={a.id} article={a} />
))}
<div className="aspect-[4/5] sm:aspect-auto">
<PhotoGalleryWidget />
</div>
<div className="aspect-[4/5]">
<div className="aspect-[4/5] sm:aspect-auto">
<RecipeWidget />
</div>
</div>
<div className="aspect-[4/5]">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="aspect-[4/5] sm:aspect-auto">
<HoroscopeWidget />
</div>
<div className="aspect-[4/5]">
{row3Middle.map((a) => (
<MediumCard key={a.id} article={a} />
))}
<div className="aspect-[4/5] sm:aspect-auto">
<NewsWidget />
</div>
</div>
{row3Articles.length > 0 && (
{row4Articles.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row3Articles.map((a) => (
{row4Articles.map((a) => (
<MediumCard key={a.id} article={a} />
))}
<NativeAdCard />
</div>
)}
{row4Articles.length > 0 && (
{row5Articles.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row4Articles.slice(0, 3).map((a) => (
{row5Articles.map((a) => (
<MediumCard key={a.id} article={a} />
))}
<NativeAdCard />

View File

@ -1,126 +1,17 @@
import { useState } from "react";
import { Link } from "wouter";
import { Star, Heart, Briefcase, TrendingUp, ChevronLeft } from "lucide-react";
import { Star, Heart, Briefcase, TrendingUp, ChevronLeft, Calendar, CalendarDays, Sparkles, Lightbulb } from "lucide-react";
import Header from "@/components/header";
import Footer from "@/components/footer";
import { InArticleAd } from "@/components/adsense";
const SIGNS = [
{ name: "Widder", symbol: "♈", date: "21.03 19.04", element: "Feuer", planet: "Mars", color: "Rot", stone: "Diamant" },
{ name: "Stier", symbol: "♉", date: "20.04 20.05", element: "Erde", planet: "Venus", color: "Grün", stone: "Smaragd" },
{ name: "Zwillinge", symbol: "♊", date: "21.05 20.06", element: "Luft", planet: "Merkur", color: "Gelb", stone: "Achat" },
{ name: "Krebs", symbol: "♋", date: "21.06 22.07", element: "Wasser", planet: "Mond", color: "Silber", stone: "Mondstein" },
{ name: "Löwe", symbol: "♌", date: "23.07 22.08", element: "Feuer", planet: "Sonne", color: "Gold", stone: "Rubin" },
{ name: "Jungfrau", symbol: "♍", date: "23.08 22.09", element: "Erde", planet: "Merkur", color: "Braun", stone: "Saphir" },
{ name: "Waage", symbol: "♎", date: "23.09 22.10", element: "Luft", planet: "Venus", color: "Rosa", stone: "Opal" },
{ name: "Skorpion", symbol: "♏", date: "23.10 21.11", element: "Wasser", planet: "Pluto", color: "Dunkelrot", stone: "Topas" },
{ name: "Schütze", symbol: "♐", date: "22.11 21.12", element: "Feuer", planet: "Jupiter", color: "Violett", stone: "Türkis" },
{ name: "Steinbock", symbol: "♑", date: "22.12 19.01", element: "Erde", planet: "Saturn", color: "Schwarz", stone: "Granat" },
{ name: "Wassermann", symbol: "♒", date: "20.01 18.02", element: "Luft", planet: "Uranus", color: "Blau", stone: "Amethyst" },
{ name: "Fische", symbol: "♓", date: "19.02 20.03", element: "Wasser", planet: "Neptun", color: "Meeresblau", stone: "Aquamarin" },
];
const DAILY_HOROSCOPES = [
{
general: "Ein wunderbarer Tag für neue Begegnungen. Die Sterne stehen günstig für spontane Entscheidungen. Sie spüren eine besondere Energie, die Sie antreibt, Neues zu wagen. Nutzen Sie diese Kraft und gehen Sie auf Menschen zu unerwartete Gespräche könnten Ihr Leben bereichern. Ihr natürlicher Optimismus strahlt heute besonders hell und zieht positive Situationen an.",
love: "In der Liebe zeigt sich heute eine besondere Verbindung. Singles könnten jemand Besonderen treffen halten Sie die Augen offen! Paare erleben einen harmonischen Tag voller Zärtlichkeit. Ein romantisches Abendessen oder ein gemeinsamer Spaziergang stärkt Ihre Beziehung.",
career: "Beruflich stehen die Zeichen auf Erfolg. Ein neues Projekt könnte sich anbieten, das Ihre Fähigkeiten perfekt zur Geltung bringt. Zeigen Sie Initiative und Ihr Vorgesetzter wird beeindruckt sein. Finanzielle Entscheidungen sollten heute wohlüberlegt getroffen werden.",
health: "Ihre Vitalität ist heute auf einem Höhepunkt. Nutzen Sie die Energie für sportliche Aktivitäten oder einen langen Spaziergang in der Natur. Achten Sie darauf, ausreichend Wasser zu trinken und gönnen Sie sich am Abend eine entspannende Auszeit.",
tip: "Tragen Sie heute etwas Rotes es verstärkt Ihre natürliche Ausstrahlung und zieht positive Energie an."
},
{
general: "Heute ist Geduld gefragt. Lassen Sie sich Zeit und genießen Sie die kleinen Freuden des Alltags. Nicht alles muss sofort erledigt werden manchmal bringt ein langsameres Tempo bessere Ergebnisse. Die Sterne empfehlen Ihnen, sich auf das Wesentliche zu konzentrieren und unnötigen Stress zu vermeiden. Am Nachmittag lichtet sich der Nebel und Sie sehen klarer.",
love: "Die Liebe braucht heute besondere Aufmerksamkeit. Nehmen Sie sich Zeit für tiefgründige Gespräche mit Ihrem Partner. Singles sollten nicht zu schnell urteilen der erste Eindruck kann täuschen. Ein zweiter Blick lohnt sich, denn wahre Schönheit zeigt sich erst bei näherem Kennenlernen.",
career: "Im Beruf ist Beharrlichkeit der Schlüssel zum Erfolg. Ein schwieriges Projekt erfordert Ihre volle Konzentration. Lassen Sie sich nicht von Rückschlägen entmutigen Ihr Durchhaltevermögen wird sich langfristig auszahlen. Finanziell ist Sparsamkeit angesagt.",
health: "Achten Sie heute besonders auf Ihre Ernährung. Frisches Obst und Gemüse geben Ihrem Körper die nötigen Vitamine. Eine kurze Meditation am Morgen oder Abend hilft Ihnen, innere Ruhe zu finden und den Alltagsstress abzubauen.",
tip: "Kochen Sie heute Ihr Lieblingsgericht es nährt nicht nur den Körper, sondern auch die Seele."
},
{
general: "Kommunikation steht im Vordergrund. Ein gutes Gespräch kann heute Wunder wirken. Ihre Worte haben besondere Kraft und können Brücken bauen. Nutzen Sie diese Gabe, um Missverständnisse zu klären oder neue Kontakte zu knüpfen. Am Abend erwartet Sie eine überraschende Nachricht, die Ihre Stimmung hebt.",
love: "Reden Sie über Ihre Gefühle! Heute ist der perfekte Tag, um Ihrem Partner oder einer besonderen Person mitzuteilen, was Sie empfinden. Offenheit wird belohnt und kann Ihre Beziehung auf ein neues Level heben. Singles sollten gesellige Orte aufsuchen.",
career: "Ein wichtiges Meeting oder Telefonat könnte heute den Durchbruch bringen. Bereiten Sie sich gut vor und präsentieren Sie Ihre Ideen selbstbewusst. Teamarbeit steht unter einem guten Stern gemeinsam erreichen Sie mehr als allein.",
health: "Soziale Kontakte sind heute Ihre beste Medizin. Ein Treffen mit Freunden oder ein anregendes Gespräch mit einem Kollegen hebt Ihre Stimmung und stärkt Ihr Wohlbefinden. Achten Sie auf ausreichend Schlaf Ihr Geist braucht Erholung.",
tip: "Schreiben Sie jemandem, den Sie schon lange nicht mehr kontaktiert haben es wird beiden guttun."
},
{
general: "Vertrauen Sie auf Ihre Intuition. Ihr Bauchgefühl weist Ihnen den richtigen Weg. Heute spüren Sie besonders deutlich, was richtig und was falsch ist. Lassen Sie sich nicht von der Meinung anderer beirren Ihre innere Stimme kennt die Antwort. Am Abend finden Sie Ruhe und Klarheit.",
love: "Emotionale Tiefe prägt heute Ihre Beziehungen. Sie spüren intuitiv, was Ihr Partner braucht, und können liebevoll darauf eingehen. Singles erkennen sofort, ob jemand zu ihnen passt. Vertrauen Sie diesem Gefühl es wird Sie nicht täuschen.",
career: "Kreative Lösungen sind heute gefragt. Verlassen Sie ausgetretene Pfade und denken Sie um die Ecke. Ihre Intuition führt Sie zu innovativen Ansätzen, die andere beeindrucken werden. Finanzielle Entscheidungen sollten aus dem Bauch heraus getroffen werden.",
health: "Hören Sie heute besonders auf Ihren Körper. Wenn er Ruhe fordert, gönnen Sie sie ihm. Ein warmes Bad, beruhigende Musik oder eine Tasse Kräutertee können Wunder wirken. Yoga oder leichte Dehnübungen harmonisieren Körper und Geist.",
tip: "Zünden Sie am Abend eine Kerze an und nehmen Sie sich zehn Minuten nur für sich Meditation oder einfaches Stillsein."
},
{
general: "Kreativität und Mut werden heute belohnt. Zeigen Sie, was in Ihnen steckt! Die kosmische Energie unterstützt alle künstlerischen und kreativen Vorhaben. Ob Musik, Malerei oder ein neues Projekt jetzt ist die Zeit, Ihre Talente zu zeigen. Ihre Begeisterung ist ansteckend und inspiriert auch andere.",
love: "Romantik liegt in der Luft! Überraschen Sie Ihren Partner mit einer liebevollen Geste oder einem spontanen Ausflug. Singles strahlen heute eine besondere Anziehungskraft aus nutzen Sie das! Ein Flirt beim Konzert oder Festival könnte der Beginn von etwas Schönem sein.",
career: "Ihre kreative Seite ist heute Ihr größtes Kapital. Neue Ideen sprudeln nur so aus Ihnen heraus und finden Anerkennung bei Kollegen und Vorgesetzten. Ein Moment im Rampenlicht steht bevor genießen Sie ihn! Finanziell könnten sich neue Möglichkeiten ergeben.",
health: "Bewegung und Aktivität tun Ihnen heute besonders gut. Tanzen Sie zu Ihrer Lieblingsmusik, gehen Sie schwimmen oder machen Sie einen Ausflug in die Berge. Ihre Energie ist grenzenlos nutzen Sie sie für Aktivitäten, die Ihnen Freude bereiten.",
tip: "Hören Sie heute bewusst Volksmusik oder besuchen Sie ein Konzert Musik nährt die Seele."
},
{
general: "Ordnung und Struktur bringen heute den Erfolg. Nutzen Sie die Energie für wichtige Aufgaben. Ein gut organisierter Tag bringt mehr Ergebnisse als hektisches Multitasking. Erstellen Sie eine Prioritätenliste und arbeiten Sie sie Schritt für Schritt ab. Am Ende des Tages werden Sie stolz auf das Erreichte sein.",
love: "Kleine Aufmerksamkeiten machen heute den Unterschied in der Liebe. Ein liebevoll zubereitetes Frühstück, eine handgeschriebene Nachricht oder ein unerwartetes Kompliment es sind die Details, die zählen. Singles sollten ihre Ansprüche nicht zu hoch schrauben.",
career: "Perfektion ist heute Ihr Markenzeichen. Nutzen Sie Ihren Blick fürs Detail, um ein wichtiges Projekt zu vervollständigen. Kollegen schätzen Ihre Zuverlässigkeit und Gründlichkeit. Ein Gespräch mit dem Chef könnte positive Entwicklungen anstoßen.",
health: "Strukturieren Sie Ihre Mahlzeiten und achten Sie auf regelmäßige Pausen. Ein aufgeräumter Arbeitsplatz und ein ordentliches Zuhause tragen zu Ihrem Wohlbefinden bei. Am Abend sorgt ein gutes Buch für die nötige Entspannung.",
tip: "Räumen Sie heute eine Schublade oder einen Schrank auf äußere Ordnung schafft innere Klarheit."
},
{
general: "Harmonie und Ausgeglichenheit bestimmen den Tag. Genießen Sie die Zeit mit Ihren Liebsten. Die Sterne schenken Ihnen heute ein besonderes Gespür für Schönheit und Ästhetik. Umgeben Sie sich mit angenehmen Dingen und Menschen, die Ihnen guttun. Konflikte lassen sich heute leicht lösen.",
love: "Ein Tag wie geschaffen für die Liebe! Paare erleben eine Phase tiefer Verbundenheit und gegenseitigen Verständnisses. Gemeinsame Aktivitäten stärken die Beziehung. Singles sollten sich schick machen und ausgehen Venus begünstigt neue Begegnungen.",
career: "Diplomatie ist heute Ihre Stärke. Vermitteln Sie geschickt zwischen verschiedenen Positionen und finden Sie Kompromisse, mit denen alle zufrieden sind. Ihre soziale Kompetenz wird anerkannt und könnte zu einer Beförderung führen.",
health: "Gönnen Sie sich heute etwas Besonderes einen Wellness-Tag, ein entspannendes Bad oder eine Massage. Ihr Körper und Geist verdienen Verwöhnung. Schöne Musik und gutes Essen tragen zu Ihrem Wohlbefinden bei.",
tip: "Besuchen Sie heute ein Museum, eine Ausstellung oder einen schönen Garten Schönheit nährt die Seele."
},
{
general: "Tiefgründige Erkenntnisse warten auf Sie. Nehmen Sie sich Zeit für Reflexion. Heute können Sie unter die Oberfläche schauen und verborgene Wahrheiten entdecken. Ihre analytische Kraft ist besonders stark nutzen Sie sie, um wichtige Lebensfragen zu beantworten. Transformation und Wandel liegen in der Luft.",
love: "Intensive Emotionen prägen heute Ihre Beziehungen. Tiefe Gespräche über Wünsche und Sehnsüchte bringen Sie und Ihren Partner näher zusammen. Singles könnten eine magnetische Anziehung zu einer bestimmten Person spüren lassen Sie sich darauf ein.",
career: "Forschen Sie heute tiefer ob bei der Arbeit oder in persönlichen Projekten. Ihre Fähigkeit, Zusammenhänge zu erkennen, die anderen verborgen bleiben, macht Sie heute unverzichtbar. Finanzielle Angelegenheiten erfordern gründliche Analyse.",
health: "Emotionale Reinigung steht an. Lassen Sie alte Verletzungen los und vergeben Sie sich selbst und anderen. Ein Tagebucheintrag oder ein Gespräch mit einer Vertrauensperson kann befreiend wirken. Achten Sie auf ausreichend Schlaf.",
tip: "Schreiben Sie heute Ihre Gedanken und Gefühle auf das Aufschreiben wirkt klärend und befreiend."
},
{
general: "Abenteuerlust liegt in der Luft! Planen Sie etwas Besonderes für heute. Die Sterne wecken Ihre Reiselust und den Wunsch nach neuen Erfahrungen. Ob ein Tagesausflug in die Berge, ein neues Restaurant oder ein spannendes Buch erweitern Sie Ihren Horizont! Optimismus und Lebensfreude begleiten Sie durch den Tag.",
love: "Abenteuer zu zweit stärken die Beziehung. Planen Sie etwas Ungewöhnliches mit Ihrem Partner ein spontaner Ausflug oder ein gemeinsames Hobby. Singles finden die Liebe an unerwarteten Orten vielleicht bei einer Wanderung oder auf einem Volksfest.",
career: "Denken Sie heute groß! Neue berufliche Chancen könnten sich am Horizont zeigen. Internationale Kontakte oder Weiterbildungen stehen unter einem guten Stern. Ihre Begeisterungsfähigkeit öffnet Türen, die anderen verschlossen bleiben.",
health: "Bewegung an der frischen Luft ist heute das beste Rezept für Körper und Seele. Eine Wanderung, Radtour oder ein Spaziergang durch die Natur laden Ihre Batterien auf. Probieren Sie ein neues Gericht aus einer anderen Kultur es bereichert Ihren Speiseplan.",
tip: "Machen Sie heute etwas, das Sie noch nie gemacht haben neue Erfahrungen halten jung und vital."
},
{
general: "Disziplin und Ausdauer zahlen sich aus. Bleiben Sie an Ihren Zielen dran. Die kosmische Energie unterstützt heute alle langfristigen Pläne und ambitionierten Vorhaben. Setzen Sie sich realistische Ziele und arbeiten Sie konsequent darauf hin. Geduld ist Ihre Stärke Erfolg kommt Schritt für Schritt.",
love: "Stabilität und Verlässlichkeit sind heute die Pfeiler Ihrer Beziehung. Zeigen Sie Ihrem Partner, dass er sich auf Sie verlassen kann. Gemeinsame Zukunftspläne zu schmieden stärkt Ihre Verbindung. Singles sollten nach jemandem Ausschau halten, der ihre Werte teilt.",
career: "Heute ist der Tag für wichtige berufliche Entscheidungen. Ihre Erfahrung und Kompetenz werden anerkannt. Führungsqualitäten kommen zum Vorschein und ebnen den Weg für einen Aufstieg. Finanzielle Disziplin zahlt sich langfristig aus.",
health: "Regelmäßigkeit ist heute der Schlüssel zu Ihrem Wohlbefinden. Halten Sie sich an Ihre Routinen regelmäßige Mahlzeiten, Bewegung und ausreichend Schlaf. Ihre Knochen und Gelenke freuen sich über sanfte Dehnübungen.",
tip: "Setzen Sie sich heute ein kleines Ziel und erreichen Sie es Erfolgserlebnisse stärken das Selbstvertrauen."
},
{
general: "Originelle Ideen kommen heute von ganz allein. Lassen Sie Ihrer Fantasie freien Lauf. Die Sterne begünstigen unkonventionelles Denken und innovative Lösungen. Sie sehen Dinge aus einer einzigartigen Perspektive, die andere inspiriert. Gemeinschaftliche Aktivitäten und Freundschaften stehen unter einem besonders guten Stern.",
love: "Freiheit und Nähe in Balance zu halten ist heute das Thema in der Liebe. Geben Sie Ihrem Partner Raum und genießen Sie gleichzeitig die gemeinsame Zeit. Singles treffen heute interessante Menschen in Gruppen oder bei Vereinsaktivitäten.",
career: "Innovation ist heute gefragt! Ihre unkonventionellen Ideen fallen auf fruchtbaren Boden. Teamarbeit bringt heute die besten Ergebnisse tauschen Sie sich mit Gleichgesinnten aus. Technologische Neuerungen könnten Ihre Arbeit revolutionieren.",
health: "Gruppenaktivitäten wie Sport im Verein, Wandergruppen oder gemeinsames Kochen tun Ihnen heute besonders gut. Der soziale Aspekt stärkt nicht nur den Körper, sondern auch die Seele. Probieren Sie eine neue Sportart oder Entspannungstechnik aus.",
tip: "Engagieren Sie sich heute für eine gute Sache Altruismus macht glücklich und erfüllt."
},
{
general: "Einfühlungsvermögen und Mitgefühl stärken heute Ihre Beziehungen. Die Sterne schärfen Ihre Sensibilität und Ihr Gespür für die Gefühle anderer. Kreative und spirituelle Aktivitäten stehen unter einem besonders guten Stern. Musik, Kunst und Natur sind heute Ihre Kraftquellen.",
love: "Romantische Träume können heute wahr werden. Ihre einfühlsame Art berührt andere Menschen tief. Paare erleben Momente tiefer emotionaler Verbundenheit. Singles könnten eine fast schicksalhafte Begegnung haben bei einem Konzert, am Wasser oder in einer kreativen Umgebung.",
career: "Kreative Berufe profitieren heute besonders von der kosmischen Energie. Musiker, Künstler und alle, die mit Menschen arbeiten, haben einen glücklichen Tag. Lassen Sie sich von Ihrer Intuition leiten sie führt Sie zu den richtigen Entscheidungen.",
health: "Wasser ist heute Ihr Element ob ein Besuch am See, ein langes Bad oder einfach genug trinken. Meditation und Entspannungsübungen harmonisieren Körper und Geist. Gönnen Sie sich Musik, die Ihre Seele berührt Volksmusik oder klassische Klänge wirken heilsam.",
tip: "Setzen Sie sich heute an einen ruhigen Ort in der Natur und lauschen Sie die Stille hat heilende Kraft."
},
];
function getDayOfYear(): number {
return Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0).getTime()) / 86400000);
}
function getHoroscope(signIndex: number) {
const day = getDayOfYear();
return DAILY_HOROSCOPES[(signIndex + day) % DAILY_HOROSCOPES.length];
}
function getRating(signIndex: number, category: string): number {
const day = getDayOfYear();
const hash = (signIndex * 7 + day * 3 + category.length) % 5;
return Math.max(3, hash + 3);
}
import {
SIGNS,
ELEMENT_COLORS,
getHoroscope,
getRating,
getLuckyNumbers,
getDailyColor,
} from "@/lib/horoscope-data";
function StarRating({ count }: { count: number }) {
return (
@ -134,6 +25,7 @@ function StarRating({ count }: { count: number }) {
export default function HoroscopePage() {
const [selected, setSelected] = useState<number | null>(null);
const [tab, setTab] = useState<"daily" | "weekly" | "monthly">("daily");
return (
<div className="min-h-screen bg-background">
@ -155,132 +47,202 @@ export default function HoroscopePage() {
</p>
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-12 gap-3 mb-10">
{SIGNS.map((sign, i) => (
<button
key={sign.name}
onClick={() => setSelected(i)}
className={`flex flex-col items-center p-3 rounded-xl transition-all duration-200 border ${
selected === i
? "bg-primary/20 border-primary shadow-lg shadow-primary/10 scale-105"
: "bg-card border-card-border hover:border-primary/50 hover:bg-card/80"
}`}
data-testid={`button-sign-select-${sign.name.toLowerCase()}`}
>
<span className="text-3xl mb-1">{sign.symbol}</span>
<span className="text-[10px] font-medium text-foreground">{sign.name}</span>
<span className="text-[8px] text-muted-foreground">{sign.date.split(" ")[0]}</span>
</button>
))}
{SIGNS.map((sign, i) => {
const ec = ELEMENT_COLORS[sign.element];
return (
<button
key={sign.name}
onClick={() => { setSelected(i); setTab("daily"); }}
className={`flex flex-col items-center p-3 rounded-xl transition-all duration-200 border ${
selected === i
? `${ec.bg} ${ec.border} shadow-lg ${ec.glow} scale-105`
: "bg-card border-card-border hover:border-primary/50 hover:bg-card/80"
}`}
data-testid={`button-sign-select-${sign.name.toLowerCase()}`}
>
<span className="text-3xl mb-1">{sign.symbol}</span>
<span className={`text-[10px] font-medium ${selected === i ? ec.text : "text-foreground"}`}>{sign.name}</span>
<span className="text-[8px] text-muted-foreground">{sign.date.split(" ")[0]}</span>
</button>
);
})}
</div>
{selected === null ? (
<div className="text-center py-16" data-testid="text-horoscope-prompt">
<span className="text-6xl block mb-4"></span>
<Sparkles className="w-16 h-16 text-primary mx-auto mb-4" />
<p className="text-muted-foreground text-lg">Wählen Sie Ihr Sternzeichen oben aus</p>
</div>
) : (
<div className="space-y-0">
<div className="bg-card rounded-xl border border-card-border p-6 md:p-8" data-testid={`card-horoscope-${SIGNS[selected].name.toLowerCase()}`}>
<div className="flex items-center gap-4 mb-6">
<span className="text-6xl">{SIGNS[selected].symbol}</span>
<div>
<h2 className="text-2xl font-bold text-foreground">{SIGNS[selected].name}</h2>
<p className="text-sm text-muted-foreground">{SIGNS[selected].date}</p>
<div className="flex flex-wrap gap-3 mt-2">
<span className="text-xs bg-muted px-2 py-0.5 rounded text-muted-foreground">Element: {SIGNS[selected].element}</span>
<span className="text-xs bg-muted px-2 py-0.5 rounded text-muted-foreground">Planet: {SIGNS[selected].planet}</span>
<span className="text-xs bg-muted px-2 py-0.5 rounded text-muted-foreground">Farbe: {SIGNS[selected].color}</span>
<span className="text-xs bg-muted px-2 py-0.5 rounded text-muted-foreground">Stein: {SIGNS[selected].stone}</span>
</div>
</div>
</div>
{(() => {
const sign = SIGNS[selected];
const ec = ELEMENT_COLORS[sign.element];
const horoscope = getHoroscope(selected);
const luckyNums = getLuckyNumbers(selected);
const dailyColor = getDailyColor(selected);
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Heart className="w-4 h-4 text-primary mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Liebe</p>
<StarRating count={getRating(selected, "love")} />
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Briefcase className="w-4 h-4 text-primary mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Beruf</p>
<StarRating count={getRating(selected, "career")} />
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<TrendingUp className="w-4 h-4 text-primary mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Gesundheit</p>
<StarRating count={getRating(selected, "health")} />
</div>
</div>
<div className="space-y-5">
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Star className="w-4 h-4 text-primary" /> Allgemein
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{getHoroscope(selected).general}</p>
</div>
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Heart className="w-4 h-4 text-primary" /> Liebe & Partnerschaft
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{getHoroscope(selected).love}</p>
</div>
</div>
</div>
<InArticleAd />
<div className="bg-card rounded-xl border border-card-border p-6 md:p-8" data-testid="card-horoscope-detail-2">
<div className="space-y-5">
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Briefcase className="w-4 h-4 text-primary" /> Beruf & Finanzen
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{getHoroscope(selected).career}</p>
</div>
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<TrendingUp className="w-4 h-4 text-primary" /> Gesundheit & Wohlbefinden
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{getHoroscope(selected).health}</p>
</div>
<div className="bg-primary/10 border border-primary/20 rounded-lg p-4">
<p className="text-sm text-foreground/90 font-medium flex items-start gap-2">
<span className="text-primary text-lg leading-none">💡</span>
<span><strong>Tipp des Tages:</strong> {getHoroscope(selected).tip}</span>
</p>
</div>
</div>
</div>
<InArticleAd />
<div className="bg-card rounded-xl border border-card-border p-6" data-testid="card-horoscope-others">
<h3 className="font-semibold text-foreground mb-4">Weitere Sternzeichen entdecken</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{SIGNS.filter((_, i) => i !== selected).map((sign, i) => {
const origIdx = SIGNS.findIndex(s => s.name === sign.name);
return (
<button
key={sign.name}
onClick={() => { setSelected(origIdx); window.scrollTo({ top: 0, behavior: "smooth" }); }}
className="bg-muted/30 hover:bg-muted/50 border border-card-border hover:border-primary/50 rounded-lg p-3 transition-all text-left"
data-testid={`button-sign-other-${sign.name.toLowerCase()}`}
>
<div className="flex items-center gap-2 mb-1">
<span className="text-xl">{sign.symbol}</span>
<span className="font-medium text-sm text-foreground">{sign.name}</span>
return (
<>
<div className="bg-card rounded-xl border border-card-border p-6 md:p-8" data-testid={`card-horoscope-${sign.name.toLowerCase()}`}>
<div className="flex items-start gap-4 mb-6">
<div className={`w-20 h-20 rounded-2xl ${ec.bg} border ${ec.border} flex items-center justify-center flex-shrink-0`}>
<span className="text-5xl">{sign.symbol}</span>
</div>
<p className="text-[10px] text-muted-foreground line-clamp-2">{getHoroscope(origIdx).general.slice(0, 80)}...</p>
</button>
);
})}
</div>
</div>
<div className="flex-1">
<h2 className={`text-2xl font-bold ${ec.text}`}>{sign.name}</h2>
<p className="text-sm text-muted-foreground">{sign.date}</p>
<div className="flex flex-wrap gap-2 mt-2">
<span className={`text-[10px] font-medium px-2 py-0.5 rounded ${ec.bg} ${ec.text} border ${ec.border}`}>{sign.element}</span>
<span className="text-[10px] bg-muted px-2 py-0.5 rounded text-muted-foreground">Planet: {sign.planet}</span>
<span className="text-[10px] bg-muted px-2 py-0.5 rounded text-muted-foreground">Farbe: {sign.color}</span>
<span className="text-[10px] bg-muted px-2 py-0.5 rounded text-muted-foreground">Stein: {sign.stone}</span>
</div>
</div>
</div>
<div className="grid grid-cols-3 sm:grid-cols-6 gap-3 mb-6">
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Heart className="w-4 h-4 text-red-400 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Liebe</p>
<StarRating count={getRating(selected, "love")} />
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Briefcase className="w-4 h-4 text-amber-400 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Beruf</p>
<StarRating count={getRating(selected, "career")} />
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<TrendingUp className="w-4 h-4 text-emerald-400 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Gesundheit</p>
<StarRating count={getRating(selected, "health")} />
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Sparkles className="w-4 h-4 text-violet-400 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Glückszahlen</p>
<p className="text-xs font-bold text-foreground" data-testid="text-lucky-numbers">{luckyNums.join(", ")}</p>
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<div className="w-4 h-4 rounded-full bg-primary/60 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Tagesfarbe</p>
<p className="text-xs font-bold text-foreground" data-testid="text-daily-color">{dailyColor}</p>
</div>
<div className="bg-muted/30 rounded-lg p-3 text-center">
<Heart className="w-4 h-4 text-pink-400 mx-auto mb-1" />
<p className="text-[10px] text-muted-foreground mb-1">Kompatibel</p>
<p className="text-[10px] font-medium text-foreground leading-tight" data-testid="text-compatible-signs">{sign.compatible.join(", ")}</p>
</div>
</div>
<div className="flex gap-1 mb-6 bg-muted/30 rounded-lg p-1">
{(["daily", "weekly", "monthly"] as const).map((t) => (
<button
key={t}
onClick={() => setTab(t)}
className={`flex-1 text-xs font-medium py-2 px-3 rounded-md transition-all flex items-center justify-center gap-1.5 ${
tab === t ? "bg-primary text-white shadow" : "text-muted-foreground hover:text-foreground"
}`}
data-testid={`button-tab-${t}`}
>
{t === "daily" && <Star className="w-3 h-3" />}
{t === "weekly" && <Calendar className="w-3 h-3" />}
{t === "monthly" && <CalendarDays className="w-3 h-3" />}
{t === "daily" ? "Heute" : t === "weekly" ? "Woche" : "Monat"}
</button>
))}
</div>
{tab === "daily" && (
<div className="space-y-5" data-testid="section-horoscope-daily">
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Star className="w-4 h-4 text-primary" /> Allgemein
</h3>
<p className="text-sm text-foreground/80 leading-relaxed" data-testid="text-horoscope-general">{horoscope.general}</p>
</div>
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Heart className="w-4 h-4 text-red-400" /> Liebe & Partnerschaft
</h3>
<p className="text-sm text-foreground/80 leading-relaxed" data-testid="text-horoscope-love">{horoscope.love}</p>
</div>
</div>
)}
{tab === "weekly" && (
<div data-testid="section-horoscope-weekly">
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Calendar className="w-4 h-4 text-primary" /> Wochenhoroskop
</h3>
<p className="text-sm text-foreground/80 leading-relaxed" data-testid="text-horoscope-weekly">{horoscope.weekly}</p>
</div>
)}
{tab === "monthly" && (
<div data-testid="section-horoscope-monthly">
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<CalendarDays className="w-4 h-4 text-primary" /> Monatshoroskop
</h3>
<p className="text-sm text-foreground/80 leading-relaxed" data-testid="text-horoscope-monthly">{horoscope.monthly}</p>
</div>
)}
</div>
<InArticleAd />
{tab === "daily" && (
<div className="bg-card rounded-xl border border-card-border p-6 md:p-8" data-testid="card-horoscope-detail-2">
<div className="space-y-5">
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<Briefcase className="w-4 h-4 text-amber-400" /> Beruf & Finanzen
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{horoscope.career}</p>
</div>
<div>
<h3 className="font-semibold text-foreground flex items-center gap-2 mb-2">
<TrendingUp className="w-4 h-4 text-emerald-400" /> Gesundheit & Wohlbefinden
</h3>
<p className="text-sm text-foreground/80 leading-relaxed">{horoscope.health}</p>
</div>
<div className="bg-primary/10 border border-primary/20 rounded-lg p-4" data-testid="card-horoscope-tip">
<p className="text-sm text-foreground/90 font-medium flex items-start gap-2">
<Lightbulb className="w-5 h-5 text-primary flex-shrink-0 mt-0.5" />
<span><strong>Tipp des Tages:</strong> {horoscope.tip}</span>
</p>
</div>
</div>
</div>
)}
<InArticleAd />
<div className="bg-card rounded-xl border border-card-border p-6" data-testid="card-horoscope-others">
<h3 className="font-semibold text-foreground mb-4">Weitere Sternzeichen entdecken</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{SIGNS.filter((_, i) => i !== selected).map((s) => {
const origIdx = SIGNS.findIndex((x) => x.name === s.name);
const sEc = ELEMENT_COLORS[s.element];
return (
<button
key={s.name}
onClick={() => { setSelected(origIdx); setTab("daily"); window.scrollTo({ top: 0, behavior: "smooth" }); }}
className={`${sEc.bg} hover:opacity-80 border ${sEc.border} rounded-lg p-3 transition-all text-left`}
data-testid={`button-sign-other-${s.name.toLowerCase()}`}
>
<div className="flex items-center gap-2 mb-1">
<span className="text-xl">{s.symbol}</span>
<span className={`font-medium text-sm ${sEc.text}`}>{s.name}</span>
</div>
<p className="text-[10px] text-muted-foreground">{s.date}</p>
</button>
);
})}
</div>
</div>
</>
);
})()}
</div>
)}
</main>

View File

@ -0,0 +1,365 @@
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 className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4">
<span className="text-[10px] font-medium text-primary bg-primary/20 px-2 py-0.5 rounded">{recipe.category}</span>
</div>
</div>
<div className="p-5">
<h2 className="text-xl font-bold text-foreground mb-1">{recipe.title}</h2>
<p className="text-sm text-muted-foreground mb-3">{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 className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent" />
<div className="absolute bottom-2 left-2">
<span className="text-[10px] font-medium text-primary bg-primary/20 px-2 py-0.5 rounded">{recipe.category}</span>
</div>
</div>
<div className="p-4">
<h3 className="font-bold text-card-foreground text-base group-hover:text-primary transition-colors">{recipe.title}</h3>
<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>
);
}

View File

@ -1,7 +1,7 @@
# news.folx.tv - MSN-Style News Portal
## Overview
A professional MSN-style news portal for Folx Music Television (news.folx.tv). Dark-themed bento grid layout with content for folk music (Volksmusik/Schlager) fans. Features articles, videos, photo gallery, horoscope widget, recipe widget, Google News feed, and integrated AdSense ads. All content is hardcoded in seed for production deployments.
A professional MSN-style news portal for Folx Music Television (news.folx.tv). Dark-themed bento grid layout with content for folk music (Volksmusik/Schlager) fans. Features articles, videos, photo gallery, horoscope widget + subpage, recipe widget + subpage, Google News feed, and integrated AdSense ads. All content is hardcoded in seed for production deployments.
## Architecture
- **Frontend**: React + Vite + TailwindCSS + shadcn/ui (dark mode)
@ -10,11 +10,12 @@ A professional MSN-style news portal for Folx Music Television (news.folx.tv). D
- **Routing**: wouter (frontend), Express (backend API)
## Key Features
- MSN-style bento grid homepage with FeaturedCarousel, HeroCard, MediumCard, TopStoriesList
- Photo gallery widget (156 Dropbox images) with fullscreen lightbox carousel
- Horoscope widget (12 zodiac signs, daily rotating texts)
- Recipe widget (6 Austrian/Slovenian recipes with modal)
- Google News RSS widget (Volksmusik/Schlager news)
- MSN-style bento grid homepage with mixed article/widget layout
- FeaturedCarousel with 5 article pages (page 2 = wide layout) + gallery page
- Photo gallery widget (547 Dropbox images) with fullscreen lightbox carousel
- Horoscope widget with element colors, star ratings, full /horoskop subpage
- Recipe widget + full /rezepte subpage (21 recipes across 5 regions: Österreich, Bayern, Schwaben/Baden, Südtirol/Alpen, Norddeutschland) with AI-generated images
- Google News RSS widget (Volksmusik/Schlager news, 5 items, auto-rotate)
- Google AdSense integration (ca-pub-4465464714854276)
- Article listing with featured carousel and category filtering
- HTML content supports embedded iframes (bunny.net, YouTube, Facebook, Instagram, TikTok)
@ -36,27 +37,39 @@ A professional MSN-style news portal for Folx Music Television (news.folx.tv). D
- `POST /api/upload` - Upload image file
- `GET /api/gallery` - Shuffled Dropbox gallery images
- `GET /api/news-feed` - Google News RSS feed for Volksmusik/Schlager
- `GET /api/videos` - BunnyCDN video list
- `GET /api/videos/:guid` - BunnyCDN video details
## File Structure
- `shared/schema.ts` - Drizzle schema + Zod validation
- `server/db.ts` - Database connection
- `server/storage.ts` - Storage interface + DatabaseStorage
- `server/routes.ts` - API routes + gallery + news feed
- `server/seed.ts` - Hardcoded seed data (7 articles)
- `server/gallery-data.json` - 156 Dropbox gallery images
- `server/seed.ts` - Hardcoded seed data (articles)
- `server/gallery-data.json` - 547 Dropbox gallery images
- `client/src/pages/home.tsx` - MSN-style bento grid homepage
- `client/src/pages/article.tsx` - Article detail page
- `client/src/pages/category.tsx` - Category listing page
- `client/src/pages/videos.tsx` - Videos page
- `client/src/pages/gallery.tsx` - Full gallery page
- `client/src/components/header.tsx` - Header with nav (Start, News, Video, Galerie)
- `client/src/pages/horoscope.tsx` - Full horoscope page (12 signs, love/career/health, weekly/monthly)
- `client/src/pages/recipes.tsx` - Full recipes page (21 recipes, 5 regions, AI-generated images)
- `client/src/lib/horoscope-data.ts` - Shared horoscope data (signs, texts, helpers)
- `client/src/components/header.tsx` - Header with nav (Start, News, Video, Galerie, Horoskop, Rezepte)
- `client/src/components/footer.tsx` - Footer with links
- `client/src/components/photo-gallery.tsx` - Gallery widget + lightbox carousel
- `client/src/components/horoscope-widget.tsx` - Horoscope widget
- `client/src/components/recipe-widget.tsx` - Recipe widget
- `client/src/components/horoscope-widget.tsx` - Horoscope widget with element colors
- `client/src/components/recipe-widget.tsx` - Recipe widget with modal
- `client/src/components/news-widget.tsx` - Google News RSS widget
- `client/src/components/adsense.tsx` - AdSense ad components
## Homepage Layout (MSN Bento Grid)
- Row 1: FeaturedCarousel (hero + side articles + TopStorys, page 2 = wide hero)
- Row 2: 2 articles + PhotoGalleryWidget + RecipeWidget (mixed)
- Row 3: HoroscopeWidget + 2 articles + NewsWidget (mixed)
- Row 4: 3 articles + NativeAdCard
- Row 5: 3 articles + NativeAdCard
## Branding
- Dark theme (class="dark" on html)
- Primary/brand color: crimson/red (RGB 218,35,77)
@ -67,5 +80,12 @@ A professional MSN-style news portal for Folx Music Television (news.folx.tv). D
## External Services
- Bunny.net: Library 476412, CDN vz-7982dfc4-cc8.b-cdn.net (NO autoplay)
- Google AdSense: ca-pub-4465464714854276
- Dropbox: Gallery image thumbnails
- Dropbox: Gallery image thumbnails (547 images from 16 folders)
- Google News RSS: Volksmusik/Schlager news feed
## Important Notes
- Tailwind `object-[center_25%]` does NOT work — must use inline `style={{ objectPosition: "center 25%" }}`
- Horoscope widget navigates to /horoskop on click (no modal)
- News widget external links open in new tab (target="_blank")
- FeaturedCarousel: page 1 = wide (5 cols, no side cards), last page = gallery
- All images use `objectPosition: "center 25%"` for better face cropping

View File

@ -79,6 +79,17 @@ const seedArticles = [
"featured": false,
"publishedAt": "2025-08-31T14:29:00.000Z",
"content": "<p>Eine faszinierende Dokumentation über die <strong>Oberkrainer aus Begunje</strong> und die Geschichte ihres legendären Liedes. Tauchen Sie ein in die Welt der slowenischen Volksmusik und erfahren Sie, wie diese einzigartige Musiktradition entstanden ist.</p>\n<div style=\"display:flex;justify-content:center;margin:2rem 0;\"><iframe src=\"https://player.mediadelivery.net/embed/476412/e87a6341-df47-4fa9-bd2e-b2f99be111dc\" loading=\"lazy\" style=\"border:none;width:100%;aspect-ratio:16/9;\" allow=\"accelerometer;gyroscope;encrypted-media;picture-in-picture;\" allowfullscreen=\"true\"></iframe></div>\n<p>Die Oberkrainer Musik, begründet von <strong>Slavko Avsenik</strong> in den 1950er Jahren, hat sich zu einem Weltphänomen entwickelt. Diese Dokumentation erzählt die Geschichte hinter den Melodien, die Millionen von Menschen auf der ganzen Welt berührt haben.</p>"
},
{
"title": "Melanie Payer präsentiert den neuen Song &bdquo;Endlich wieder Gipfelstammtisch&ldquo;",
"slug": "melanie-payer-endlich-wieder-gipfelstammtisch",
"excerpt": "Die talentierte Sängerin Melanie Payer bringt mit ihrem neuen Titel &bdquo;Endlich wieder Gipfelstammtisch&ldquo; frischen Wind in die Musikwelt. Der Song markiert die erste Veröffentlichung des Labels mymusic.media und ist das Herzstück der neuen Staffel der beliebten Sendung auf Folx TV.",
"category": "News",
"author": "Folx Music Television",
"coverImage": "/uploads/melanie-payer-gipfelstammtisch.jpg",
"featured": true,
"publishedAt": "2025-09-05T10:00:00.000Z",
"content": "<p>Die talentierte Sängerin <strong>Melanie Payer</strong> bringt mit ihrem neuen Titel &bdquo;Endlich wieder Gipfelstammtisch&ldquo; frischen Wind in die Musikwelt. Der Song wird ab dem 27. September 2024 zum Streaming und Download verfügbar sein und markiert die erste Veröffentlichung des Labels mymusic.media.</p>\n<div style=\"display:flex;justify-content:center;margin:2rem 0;\"><iframe src=\"https://www.facebook.com/plugins/video.php?height=476&href=https%3A%2F%2Fwww.facebook.com%2Freel%2F1201643474458180%2F&show_text=true&width=380&t=0\" width=\"380\" height=\"591\" style=\"border:none;overflow:hidden\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"true\" allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\"></iframe></div>\n<p>Die Schaffung dieser musikalischen Perle fand im renommierten Tonstudio FD-Musics in Gmunden statt. Der Song wurde von <strong>Flo Daxner</strong> und <strong>Hanneliese Kreißl Wurth</strong> komponiert, die auch die Texte verfasste. Flo Daxner übernahm zudem die Produktion und das Arrangement, was dem Lied seine einzigartige Klangtiefe verleiht.</p>\n<div style=\"display:flex;justify-content:center;margin:2rem 0;\"><blockquote class=\"instagram-media\" data-instgrm-permalink=\"https://www.instagram.com/reel/C9UphycIry4/\" data-instgrm-version=\"14\" style=\"background:#000;border:0;border-radius:3px;max-width:540px;min-width:326px;padding:0;width:calc(100% - 2px);\"><a href=\"https://www.instagram.com/reel/C9UphycIry4/\">View on Instagram</a></blockquote></div>\n<p>&bdquo;Endlich wieder Gipfelstammtisch&ldquo; ist das Herzstück der neuen Staffel der beliebten Sendung <strong>&bdquo;Gipfelstammtisch&ldquo;</strong> auf Folx TV. Moderiert von dem charismatischen <strong>Wijbrand van der Sande</strong>, verspricht die Show, Zuschauer mit einzigartigen Einblicken und der bezaubernden Volksmusik der Wilder Kaiser Region zu fesseln. Der Song nimmt Zuhörer auf eine musikalische Reise mit, die die Magie der Berge und der Volksmusik in jedem Ton spürbar macht.</p>\n<div style=\"display:flex;justify-content:center;margin:2rem 0;\"><blockquote class=\"instagram-media\" data-instgrm-permalink=\"https://www.instagram.com/reel/C__LXF_x-a5/\" data-instgrm-version=\"14\" style=\"background:#000;border:0;border-radius:3px;max-width:540px;min-width:326px;padding:0;width:calc(100% - 2px);\"><a href=\"https://www.instagram.com/reel/C__LXF_x-a5/\">View on Instagram</a></blockquote></div>\n<p>Folx TV setzt sich für innovative Unterhaltung und Musik ein. Die neue Staffel des Gipfelstammtischs und der Song von Melanie Payer sind mit Spannung erwartet. Verpassen Sie nicht die neue Staffel und erleben Sie den Song und den Gipfelstammtisch hautnah!</p>"
}
];