scolling
This commit is contained in:
@@ -84,20 +84,38 @@ export default function KoFixtures({ teams, matches }: { teams: Team[]; matches:
|
|||||||
}, [koMatches]);
|
}, [koMatches]);
|
||||||
|
|
||||||
const targetRef = useRef<HTMLDivElement>(null);
|
const targetRef = useRef<HTMLDivElement>(null);
|
||||||
|
const hasScrolledRef = useRef<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mounted && targetRef.current) {
|
if (!mounted || !targetRef.current) return;
|
||||||
targetRef.current.scrollIntoView({ behavior: "smooth", block: "center" });
|
if (targetMatchId === hasScrolledRef.current) return;
|
||||||
}
|
const el = targetRef.current;
|
||||||
}, [mounted]);
|
const raf = requestAnimationFrame(() => {
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const absoluteTop = rect.top + window.scrollY;
|
||||||
|
const offset = 180;
|
||||||
|
window.scrollTo({ top: Math.max(0, absoluteTop - offset), behavior: "smooth" });
|
||||||
|
});
|
||||||
|
hasScrolledRef.current = targetMatchId;
|
||||||
|
return () => cancelAnimationFrame(raf);
|
||||||
|
}, [mounted, targetMatchId, koMatches.length]);
|
||||||
|
|
||||||
|
const [showScrollTop, setShowScrollTop] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
const onScroll = () => setShowScrollTop(window.scrollY > 100);
|
||||||
|
window.addEventListener("scroll", onScroll, { passive: true });
|
||||||
|
onScroll();
|
||||||
|
return () => window.removeEventListener("scroll", onScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (koMatches.length === 0) {
|
if (koMatches.length === 0) {
|
||||||
return <div className="notice">Keine K.o.-Spiele mit bekannten Teams verfügbar.</div>;
|
return <div className="notice">Keine K.o.-Spiele mit bekannten Teams verfügbar.</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{groups.map(([date, groupMatches]) => (
|
<div>
|
||||||
|
{groups.map(([date, groupMatches]) => (
|
||||||
<div key={date} style={{ marginBottom: 24 }}>
|
<div key={date} style={{ marginBottom: 24 }}>
|
||||||
<h3 style={{
|
<h3 style={{
|
||||||
fontFamily: "var(--font-display)", fontSize: 13,
|
fontFamily: "var(--font-display)", fontSize: 13,
|
||||||
@@ -117,14 +135,19 @@ export default function KoFixtures({ teams, matches }: { teams: Team[]; matches:
|
|||||||
};
|
};
|
||||||
|
|
||||||
const city = STADIUMS[MATCH_STADIUMS[m.matchNumber]]?.city;
|
const city = STADIUMS[MATCH_STADIUMS[m.matchNumber]]?.city;
|
||||||
|
const isTarget = String(m.id) === String(targetMatchId);
|
||||||
|
const finished = m.status === "FINISHED";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={m.id}
|
key={m.id}
|
||||||
ref={m.id === targetMatchId ? targetRef : undefined}
|
ref={isTarget ? targetRef : undefined}
|
||||||
style={{
|
style={{
|
||||||
background: "var(--bg-card)", border: `1px solid ${live ? "var(--turf)" : "var(--line-soft)"}`,
|
background: "var(--bg-card)",
|
||||||
|
border: `${isTarget ? 2 : 1}px solid ${live ? "var(--turf)" : isTarget ? "var(--turf)" : "var(--line-soft)"}`,
|
||||||
borderRadius: "var(--radius-sm)", padding: "12px 14px",
|
borderRadius: "var(--radius-sm)", padding: "12px 14px",
|
||||||
|
opacity: finished && !isTarget ? 0.65 : 1,
|
||||||
|
boxShadow: isTarget ? "0 0 0 1px var(--turf)" : undefined,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Kopfzeile */}
|
{/* Kopfzeile */}
|
||||||
@@ -133,7 +156,17 @@ export default function KoFixtures({ teams, matches }: { teams: Team[]; matches:
|
|||||||
marginBottom: 8, fontSize: 11,
|
marginBottom: 8, fontSize: 11,
|
||||||
fontFamily: "var(--font-mono)", color: "var(--ink-faint)",
|
fontFamily: "var(--font-mono)", color: "var(--ink-faint)",
|
||||||
}}>
|
}}>
|
||||||
<span>
|
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||||
|
{isTarget && (
|
||||||
|
<span style={{
|
||||||
|
background: live ? "var(--turf)" : "var(--turf-deep)",
|
||||||
|
color: "#fff", fontSize: 9, fontWeight: 700,
|
||||||
|
padding: "1px 6px", borderRadius: 999,
|
||||||
|
letterSpacing: "0.04em",
|
||||||
|
}}>
|
||||||
|
{live ? "LIVE" : "NÄCHSTES SPIEL"}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{stageMap[m.stage] ?? m.stage} · Spiel {m.matchNumber || "—"}
|
{stageMap[m.stage] ?? m.stage} · Spiel {m.matchNumber || "—"}
|
||||||
{city ? ` · ${city}` : ""}
|
{city ? ` · ${city}` : ""}
|
||||||
</span>
|
</span>
|
||||||
@@ -200,6 +233,23 @@ export default function KoFixtures({ teams, matches }: { teams: Team[]; matches:
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
{showScrollTop && (
|
||||||
|
<button
|
||||||
|
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
|
||||||
|
style={{
|
||||||
|
position: "fixed", right: 24, bottom: 24, zIndex: 50,
|
||||||
|
width: 48, height: 48, borderRadius: "50%",
|
||||||
|
background: "var(--bg-card)", color: "var(--ink-dim)",
|
||||||
|
border: "1px solid var(--line)", boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
|
||||||
|
cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
|
fontSize: 22, lineHeight: 1,
|
||||||
|
}}
|
||||||
|
title="Nach oben scrollen"
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user