Compare commits

..

2 Commits

Author SHA1 Message Date
b3eb21e59b scolling 2026-06-28 18:16:42 -05:00
87624ae484 scrolling 2026-06-28 17:03:21 -05:00

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useMemo, useState, useEffect } from "react"; import { useMemo, useState, useEffect, useRef } from "react";
import { Match, Team } from "@/lib/types"; import { Match, Team } from "@/lib/types";
import { STADIUMS, MATCH_STADIUMS } from "@/lib/stadiums"; import { STADIUMS, MATCH_STADIUMS } from "@/lib/stadiums";
import Flag from "./Flag"; import Flag from "./Flag";
@@ -76,11 +76,44 @@ export default function KoFixtures({ teams, matches }: { teams: Team[]; matches:
return [...map.entries()]; return [...map.entries()];
}, [koMatches, mounted]); }, [koMatches, mounted]);
const targetMatchId = useMemo(() => {
const live = koMatches.find(m => isLive(m));
if (live) return live.id;
const upcoming = koMatches.find(m => m.status !== "FINISHED");
return upcoming?.id ?? null;
}, [koMatches]);
const targetRef = useRef<HTMLDivElement>(null);
const hasScrolledRef = useRef<string | null>(null);
useEffect(() => {
if (!mounted || !targetRef.current) return;
if (targetMatchId === hasScrolledRef.current) return;
const el = targetRef.current;
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> <div>
{groups.map(([date, groupMatches]) => ( {groups.map(([date, groupMatches]) => (
<div key={date} style={{ marginBottom: 24 }}> <div key={date} style={{ marginBottom: 24 }}>
@@ -102,13 +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={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 */}
@@ -117,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>
@@ -184,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>
)}
</>
); );
} }