Horoskop widget na naslovnici: slikce znamenj + povezava na znamenje
This commit is contained in:
parent
68fe291b55
commit
3c6079d720
@ -8,6 +8,7 @@ interface AIHoroscope {
|
|||||||
signIndex: number;
|
signIndex: number;
|
||||||
signName: string;
|
signName: string;
|
||||||
general: string;
|
general: string;
|
||||||
|
imageUrl?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MiniStars({ count, max = 5 }: { count: number; max?: number }) {
|
function MiniStars({ count, max = 5 }: { count: number; max?: number }) {
|
||||||
@ -44,6 +45,9 @@ export function HoroscopeWidget() {
|
|||||||
// Prefer the real AI-generated horoscope for today; fall back to static text until loaded.
|
// Prefer the real AI-generated horoscope for today; fall back to static text until loaded.
|
||||||
const aiForSign = aiHoroscopes.find((h) => h.signIndex === index);
|
const aiForSign = aiHoroscopes.find((h) => h.signIndex === index);
|
||||||
const generalText = aiForSign?.general || getHoroscope(index).general;
|
const generalText = aiForSign?.general || getHoroscope(index).general;
|
||||||
|
const imageFor = (i: number) => aiHoroscopes.find((h) => h.signIndex === i)?.imageUrl || null;
|
||||||
|
const currentImage = imageFor(index);
|
||||||
|
const signPath = (i: number) => `/horoskop/${encodeURIComponent(SIGNS[i].name.toLowerCase())}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -51,7 +55,7 @@ export function HoroscopeWidget() {
|
|||||||
style={{ background: "linear-gradient(135deg, hsl(250 30% 14%), hsl(270 25% 10%))" }}
|
style={{ background: "linear-gradient(135deg, hsl(250 30% 14%), hsl(270 25% 10%))" }}
|
||||||
onMouseEnter={() => setPaused(true)}
|
onMouseEnter={() => setPaused(true)}
|
||||||
onMouseLeave={() => setPaused(false)}
|
onMouseLeave={() => setPaused(false)}
|
||||||
onClick={() => navigate("/horoskop")}
|
onClick={() => navigate(signPath(index))}
|
||||||
data-testid="widget-horoscope"
|
data-testid="widget-horoscope"
|
||||||
>
|
>
|
||||||
<div className="p-3 flex items-center justify-between border-b border-white/10 flex-shrink-0">
|
<div className="p-3 flex items-center justify-between border-b border-white/10 flex-shrink-0">
|
||||||
@ -78,8 +82,18 @@ export function HoroscopeWidget() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 flex flex-col">
|
<div className="flex-1 flex flex-col">
|
||||||
<div className="p-4 flex items-center gap-3">
|
<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">
|
<div className="w-14 h-14 rounded-xl bg-white/5 border border-white/10 overflow-hidden flex items-center justify-center flex-shrink-0">
|
||||||
|
{currentImage ? (
|
||||||
|
<img
|
||||||
|
src={currentImage}
|
||||||
|
alt={`Tageshoroskop ${sign.name}`}
|
||||||
|
loading="lazy"
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
data-testid="img-widget-horoscope-sign"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<span className="text-3xl">{sign.symbol}</span>
|
<span className="text-3xl">{sign.symbol}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<p className="font-bold text-lg text-white">{sign.name}</p>
|
<p className="font-bold text-lg text-white">{sign.name}</p>
|
||||||
@ -107,15 +121,30 @@ export function HoroscopeWidget() {
|
|||||||
<p className="text-[10px] text-amber-400 mt-2 group-hover:underline">Mehr lesen</p>
|
<p className="text-[10px] text-amber-400 mt-2 group-hover:underline">Mehr lesen</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-center gap-1 pb-3">
|
<div className="grid grid-cols-6 gap-1 px-2 pb-3">
|
||||||
{SIGNS.map((_, i) => (
|
{SIGNS.map((s, i) => {
|
||||||
|
const img = imageFor(i);
|
||||||
|
return (
|
||||||
<button
|
<button
|
||||||
key={i}
|
key={s.name}
|
||||||
onClick={(e) => { e.stopPropagation(); setIndex(i); }}
|
title={s.name}
|
||||||
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"}`}
|
onClick={(e) => { e.stopPropagation(); navigate(signPath(i)); }}
|
||||||
data-testid={`button-horoscope-dot-${i}`}
|
onMouseEnter={() => setIndex(i)}
|
||||||
/>
|
className={`aspect-square rounded-md overflow-hidden border transition-all flex items-center justify-center ${
|
||||||
))}
|
i === index
|
||||||
|
? "border-amber-400 ring-1 ring-amber-400/40"
|
||||||
|
: "border-white/10 hover:border-white/40 opacity-70 hover:opacity-100"
|
||||||
|
}`}
|
||||||
|
data-testid={`button-horoscope-thumb-${s.name.toLowerCase()}`}
|
||||||
|
>
|
||||||
|
{img ? (
|
||||||
|
<img src={img} alt={s.name} loading="lazy" className="w-full h-full object-cover" />
|
||||||
|
) : (
|
||||||
|
<span className="text-sm">{s.symbol}</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -337,7 +337,10 @@ export default function HoroscopePage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (params.sign) {
|
if (params.sign) {
|
||||||
const idx = SIGNS.findIndex((s) => s.name.toLowerCase() === params.sign?.toLowerCase());
|
let raw = params.sign;
|
||||||
|
try { raw = decodeURIComponent(params.sign); } catch { /* ostane surov */ }
|
||||||
|
const wanted = raw.toLowerCase();
|
||||||
|
const idx = SIGNS.findIndex((s) => s.name.toLowerCase() === wanted);
|
||||||
if (idx >= 0) setSelected(idx);
|
if (idx >= 0) setSelected(idx);
|
||||||
}
|
}
|
||||||
}, [params.sign]);
|
}, [params.sign]);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user