122 lines
5.2 KiB
TypeScript
122 lines
5.2 KiB
TypeScript
|
|
'use client'
|
||
|
|
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||
|
|
import Link from 'next/link'
|
||
|
|
import { TeamFlag } from '@/components/team-flag'
|
||
|
|
|
||
|
|
const HISTORY_QUERY = gql`
|
||
|
|
query History {
|
||
|
|
tournaments {
|
||
|
|
year host winner runnerUp thirdPlace fourthPlace
|
||
|
|
totalGoals matchesCount teamsCount avgGoalsPerGame
|
||
|
|
topScorers(limit: 1) { playerName goals team { name iso2 } }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
`
|
||
|
|
|
||
|
|
interface Tournament {
|
||
|
|
year: number; host: string; winner?: string | null; runnerUp?: string | null
|
||
|
|
thirdPlace?: string | null; fourthPlace?: string | null
|
||
|
|
totalGoals?: number | null; matchesCount?: number | null; teamsCount?: number | null
|
||
|
|
avgGoalsPerGame?: string | number | null
|
||
|
|
topScorers: Array<{ playerName: string; goals: number; team?: { name: string; iso2?: string | null } | null }>
|
||
|
|
}
|
||
|
|
|
||
|
|
function HostIso(host: string): string {
|
||
|
|
const map: Record<string, string> = {
|
||
|
|
'Uruguay': 'uy', 'Italy': 'it', 'France': 'fr', 'Brazil': 'br',
|
||
|
|
'Switzerland': 'ch', 'Sweden': 'se', 'Chile': 'cl', 'England': 'gb-eng',
|
||
|
|
'Mexico': 'mx', 'Germany': 'de', 'Argentina': 'ar', 'Spain': 'es',
|
||
|
|
'South Korea / Japan': 'kr', 'South Africa': 'za', 'Russia': 'ru',
|
||
|
|
'Qatar': 'qa', 'USA': 'us', 'USA / Canada / Mexico': 'us',
|
||
|
|
}
|
||
|
|
return map[host] ?? 'un'
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function HistoryPage() {
|
||
|
|
const { data, loading } = useQuery(HISTORY_QUERY)
|
||
|
|
const tournaments: Tournament[] = data?.tournaments ?? []
|
||
|
|
const is2026InProgress = !tournaments.find(t => t.year === 2026)?.winner
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||
|
|
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none mb-2">
|
||
|
|
World Cup History
|
||
|
|
</h1>
|
||
|
|
<p className="text-[#2a5c35] text-sm mb-9">
|
||
|
|
Every edition — Uruguay 1930 through 2026 · {tournaments.length} tournaments
|
||
|
|
</p>
|
||
|
|
|
||
|
|
{loading && !data && (
|
||
|
|
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
|
||
|
|
{Array.from({ length: 24 }).map((_, i) => (
|
||
|
|
<div key={i} className="h-52 rounded-2xl animate-pulse" style={{ background: '#0a1810' }} />
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
|
||
|
|
{tournaments.map(t => {
|
||
|
|
const inProgress = t.year === 2026 && is2026InProgress
|
||
|
|
const topScorer = t.topScorers?.[0]
|
||
|
|
return (
|
||
|
|
<Link key={t.year} href={`/tournaments/${t.year}`}>
|
||
|
|
<div className="rounded-2xl p-5 relative overflow-hidden cursor-pointer hover:border-[rgba(34,197,94,0.3)] transition-colors"
|
||
|
|
style={{ background: '#0a1810', border: '1px solid rgba(34,197,94,0.13)' }}>
|
||
|
|
{/* Year watermark */}
|
||
|
|
<div className="absolute right-[-6px] bottom-[-18px] font-['Bebas_Neue'] text-[88px] leading-none pointer-events-none select-none"
|
||
|
|
style={{ color: 'rgba(34,197,94,0.04)' }}>
|
||
|
|
{t.year}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="relative">
|
||
|
|
<div className="flex justify-between items-start mb-3.5">
|
||
|
|
<div>
|
||
|
|
<div className="font-['Bebas_Neue'] text-[34px] text-[#22c55e] leading-none">{t.year}</div>
|
||
|
|
<div className="text-xs text-[#2a5c35] mt-0.5 flex items-center gap-1.5">
|
||
|
|
<span className={`fi fi-${HostIso(t.host)} rounded-sm text-sm inline-block`} />
|
||
|
|
{t.host}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{inProgress
|
||
|
|
? <div className="text-[10px] text-[#22c55e] font-bold tracking-[0.12em] bg-[rgba(34,197,94,0.1)] px-2.5 py-1 rounded-full mt-1">
|
||
|
|
IN PROGRESS
|
||
|
|
</div>
|
||
|
|
: t.winner && (
|
||
|
|
<div className="text-right">
|
||
|
|
<TeamFlag name={t.winner} size="md" />
|
||
|
|
<div className="text-[11px] text-[#6abf7a] mt-0.5">{t.winner}</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{!inProgress && t.winner && t.runnerUp && (
|
||
|
|
<div className="rounded-lg px-3 py-2 text-xs text-[#6abf7a] mb-3"
|
||
|
|
style={{ background: 'rgba(34,197,94,0.07)' }}>
|
||
|
|
<span className="font-semibold text-[#dff5e8]">{t.winner}</span>
|
||
|
|
<span className="mx-2 text-[#2a5c35]">def.</span>
|
||
|
|
{t.runnerUp}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
<div className="flex gap-3.5 text-[11px] text-[#2a5c35] flex-wrap">
|
||
|
|
{t.totalGoals != null && <span>⚽ {t.totalGoals}</span>}
|
||
|
|
{t.matchesCount != null && <span>🗓 {t.matchesCount} games</span>}
|
||
|
|
{t.teamsCount != null && <span>🏳 {t.teamsCount} teams</span>}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{topScorer && (
|
||
|
|
<div className="mt-2 text-[10px] text-[#1a3a22]">
|
||
|
|
Golden Boot: <span className="text-[#2a5c35]">{topScorer.playerName} ({topScorer.goals}⚽)</span>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Link>
|
||
|
|
)
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|