folx-tv/client/src/components/horoscope-widget.tsx
sebastjanartic 0918ffd291 Adjust image cropping to better display faces in photos
Apply `objectPosition: "center 25%"` to all relevant image elements across the client application to ensure faces are consistently visible and not cropped out by the `object-cover` CSS property. This change impacts components in `photo-gallery`, `article`, `category`, and `home` pages.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 413891e8-d784-4bea-b9f5-91a5a68316b4
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 6fbb209e-0312-4027-963a-b6aa098cc025
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/413891e8-d784-4bea-b9f5-91a5a68316b4/RVXhOPb
Replit-Helium-Checkpoint-Created: true
2026-02-28 19:22:57 +00:00

142 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect, useCallback } from "react";
import { useLocation } from "wouter";
import { Star, ChevronLeft, ChevronRight, X } 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);
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>
);
}
export function HoroscopeWidget() {
const [showModal, setShowModal] = useState(false);
const [index, setIndex] = useState(0);
const [paused, setPaused] = useState(false);
const next = useCallback(() => setIndex((i) => (i + 1) % SIGNS.length), []);
useEffect(() => {
if (paused) return;
const timer = setInterval(next, 6000);
return () => clearInterval(timer);
}, [paused, next]);
const sign = SIGNS[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"
onMouseEnter={() => setPaused(true)}
onMouseLeave={() => setPaused(false)}
onClick={() => setShowModal(true)}
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>
<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">
{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"}`}
data-testid={`button-horoscope-dot-${i}`}
/>
))}
</div>
</div>
</div>
{showModal && <HoroscopeModal initialSign={index} onClose={() => setShowModal(false)} />}
</>
);
}