refactor: replace hardcoded hex colors with theme tokens, move data/ to root

- Add --color-green-mid token (#4a7a55) to @theme for dimmer stat values
- Replace all text-[#hex]/bg-[#hex] arbitrary values with named tokens:
  text-green, text-green-light, text-green-sec, text-green-muted,
  text-green-dark, text-green-mid, text-text, bg-card, bg-bg, border-border
- Replace rgba(34,197,94,X) inline styles with bg-green/X opacity modifiers
- Convert single-prop style={{ borderColor/background }} to className
- Fix SVG stroke="#dff5e8" → stroke="currentColor"
- Use CSS variables in globals.css base styles (background-color, color)
- Move app/data/wikipedia/ → data/ (project root, not inside Next.js app dir)
- Update Dockerfile, seed.ts, scrape-wikipedia.ts paths accordingly
- Remove unused app/data/world_cup.csv

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 18:08:23 +02:00
parent 187ee2e312
commit b141356247
125 changed files with 279 additions and 322 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/lib ./lib
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/tsconfig.json ./tsconfig.json
COPY --from=builder /app/app/data ./app/data
COPY --from=builder /app/data ./data
USER nextjs
EXPOSE 3000
ENV PORT=3000 HOSTNAME="0.0.0.0"
-23
View File
@@ -1,23 +0,0 @@
Year,Host,Teams,Champion,Runner-Up,TopScorrer,Attendance,AttendanceAvg,Matches
2022,Qatar,32,Argentina,France,Kylian Mbappé - 8,3404252,53191,64
2018,Russia,32,France,Croatia,Harry Kane - 6,3031768,47371,64
2014,Brazil,32,Germany,Argentina,James Rodríguez - 6,3429873,53592,64
2010,South Africa,32,Spain,Netherlands,"Wesley Sneijder, Thomas Müller... - 5",3178856,49670,64
2006,Germany,32,Italy,France,Miroslav Klose - 5,3352605,52384,64
2002,"Korea Republic, Japan",32,Brazil,Germany,Ronaldo - 8,2705337,42271,64
1998,France,32,France,Brazil,Davor Šuker - 6,2903477,45367,64
1994,United States,24,Brazil,Italy,"Hristo Stoichkov, Oleg Salenko - 6",3587538,68991,52
1990,Italy,24,West Germany,Argentina,Salvatore Schillaci - 6,2516215,48389,52
1986,Mexico,24,Argentina,West Germany,Gary Lineker - 6,2394031,46039,52
1982,Spain,24,Italy,West Germany,Paolo Rossi - 6,2109723,40572,52
1978,Argentina,16,Argentina,Netherlands,Mario Kempes - 6,1545791,40679,38
1974,Germany,16,West Germany,Netherlands,Grzegorz Lato - 7,1865753,49099,38
1970,Mexico,16,Brazil,Italy,Gerd Müller - 10,1603975,50124,32
1966,England,16,England,West Germany,Eusébio - 9,1563135,48848,32
1962,Chile,16,Brazil,Czechoslovakia,"Leonel Sánchez, Flórián Albert... - 4",893172,27912,32
1958,Sweden,16,Brazil,Sweden,Just Fontaine - 13,819810,23423,35
1954,Switzerland,16,Germany,Hungary,Sándor Kocsis - 11,768607,29562,26
1950,Brazil,15,Uruguay,Brazil,Ademir - 8,1045246,47511,22
1938,France,16,Italy,Hungary,Leônidas - 7,375700,20872,18
1934,Italy,16,Italy,Czechoslovakia,Oldřich Nejedlý - 5,363000,21353,17
1930,Uruguay,13,Uruguay,Argentina,Guillermo Stábile - 8,590549,32808,18
1 Year Host Teams Champion Runner-Up TopScorrer Attendance AttendanceAvg Matches
2 2022 Qatar 32 Argentina France Kylian Mbappé - 8 3404252 53191 64
3 2018 Russia 32 France Croatia Harry Kane - 6 3031768 47371 64
4 2014 Brazil 32 Germany Argentina James Rodríguez - 6 3429873 53592 64
5 2010 South Africa 32 Spain Netherlands Wesley Sneijder, Thomas Müller... - 5 3178856 49670 64
6 2006 Germany 32 Italy France Miroslav Klose - 5 3352605 52384 64
7 2002 Korea Republic, Japan 32 Brazil Germany Ronaldo - 8 2705337 42271 64
8 1998 France 32 France Brazil Davor Šuker - 6 2903477 45367 64
9 1994 United States 24 Brazil Italy Hristo Stoichkov, Oleg Salenko - 6 3587538 68991 52
10 1990 Italy 24 West Germany Argentina Salvatore Schillaci - 6 2516215 48389 52
11 1986 Mexico 24 Argentina West Germany Gary Lineker - 6 2394031 46039 52
12 1982 Spain 24 Italy West Germany Paolo Rossi - 6 2109723 40572 52
13 1978 Argentina 16 Argentina Netherlands Mario Kempes - 6 1545791 40679 38
14 1974 Germany 16 West Germany Netherlands Grzegorz Lato - 7 1865753 49099 38
15 1970 Mexico 16 Brazil Italy Gerd Müller - 10 1603975 50124 32
16 1966 England 16 England West Germany Eusébio - 9 1563135 48848 32
17 1962 Chile 16 Brazil Czechoslovakia Leonel Sánchez, Flórián Albert... - 4 893172 27912 32
18 1958 Sweden 16 Brazil Sweden Just Fontaine - 13 819810 23423 35
19 1954 Switzerland 16 Germany Hungary Sándor Kocsis - 11 768607 29562 26
20 1950 Brazil 15 Uruguay Brazil Ademir - 8 1045246 47511 22
21 1938 France 16 Italy Hungary Leônidas - 7 375700 20872 18
22 1934 Italy 16 Italy Czechoslovakia Oldřich Nejedlý - 5 363000 21353 17
23 1930 Uruguay 13 Uruguay Argentina Guillermo Stábile - 8 590549 32808 18
+6 -5
View File
@@ -12,6 +12,7 @@
--color-green-sec: #6abf7a;
--color-green-muted: #2a5c35;
--color-green-dark: #1a3a22;
--color-green-mid: #4a7a55;
--color-text: #dff5e8;
--color-border: rgba(34,197,94,0.15);
@@ -25,7 +26,7 @@
html { scroll-behavior: smooth; }
body {
background-color: #040d08;
background-color: var(--color-bg);
/* Diagonal goal-net pattern */
background-image:
repeating-linear-gradient(
@@ -38,7 +39,7 @@
rgba(34,197,94,0.028) 0, rgba(34,197,94,0.028) 1px,
transparent 1px, transparent 28px
);
color: #dff5e8;
color: var(--color-text);
font-family: "Space Grotesk", system-ui, sans-serif;
min-height: 100vh;
overflow-x: hidden;
@@ -47,7 +48,7 @@
/* Glass card — semi-transparent over the body net pattern */
.glass-card {
background: rgba(4, 18, 8, 0.78);
border: 1px solid rgba(34,197,94,0.15);
border: 1px solid var(--color-border);
border-radius: 1rem;
overflow: hidden;
backdrop-filter: blur(10px);
@@ -56,7 +57,7 @@
.glass-card-hero {
background: linear-gradient(145deg, rgba(13,32,22,0.82), rgba(16,42,28,0.82));
border: 1px solid rgba(34,197,94,0.28);
border: 1px solid color-mix(in srgb, var(--color-green) 28%, transparent);
border-radius: 1rem;
overflow: hidden;
backdrop-filter: blur(10px);
@@ -65,7 +66,7 @@
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: #020a04; }
::-webkit-scrollbar-thumb { background: rgba(34,197,94,0.25); border-radius: 4px; }
::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--color-green) 25%, transparent); border-radius: 4px; }
@keyframes livePulse {
0%, 100% { opacity: 1; transform: scale(1); }
+13 -20
View File
@@ -36,14 +36,14 @@ export default function GroupsPage() {
return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
<div className="mb-9">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none">2026 Groups</h1>
<p className="text-[#2a5c35] text-sm mt-1.5">48 teams · 12 groups · Top 2 + 8 best 3rd-place advance</p>
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none">2026 Groups</h1>
<p className="text-green-muted text-sm mt-1.5">48 teams · 12 groups · Top 2 + 8 best 3rd-place advance</p>
</div>
{loading && !data && (
<div className="grid grid-cols-[repeat(auto-fill,minmax(268px,1fr))] gap-3.5">
{Array.from({ length: 12 }).map((_, i) => (
<div key={i} className="h-56 rounded-2xl animate-pulse" style={{ background: '#0a1810' }} />
<div key={i} className="h-56 rounded-2xl animate-pulse bg-card" />
))}
</div>
)}
@@ -58,13 +58,11 @@ export default function GroupsPage() {
const letter = groupName.replace('Group ', '')
return (
<div key={groupName} className="glass-card">
<div className="px-4 py-3 border-b" style={{
background: 'linear-gradient(90deg,rgba(34,197,94,0.12) 0%,rgba(34,197,94,0.04) 100%)',
borderColor: 'rgba(34,197,94,0.1)',
}}>
<span className="font-['Bebas_Neue'] text-[28px] text-[#22c55e] tracking-[0.05em]">GROUP {letter}</span>
<div className="px-4 py-3 border-b border-green/10"
style={{ background: 'linear-gradient(90deg,color-mix(in srgb,var(--color-green) 12%,transparent) 0%,color-mix(in srgb,var(--color-green) 4%,transparent) 100%)' }}>
<span className="font-['Bebas_Neue'] text-[28px] text-green tracking-[0.05em]">GROUP {letter}</span>
</div>
<div className="grid px-4 py-2 text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase"
<div className="grid px-4 py-2 text-[9px] text-green-muted tracking-[0.1em] uppercase"
style={{ gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px', gap: '3px' }}>
<span>Team</span>
<span className="text-center">P</span><span className="text-center">W</span>
@@ -73,24 +71,19 @@ export default function GroupsPage() {
</div>
{sorted.map((t, idx) => (
<Link key={t.team.id} href={`/teams/${t.team.slug}`}>
<div className="grid px-4 py-2.5 items-center border-t hover:bg-[rgba(34,197,94,0.03)] transition-colors cursor-pointer"
style={{
gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px',
gap: '3px',
borderColor: 'rgba(34,197,94,0.06)',
background: idx < 2 ? 'rgba(34,197,94,0.025)' : undefined,
}}>
<div className={`grid px-4 py-2.5 items-center border-t border-green/[6%] hover:bg-green/[3%] transition-colors cursor-pointer ${idx < 2 ? 'bg-green/[2.5%]' : ''}`}
style={{ gridTemplateColumns: '1fr 22px 22px 22px 22px 22px 30px', gap: '3px' }}>
<div className="flex items-center gap-2 overflow-hidden">
<TeamFlag name={t.team.name} iso2={t.team.iso2} size="sm" />
<span className={`text-sm truncate font-medium ${idx < 2 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{t.team.name}</span>
<span className={`text-sm truncate font-medium ${idx < 2 ? 'text-text' : 'text-green-sec'}`}>{t.team.name}</span>
</div>
{[t.played, t.won, t.drawn, t.lost].map((v, i) => (
<span key={i} className="text-center text-[13px] text-[#4a7a55]">{v}</span>
<span key={i} className="text-center text-[13px] text-green-mid">{v}</span>
))}
<span className="text-center text-[13px] text-[#4a7a55]">
<span className="text-center text-[13px] text-green-mid">
{t.goalDiff > 0 ? `+${t.goalDiff}` : t.goalDiff}
</span>
<span className="text-center text-[13px] font-bold text-[#22c55e]">{t.pts}</span>
<span className="text-center text-[13px] font-bold text-green">{t.pts}</span>
</div>
</Link>
))}
+15 -17
View File
@@ -33,17 +33,17 @@ export default function HistoryPage() {
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">
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-2">
World Cup History
</h1>
<p className="text-[#2a5c35] text-sm mb-9">
<p className="text-green-muted 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 key={i} className="h-52 rounded-2xl animate-pulse bg-card" />
))}
</div>
)}
@@ -54,52 +54,50 @@ export default function HistoryPage() {
const topScorer = t.topScorers?.[0]
return (
<Link key={t.year} href={`/tournaments/${t.year}`}>
<div className="glass-card p-5 relative cursor-pointer hover:border-[rgba(34,197,94,0.3)] transition-colors">
<div className="glass-card p-5 relative cursor-pointer hover:border-green/30 transition-colors">
{/* 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)' }}>
<div className="absolute right-[-6px] bottom-[-18px] font-['Bebas_Neue'] text-[88px] leading-none pointer-events-none select-none text-green/[4%]">
{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">
<div className="font-['Bebas_Neue'] text-[34px] text-green leading-none">{t.year}</div>
<div className="text-xs text-green-muted mt-0.5">
{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">
? <div className="text-[10px] text-green font-bold tracking-[0.12em] bg-green/10 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 className="text-[11px] text-green-sec 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>
<div className="rounded-lg px-3 py-2 text-xs text-green-sec mb-3 bg-green/[7%]">
<span className="font-semibold text-text">{t.winner}</span>
<span className="mx-2 text-green-muted">def.</span>
{t.runnerUp}
</div>
)}
<div className="flex gap-3.5 text-[11px] text-[#2a5c35] flex-wrap">
<div className="flex gap-3.5 text-[11px] text-green-muted flex-wrap">
{t.totalGoals != null && <span className="inline-flex items-center gap-1"><FireIcon className="w-3 h-3" />{t.totalGoals}</span>}
{t.matchesCount != null && <span className="inline-flex items-center gap-1"><CalendarDaysIcon className="w-3 h-3" />{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} (<span className="inline-flex items-center gap-0.5"><FireIcon className="w-2.5 h-2.5 inline" />{topScorer.goals}</span>)</span>
<div className="mt-2 text-[10px] text-green-dark">
Golden Boot: <span className="text-green-muted">{topScorer.playerName} (<span className="inline-flex items-center gap-0.5"><FireIcon className="w-2.5 h-2.5 inline" />{topScorer.goals}</span>)</span>
</div>
)}
</div>
+3 -3
View File
@@ -35,11 +35,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<AppApolloProvider>
<Nav />
<main className="pt-[60px] min-h-screen">{children}</main>
<footer className="border-t mt-8" style={{ borderColor: 'rgba(34,197,94,0.08)' }}>
<div className="max-w-[1200px] mx-auto px-7 py-6 flex flex-col sm:flex-row items-center justify-between gap-2 text-[11px] text-[#1a3a22]">
<footer className="border-t border-green/8 mt-8">
<div className="max-w-[1200px] mx-auto px-7 py-6 flex flex-col sm:flex-row items-center justify-between gap-2 text-[11px] text-green-dark">
<span>© {new Date().getFullYear()} World Cup Statistics.</span>
<a href="https://dev.pivoine.art" target="_blank" rel="noopener noreferrer"
className="text-[#2a5c35] hover:text-[#22c55e] transition-colors">
className="text-green-muted hover:text-green transition-colors">
dev.pivoine.art
</a>
</div>
+3 -3
View File
@@ -9,15 +9,15 @@ export default function NotFound() {
<div
className="pitch-grid glass-card-hero rounded-2xl px-12 py-16 w-full max-w-lg"
>
<div className="font-['Bebas_Neue'] text-[120px] text-[#22c55e] leading-none">
<div className="font-['Bebas_Neue'] text-[120px] text-green leading-none">
404
</div>
<p className="text-[#6abf7a] text-lg mt-2 mb-8">
<p className="text-green-sec text-lg mt-2 mb-8">
This page doesn&apos;t exist.
</p>
<Link
href="/"
className="inline-block font-['Bebas_Neue'] text-xl tracking-[0.1em] text-[#040d08] bg-[#22c55e] px-8 py-3 rounded-xl hover:bg-[#4ade80] transition-colors"
className="inline-block font-['Bebas_Neue'] text-xl tracking-[0.1em] text-bg bg-green px-8 py-3 rounded-xl hover:bg-green-light transition-colors"
>
Back to Home
</Link>
+24 -27
View File
@@ -32,18 +32,17 @@ const HOME_QUERY = gql`
function SectionHeader({ label }: { label: string }) {
return (
<div className="flex items-center gap-2.5 mb-4">
<div className="w-[3px] h-[18px] bg-[#22c55e] rounded-sm" />
<span className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase">{label}</span>
<div className="w-[3px] h-[18px] bg-green rounded-sm" />
<span className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase">{label}</span>
</div>
)
}
function StatPill({ label, value }: { label: string; value: string | number }) {
return (
<div className="flex-1 min-w-[90px] rounded-xl p-3.5 px-5"
style={{ background: 'rgba(34,197,94,0.05)', border: '1px solid rgba(34,197,94,0.12)' }}>
<div className="text-[9px] text-[#2a5c35] tracking-[0.13em] uppercase mb-1.5 whitespace-nowrap">{label}</div>
<div className="font-['Bebas_Neue'] text-[30px] text-[#22c55e] leading-none">{value ?? ''}</div>
<div className="flex-1 min-w-[90px] rounded-xl p-3.5 px-5 bg-green/5 border border-green/[12%]">
<div className="text-[9px] text-green-muted tracking-[0.13em] uppercase mb-1.5 whitespace-nowrap">{label}</div>
<div className="font-['Bebas_Neue'] text-[30px] text-green leading-none">{value ?? ''}</div>
</div>
)
}
@@ -58,13 +57,13 @@ function UpcomingFixture({ match }: { match: UpcomingMatch }) {
const time = match.time?.split(' ')[0] ?? ''
return (
<Link href={`/tournaments/${match.year}#match-${match.id}`}>
<div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-[rgba(34,197,94,0.2)] transition-colors cursor-pointer">
<div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-green/20 transition-colors cursor-pointer">
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
<div className="flex-1 text-[13px] text-[#6abf7a] font-medium truncate">
{match.team1.name} <span className="text-[#2a5c35]">vs</span> {match.team2.name}
<div className="flex-1 text-[13px] text-green-sec font-medium truncate">
{match.team1.name} <span className="text-green-muted">vs</span> {match.team2.name}
</div>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
{time && <div className="text-[11px] text-[#2a5c35] whitespace-nowrap ml-1">{time}</div>}
{time && <div className="text-[11px] text-green-muted whitespace-nowrap ml-1">{time}</div>}
</div>
</Link>
)
@@ -100,9 +99,8 @@ export default function HomePage() {
return (
<div>
{/* ── Hero ── */}
<div className="pitch-grid border-b" style={{
<div className="pitch-grid border-b border-border" style={{
background: 'linear-gradient(145deg,rgba(10,26,14,0.9) 0%,rgba(13,36,22,0.9) 55%,rgba(10,26,14,0.9) 100%)',
borderColor: 'rgba(34,197,94,0.15)',
padding: '52px 0 44px',
}}>
<div className="max-w-[1200px] mx-auto px-7">
@@ -110,15 +108,15 @@ export default function HomePage() {
{live.length > 0
? <LiveBadge label="Live · Group Stage in Progress" />
: <div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-[#22c55e] inline-block" />
<span className="text-[11px] font-bold text-[#22c55e] tracking-[0.14em] uppercase">World Cup 2026 · In Progress</span>
<span className="w-2 h-2 rounded-full bg-green inline-block" />
<span className="text-[11px] font-bold text-green tracking-[0.14em] uppercase">World Cup 2026 · In Progress</span>
</div>
}
</div>
<h1 className="font-['Bebas_Neue'] text-[clamp(50px,9vw,100px)] tracking-[0.04em] text-white leading-[0.92] mb-2.5">
World Cup 2026
</h1>
<p className="text-[#2a5c35] text-sm mb-9">
<p className="text-green-muted text-sm mb-9">
USA · Canada · Mexico &nbsp;·&nbsp; 11 June 19 July 2026 · 48 Teams
</p>
<div className="flex gap-2.5 flex-wrap max-w-[760px]">
@@ -132,7 +130,7 @@ export default function HomePage() {
<StatPill label="2026 Avg" value={wc2026.avgGoalsPerGame ? Number(wc2026.avgGoalsPerGame).toFixed(2) : ''} />
</>}
</> : [1,2,3,4].map(i => (
<div key={i} className="flex-1 min-w-[90px] h-20 rounded-xl animate-pulse" style={{ background: 'rgba(34,197,94,0.04)' }} />
<div key={i} className="flex-1 min-w-[90px] h-20 rounded-xl animate-pulse bg-green/[4%]" />
))}
</div>
</div>
@@ -184,30 +182,29 @@ export default function HomePage() {
<div className="glass-card">
{scorers.map((s, i) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-[rgba(34,197,94,0.03)] transition-colors cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}>
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className={`flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b border-green/[6%] hover:bg-green/[3%] transition-colors cursor-pointer ${i === 0 ? 'bg-green/[4%]' : ''}`}>
<span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0">
<div className={`text-sm font-semibold truncate ${i === 0 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{s.playerName}</div>
<div className="text-[10px] text-[#2a5c35] truncate">{s.team?.name}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
<div className={`text-sm font-semibold truncate ${i === 0 ? 'text-text' : 'text-green-sec'}`}>{s.playerName}</div>
<div className="text-[10px] text-green-muted truncate">{s.team?.name}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
</div>
<div className="hidden sm:block w-24 h-1 rounded-full overflow-hidden flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}>
<div className="h-full rounded-full bg-[#22c55e] transition-all" style={{ width: `${(s.goals / maxGoals) * 100}%` }} />
<div className="hidden sm:block w-24 h-1 rounded-full overflow-hidden flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-green transition-all" style={{ width: `${(s.goals / maxGoals) * 100}%` }} />
</div>
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] min-w-[24px] text-right flex-shrink-0">{s.goals}</span>
<span className="font-['Bebas_Neue'] text-[22px] text-green min-w-[24px] text-right flex-shrink-0">{s.goals}</span>
</div>
</Link>
))}
</div>
<p className="text-[10px] text-[#1a3a22] mt-3 text-center">
<Link href="/stats" className="hover:text-[#2a5c35]">View all-time top scorers </Link>
<p className="text-[10px] text-green-dark mt-3 text-center">
<Link href="/stats" className="hover:text-green-muted">View all-time top scorers </Link>
</p>
</div>
)}
{loading && !data && (
<div className="py-16 text-center text-[#2a5c35] text-sm">Loading live World Cup data</div>
<div className="py-16 text-center text-green-muted text-sm">Loading live World Cup data</div>
)}
</div>
</div>
+13 -13
View File
@@ -47,15 +47,15 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
`)
if (loading && !data) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Loading player</div>
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Loading player</div>
}
if (!player) {
return (
<div className="max-w-[1200px] mx-auto px-7 py-10">
<h1 className="font-['Bebas_Neue'] text-[52px] text-[#22c55e]">{name}</h1>
<p className="text-[#2a5c35] mt-4">No goal data found for this player in World Cup history.</p>
<Link href="/stats" className="text-[#22c55e] text-sm mt-4 inline-block hover:underline"> All-time scorers</Link>
<h1 className="font-['Bebas_Neue'] text-[52px] text-green">{name}</h1>
<p className="text-green-muted mt-4">No goal data found for this player in World Cup history.</p>
<Link href="/stats" className="text-green text-sm mt-4 inline-block hover:underline"> All-time scorers</Link>
</div>
)
}
@@ -69,16 +69,16 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
<div className="flex items-center gap-6 flex-wrap">
{player.team && <TeamFlag name={player.team.name} iso2={player.team.iso2} size="xl" />}
<div>
<h1 className="font-['Bebas_Neue'] text-[clamp(36px,6vw,64px)] text-[#22c55e] leading-none">{player.playerName}</h1>
<h1 className="font-['Bebas_Neue'] text-[clamp(36px,6vw,64px)] text-green leading-none">{player.playerName}</h1>
{player.team && (
<Link href={`/teams/${player.team.slug}`} className="text-[#6abf7a] text-sm mt-1 hover:text-[#dff5e8] transition-colors inline-block">
<Link href={`/teams/${player.team.slug}`} className="text-green-sec text-sm mt-1 hover:text-text transition-colors inline-block">
{player.team.name}
</Link>
)}
</div>
<div className="ml-auto text-right">
<div className="font-['Bebas_Neue'] text-[80px] text-[#22c55e] leading-none">{player.goals}</div>
<div className="text-[10px] text-[#2a5c35] tracking-[0.12em] uppercase">World Cup Goals</div>
<div className="font-['Bebas_Neue'] text-[80px] text-green leading-none">{player.goals}</div>
<div className="text-[10px] text-green-muted tracking-[0.12em] uppercase">World Cup Goals</div>
</div>
</div>
</div>
@@ -92,23 +92,23 @@ export default function PlayerPage({ params }: { params: Promise<{ name: string
{ label: 'Tournaments', value: player.tournaments },
].map(item => (
<div key={item.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{item.value}</div>
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-green">{item.value}</div>
</div>
))}
</div>
{player.ownGoals > 0 && (
<div className="mb-6 glass-card rounded-xl p-3 px-4 text-sm text-[#2a5c35]">
<div className="mb-6 glass-card rounded-xl p-3 px-4 text-sm text-green-muted">
Includes {player.ownGoals} own goal{player.ownGoals !== 1 ? 's' : ''}
</div>
)}
{/* Back links */}
<div className="flex gap-4 mt-8">
<Link href="/stats" className="text-[#22c55e] text-sm hover:underline"> All-time scorers</Link>
<Link href="/stats" className="text-green text-sm hover:underline"> All-time scorers</Link>
{player.team && (
<Link href={`/teams/${player.team.slug}`} className="text-[#22c55e] text-sm hover:underline">
<Link href={`/teams/${player.team.slug}`} className="text-green text-sm hover:underline">
{player.team.name} team page
</Link>
)}
+29 -30
View File
@@ -62,7 +62,7 @@ function SearchContent() {
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-6">Search</h1>
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-6">Search</h1>
{/* Search input */}
<div className="relative max-w-lg mb-8">
@@ -70,47 +70,46 @@ function SearchContent() {
type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search teams, players, tournaments…"
autoFocus
className="w-full pl-10 pr-4 py-3 rounded-2xl text-[#dff5e8] text-sm outline-none"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.2)' }}
className="w-full pl-10 pr-4 py-3 rounded-2xl text-text text-sm outline-none bg-green/[6%] border-green/20"
/>
<svg className="absolute left-3.5 top-1/2 -translate-y-1/2 opacity-40" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5">
<svg className="absolute left-3.5 top-1/2 -translate-y-1/2 opacity-40" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
{loading && <div className="absolute right-3.5 top-1/2 -translate-y-1/2 w-4 h-4 border-2 border-[#22c55e] border-t-transparent rounded-full animate-spin" />}
{loading && <div className="absolute right-3.5 top-1/2 -translate-y-1/2 w-4 h-4 border-2 border-green border-t-transparent rounded-full animate-spin" />}
</div>
{/* Prompt */}
{skip && (
<div className="flex flex-col items-center py-20 text-center">
<div className="text-[56px] mb-5">🔍</div>
<div className="text-[#2a5c35] text-base">Search for nations, players, or tournaments</div>
<div className="text-[#1a3a22] text-sm mt-2">Examples: "Brazil", "Ronaldo", "1966"</div>
<div className="text-green-muted text-base">Search for nations, players, or tournaments</div>
<div className="text-green-dark text-sm mt-2">Examples: "Brazil", "Ronaldo", "1966"</div>
</div>
)}
{/* No results */}
{!skip && !loading && total === 0 && (
<div className="text-center text-[#1a3a22] py-16 text-sm">No results for "{debouncedQ}"</div>
<div className="text-center text-green-dark py-16 text-sm">No results for "{debouncedQ}"</div>
)}
{/* Results count */}
{!skip && total > 0 && (
<div className="text-[13px] text-[#2a5c35] mb-6">{total} result{total !== 1 ? 's' : ''} for "{debouncedQ}"</div>
<div className="text-[13px] text-green-muted mb-6">{total} result{total !== 1 ? 's' : ''} for "{debouncedQ}"</div>
)}
<div className="flex flex-col gap-6">
{/* Teams */}
{results?.teams?.length > 0 && (
<section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Teams</h3>
<h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Teams</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-2.5">
{results.teams.map((t: { name: string; iso2?: string | null; slug: string; stats?: { appearances: number; titles: number } | null }) => (
<Link key={t.name} href={`/teams/${t.slug}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer">
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<TeamFlag name={t.name} iso2={t.iso2} size="md" />
<div>
<div className="text-sm font-semibold text-[#dff5e8]">{t.name}</div>
<div className="text-[10px] text-[#2a5c35]">
<div className="text-sm font-semibold text-text">{t.name}</div>
<div className="text-[10px] text-green-muted">
{t.stats?.appearances ?? 0} WCs{t.stats?.titles ? <span className="inline-flex items-center gap-0.5 ml-1">· {t.stats.titles}<TrophyIcon className="w-3 h-3 inline" /></span> : ''}
</div>
</div>
@@ -124,17 +123,17 @@ function SearchContent() {
{/* Players */}
{results?.players?.length > 0 && (
<section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Players</h3>
<h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Players</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(220px,1fr))] gap-2.5">
{results.players.map((p: { playerName: string; goals: number; tournaments: number; team?: { name: string; iso2?: string | null } | null }) => (
<Link key={p.playerName} href={`/players/${encodeURIComponent(p.playerName)}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer">
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
{p.team && <TeamFlag name={p.team.name} iso2={p.team.iso2} size="sm" />}
<div className="flex-1 min-w-0">
<div className="text-sm font-semibold text-[#dff5e8] truncate">{p.playerName}</div>
<div className="text-[10px] text-[#2a5c35]">{p.team?.name} · {p.tournaments} WC{p.tournaments !== 1 ? 's' : ''}</div>
<div className="text-sm font-semibold text-text truncate">{p.playerName}</div>
<div className="text-[10px] text-green-muted">{p.team?.name} · {p.tournaments} WC{p.tournaments !== 1 ? 's' : ''}</div>
</div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0 inline-flex items-center gap-0.5">{p.goals}<FireIcon className="w-3.5 h-3.5" /></span>
<span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0 inline-flex items-center gap-0.5">{p.goals}<FireIcon className="w-3.5 h-3.5" /></span>
</div>
</Link>
))}
@@ -145,15 +144,15 @@ function SearchContent() {
{/* Tournaments */}
{results?.tournaments?.length > 0 && (
<section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Tournaments</h3>
<h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Tournaments</h3>
<div className="grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2.5">
{results.tournaments.map((t: { year: number; host: string; winner?: string | null; totalGoals?: number | null; matchesCount?: number | null }) => (
<Link key={t.year} href={`/tournaments/${t.year}`}>
<div className="glass-card p-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer">
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{t.year}</div>
<div className="text-sm text-[#dff5e8]">{t.host}</div>
{t.winner && <div className="text-[10px] text-[#2a5c35] mt-1 flex items-center gap-1"><TrophyIcon className="w-3 h-3 flex-shrink-0" />{t.winner}</div>}
{t.totalGoals && <div className="text-[10px] text-[#1a3a22] flex items-center gap-1"><FireIcon className="w-3 h-3 flex-shrink-0" />{t.totalGoals} goals</div>}
<div className="glass-card p-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<div className="font-['Bebas_Neue'] text-3xl text-green">{t.year}</div>
<div className="text-sm text-text">{t.host}</div>
{t.winner && <div className="text-[10px] text-green-muted mt-1 flex items-center gap-1"><TrophyIcon className="w-3 h-3 flex-shrink-0" />{t.winner}</div>}
{t.totalGoals && <div className="text-[10px] text-green-dark flex items-center gap-1"><FireIcon className="w-3 h-3 flex-shrink-0" />{t.totalGoals} goals</div>}
</div>
</Link>
))}
@@ -164,16 +163,16 @@ function SearchContent() {
{/* Matches */}
{results?.matches?.length > 0 && (
<section>
<h3 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.12em] uppercase mb-3">Matches</h3>
<h3 className="text-[11px] text-green-muted font-bold tracking-[0.12em] uppercase mb-3">Matches</h3>
<div className="flex flex-col gap-2">
{results.matches.map((m: SearchMatch) => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-[rgba(34,197,94,0.25)] transition-colors cursor-pointer">
<div className="glass-card flex items-center gap-3 p-3 px-4 rounded-xl hover:border-green/25 transition-colors cursor-pointer">
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 text-sm text-[#dff5e8]">{m.team1.name} vs {m.team2.name}</div>
{m.scoreFt && <span className="font-['Bebas_Neue'] text-lg text-[#22c55e]">{m.scoreFt[0]}{m.scoreFt[1]}</span>}
<div className="flex-1 text-sm text-text">{m.team1.name} vs {m.team2.name}</div>
{m.scoreFt && <span className="font-['Bebas_Neue'] text-lg text-green">{m.scoreFt[0]}{m.scoreFt[1]}</span>}
<TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" />
<div className="text-[10px] text-[#2a5c35] whitespace-nowrap">{m.year} · {m.round}</div>
<div className="text-[10px] text-green-muted whitespace-nowrap">{m.year} · {m.round}</div>
</div>
</Link>
))}
@@ -187,7 +186,7 @@ function SearchContent() {
export default function SearchPage() {
return (
<Suspense fallback={<div className="p-10 text-[#2a5c35]">Loading</div>}>
<Suspense fallback={<div className="p-10 text-green-muted">Loading</div>}>
<SearchContent />
</Suspense>
)
+65 -66
View File
@@ -42,7 +42,7 @@ const STATS_QUERY = gql`
function SectionTitle({ children, icon: Icon }: { children: React.ReactNode; icon: React.ComponentType<{ className?: string }> }) {
return (
<h2 className="flex items-center gap-1.5 text-[11px] font-bold tracking-[0.14em] uppercase text-[#2a5c35] mb-4">
<h2 className="flex items-center gap-1.5 text-[11px] font-bold tracking-[0.14em] uppercase text-green-muted mb-4">
<Icon className="w-3.5 h-3.5 flex-shrink-0" />
{children}
</h2>
@@ -92,10 +92,10 @@ export default function StatsPage() {
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-10">Historical Statistics</h1>
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-10">Historical Statistics</h1>
{loading && !data && (
<div className="text-[#2a5c35] text-sm py-16 text-center">Loading statistics</div>
<div className="text-green-muted text-sm py-16 text-center">Loading statistics</div>
)}
{/* ── Goals per tournament bar chart ── */}
@@ -110,18 +110,18 @@ export default function StatsPage() {
const avg = t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(1) : null
return (
<Link key={t.year} href={`/tournaments/${t.year}`} className="flex flex-col items-center flex-1 min-w-[8px] group">
<div className="text-[6px] sm:text-[7px] text-[#2a5c35] font-semibold mb-1 leading-none group-hover:text-[#22c55e]">{t.totalGoals}</div>
<div className="w-full rounded-t-sm border-t-2 transition-colors group-hover:bg-[rgba(34,197,94,0.35)]"
style={{ height: `${h}px`, background: 'rgba(34,197,94,0.18)', borderColor: 'rgba(34,197,94,0.45)' }}
<div className="text-[6px] sm:text-[7px] text-green-muted font-semibold mb-1 leading-none group-hover:text-green">{t.totalGoals}</div>
<div className="w-full rounded-t-sm border-t-2 border-green/45 transition-colors group-hover:bg-green/35 bg-green/[18%]"
style={{ height: `${h}px` }}
title={`${t.year}: ${t.totalGoals} goals${avg ? ` · ${avg}/game` : ''}`}
/>
</Link>
)
})}
</div>
<div className="flex gap-[2px] sm:gap-[3px] pt-1.5 pb-3 border-t" style={{ borderColor: 'rgba(34,197,94,0.06)' }}>
<div className="flex gap-[2px] sm:gap-[3px] pt-1.5 pb-3 border-t border-green/[6%]">
{tournaments.map(t => (
<div key={t.year} className="flex-1 text-center text-[6px] text-[#1a3a22]" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}>
<div key={t.year} className="flex-1 text-center text-[6px] text-green-dark" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}>
{t.year}
</div>
))}
@@ -138,18 +138,17 @@ export default function StatsPage() {
<Card>
{scorers.map((s, i) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}>
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className={`flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 border-b hover:bg-green/[3%] cursor-pointer border-green/5 ${i === 0 ? 'bg-green/[4%]' : ''}`}>
<span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0">
<div className={`text-sm font-semibold truncate ${i < 3 ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>{s.playerName}</div>
<div className="text-[10px] text-[#2a5c35] truncate">{s.team?.name} · {s.tournaments} WC{s.tournaments !== 1 ? 's' : ''}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
<div className={`text-sm font-semibold truncate ${i < 3 ? 'text-text' : 'text-green-sec'}`}>{s.playerName}</div>
<div className="text-[10px] text-green-muted truncate">{s.team?.name} · {s.tournaments} WC{s.tournaments !== 1 ? 's' : ''}{s.penalties > 0 ? ` · ${s.penalties}P` : ''}</div>
</div>
<div className="hidden sm:block w-16 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}>
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
<div className="hidden sm:block w-16 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-green" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
</div>
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] min-w-[28px] text-right flex-shrink-0">{s.goals}</span>
<span className="font-['Bebas_Neue'] text-[22px] text-green min-w-[28px] text-right flex-shrink-0">{s.goals}</span>
</div>
</Link>
))}
@@ -162,17 +161,17 @@ export default function StatsPage() {
<Card>
{titlesByNation.map((t, i) => (
<Link key={t.name} href={`/teams/${t.slug}`}>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}>
<span className="text-[11px] text-[#2a5c35] w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className="flex items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
>
<span className="text-[11px] text-green-muted w-5 text-right font-bold flex-shrink-0">{i + 1}</span>
<TeamFlag name={t.name} iso2={t.iso2} size="sm" />
<div className="flex-1 min-w-0 text-sm font-semibold text-[#dff5e8] truncate">{t.name}</div>
<div className="flex-1 min-w-0 text-sm font-semibold text-text truncate">{t.name}</div>
<div className="hidden sm:flex gap-0.5 flex-shrink-0">
{Array.from({ length: t.stats?.titles ?? 0 }).map((_, j) => (
<TrophyIcon key={j} className="w-4 h-4 text-[#22c55e]" />
<TrophyIcon key={j} className="w-4 h-4 text-green" />
))}
</div>
<span className="font-['Bebas_Neue'] text-[28px] text-[#22c55e] flex-shrink-0">{t.stats?.titles}</span>
<span className="font-['Bebas_Neue'] text-[28px] text-green flex-shrink-0">{t.stats?.titles}</span>
</div>
</Link>
))}
@@ -191,9 +190,9 @@ export default function StatsPage() {
const h = Math.max(8, Math.round((b.count / maxMinute) * 80))
return (
<div key={b.bucket} className="flex-1 flex flex-col items-center gap-1">
<span className="text-[7px] sm:text-[9px] text-[#2a5c35] font-bold leading-none">{b.count}</span>
<div className="w-full rounded-t" style={{ height: `${h}px`, background: 'rgba(34,197,94,0.3)', border: '1px solid rgba(34,197,94,0.5)' }} />
<span className="text-[7px] sm:text-[9px] text-[#1a3a22] leading-none">{b.bucket}</span>
<span className="text-[7px] sm:text-[9px] text-green-muted font-bold leading-none">{b.count}</span>
<div className="w-full rounded-t bg-green/30 border border-green/50" style={{ height: `${h}px` }} />
<span className="text-[7px] sm:text-[9px] text-green-dark leading-none">{b.bucket}</span>
</div>
)
})}
@@ -210,17 +209,17 @@ export default function StatsPage() {
<Card>
{biggestWins.map(m => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
>
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 min-w-0">
<div className="text-sm font-medium text-[#dff5e8] truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-[#2a5c35]">{m.year} · {m.round}</div>
<div className="text-sm font-medium text-text truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-green-muted">{m.year} · {m.round}</div>
</div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">
<span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">
{m.scoreFt?.[0]}{m.scoreFt?.[1]}
</span>
<span className="text-[10px] text-[#2a5c35] flex-shrink-0">+{m.margin}</span>
<span className="text-[10px] text-green-muted flex-shrink-0">+{m.margin}</span>
</div>
</Link>
))}
@@ -233,17 +232,17 @@ export default function StatsPage() {
<Card>
{highScoring.map(m => (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)' }}>
<div className="flex items-center gap-3 px-4 py-2.5 border-b border-green/5 hover:bg-green/[3%] cursor-pointer"
>
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
<div className="flex-1 min-w-0">
<div className="text-sm font-medium text-[#dff5e8] truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-[#2a5c35]">{m.year} · {m.round}</div>
<div className="text-sm font-medium text-text truncate">{m.team1.name} vs {m.team2.name}</div>
<div className="text-[10px] text-green-muted">{m.year} · {m.round}</div>
</div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">
<span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">
{m.scoreFt?.[0]}{m.scoreFt?.[1]}
</span>
<span className="text-[10px] text-[#4ade80] flex-shrink-0">{m.totalGoals} goals</span>
<span className="text-[10px] text-green-light flex-shrink-0">{m.totalGoals} goals</span>
</div>
</Link>
))}
@@ -261,12 +260,12 @@ export default function StatsPage() {
<div className="flex items-center gap-2 mb-2">
{h.team && <TeamFlag name={h.team.name} iso2={h.team.iso2} size="sm" />}
<div>
<div className="text-sm font-semibold text-[#dff5e8]">{h.playerName}</div>
<div className="text-[10px] text-[#2a5c35]">{h.team?.name}</div>
<div className="text-sm font-semibold text-text">{h.playerName}</div>
<div className="text-[10px] text-green-muted">{h.team?.name}</div>
</div>
<span className="ml-auto font-['Bebas_Neue'] text-2xl text-[#22c55e]">{h.goals}</span>
<span className="ml-auto font-['Bebas_Neue'] text-2xl text-green">{h.goals}</span>
</div>
<div className="text-[10px] text-[#2a5c35]">
<div className="text-[10px] text-green-muted">
{h.year} · {h.round}
{h.opponent && <span> vs {h.opponent.name}</span>}
</div>
@@ -288,8 +287,8 @@ export default function StatsPage() {
{ label: 'Decided in 90min', value: etStats.totalKnockoutMatches - etStats.wentToExtraTime },
].map(s => (
<div key={s.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2">{s.label}</div>
<div className="font-['Bebas_Neue'] text-2xl text-[#22c55e]">{s.value}</div>
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2">{s.label}</div>
<div className="font-['Bebas_Neue'] text-2xl text-green">{s.value}</div>
</div>
))}
</div>
@@ -303,20 +302,20 @@ export default function StatsPage() {
<Card>
<table className="w-full">
<thead>
<tr className="border-b" style={{ borderColor: 'rgba(34,197,94,0.08)' }}>
<th className="text-left px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Confederation</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Appearances</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Titles</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35]">Goals</th>
<tr className="border-b border-green/8">
<th className="text-left px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Confederation</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Appearances</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Titles</th>
<th className="text-right px-4 py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted">Goals</th>
</tr>
</thead>
<tbody>
{confStats.map(c => (
<tr key={c.confederation} className="border-t" style={{ borderColor: 'rgba(34,197,94,0.06)' }}>
<td className="px-4 py-3 text-sm font-medium text-[#dff5e8]">{c.confederation}</td>
<td className="px-4 py-3 text-right text-sm text-[#6abf7a]">{c.appearances}</td>
<td className="px-4 py-3 text-right font-['Bebas_Neue'] text-xl text-[#22c55e]">{c.titles}</td>
<td className="px-4 py-3 text-right text-sm text-[#6abf7a]">{c.totalGoals}</td>
<tr key={c.confederation} className="border-t border-green/[6%]">
<td className="px-4 py-3 text-sm font-medium text-text">{c.confederation}</td>
<td className="px-4 py-3 text-right text-sm text-green-sec">{c.appearances}</td>
<td className="px-4 py-3 text-right font-['Bebas_Neue'] text-xl text-green">{c.titles}</td>
<td className="px-4 py-3 text-right text-sm text-green-sec">{c.totalGoals}</td>
</tr>
))}
</tbody>
@@ -333,34 +332,34 @@ export default function StatsPage() {
<div className="overflow-x-auto">
<table className="w-full" style={{ minWidth: '560px' }}>
<thead>
<tr className="border-b" style={{ borderColor: 'rgba(34,197,94,0.08)' }}>
<tr className="border-b border-green/8">
{['#', 'Team', 'WC', 'W', 'D', 'L', 'GF', 'GA', 'GD', 'Win%'].map((h, i) => (
<th key={h} className={`py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-[#2a5c35] ${i === 0 ? 'pl-4 pr-2 text-left w-8' : i === 1 ? 'px-2 text-left' : 'px-2 text-right'}`}>{h}</th>
<th key={h} className={`py-2 text-[9px] font-bold tracking-[0.1em] uppercase text-green-muted ${i === 0 ? 'pl-4 pr-2 text-left w-8' : i === 1 ? 'px-2 text-left' : 'px-2 text-right'}`}>{h}</th>
))}
</tr>
</thead>
<tbody>
{teams.slice(0, 40).map((t, i) => (
<tr key={t.id} className="border-t hover:bg-[rgba(34,197,94,0.03)]" style={{ borderColor: 'rgba(34,197,94,0.05)' }}>
<td className="pl-4 pr-2 py-2.5 text-[11px] text-[#2a5c35] font-bold">{i + 1}</td>
<tr key={t.id} className="border-t border-green/5 hover:bg-green/[3%]">
<td className="pl-4 pr-2 py-2.5 text-[11px] text-green-muted font-bold">{i + 1}</td>
<td className="px-2 py-2.5">
<Link href={`/teams/${t.slug}`} className="flex items-center gap-2">
<TeamFlag name={t.name} iso2={t.iso2} size="sm" />
<span className="text-sm text-[#dff5e8] whitespace-nowrap">{t.name}</span>
<span className="text-sm text-text whitespace-nowrap">{t.name}</span>
</Link>
</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.appearances}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.wins}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.draws}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.losses}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.goalsFor}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">{t.stats?.goalsAgainst}</td>
<td className="px-2 py-2.5 text-right text-sm text-[#4a7a55]">
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.appearances}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.wins}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.draws}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.losses}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.goalsFor}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">{t.stats?.goalsAgainst}</td>
<td className="px-2 py-2.5 text-right text-sm text-green-mid">
{(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0) >= 0
? `+${(t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)}`
: (t.stats?.goalsFor ?? 0) - (t.stats?.goalsAgainst ?? 0)}
</td>
<td className="px-2 pr-4 py-2.5 text-right text-[13px] font-bold text-[#22c55e]">{t.stats?.winPct}%</td>
<td className="px-2 pr-4 py-2.5 text-right text-[13px] font-bold text-green">{t.stats?.winPct}%</td>
</tr>
))}
</tbody>
+35 -37
View File
@@ -77,11 +77,11 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
const years = Object.keys(matchesByYear).map(Number).sort((a, b) => b - a)
if (loading && !teamData) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Loading team</div>
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Loading team</div>
}
if (!team) {
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Team not found.</div>
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Team not found.</div>
}
const s = team.stats
@@ -95,13 +95,13 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
<div className="flex items-center gap-6 flex-wrap">
<TeamFlag name={team.name} iso2={team.iso2} size="xl" />
<div>
<h1 className="font-['Bebas_Neue'] text-[56px] text-[#22c55e] leading-none">{team.name}</h1>
<h1 className="font-['Bebas_Neue'] text-[56px] text-green leading-none">{team.name}</h1>
<div className="flex gap-3 mt-2 flex-wrap">
{team.fifaCode && <span className="text-[11px] text-[#2a5c35] font-bold tracking-wider">{team.fifaCode}</span>}
{team.confederation && <span className="text-[11px] text-[#2a5c35]">{team.confederation}</span>}
{team.continent && <span className="text-[11px] text-[#2a5c35]">{team.continent}</span>}
{team.fifaCode && <span className="text-[11px] text-green-muted font-bold tracking-wider">{team.fifaCode}</span>}
{team.confederation && <span className="text-[11px] text-green-muted">{team.confederation}</span>}
{team.continent && <span className="text-[11px] text-green-muted">{team.continent}</span>}
{(s?.titles ?? 0) > 0 && (
<span className="inline-flex items-center gap-1 text-[11px] text-[#22c55e] font-bold">
<span className="inline-flex items-center gap-1 text-[11px] text-green font-bold">
{Array.from({ length: s?.titles ?? 0 }).map((_, i) => <TrophyIcon key={i} className="w-3.5 h-3.5" />)}
{s?.titles} title{(s?.titles ?? 0) !== 1 ? 's' : ''}
</span>
@@ -116,7 +116,7 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Stats grid */}
{s && (
<div className="mb-8">
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">World Cup Record</h2>
<h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">World Cup Record</h2>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-3">
{[
{ label: 'Appearances', value: s.appearances },
@@ -125,28 +125,28 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{ label: 'Goals For', value: s.goalsFor },
].map(item => (
<div key={item.label} className="glass-card rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{item.value}</div>
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-1.5">{item.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-green">{item.value}</div>
</div>
))}
</div>
<div className="glass-card rounded-xl">
<div className="grid px-4 py-2.5 text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase"
<div className="grid px-4 py-2.5 text-[9px] text-green-muted tracking-[0.1em] uppercase"
style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px' }}>
<span>Team</span><span className="text-center">W</span><span className="text-center">D</span>
<span className="text-center">L</span><span className="text-center">GF</span>
<span className="text-center">GA</span><span className="text-center">GD</span>
</div>
<div className="grid px-4 py-3 border-t items-center"
style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px', borderColor: 'rgba(34,197,94,0.06)' }}>
<div className="grid px-4 py-3 border-t border-green/[6%] items-center"
style={{ gridTemplateColumns: '1fr 44px 44px 44px 60px 60px 60px' }}>
<div className="flex items-center gap-2">
<TeamFlag name={team.name} iso2={team.iso2} size="sm" />
<span className="text-sm text-[#dff5e8]">{team.name}</span>
<span className="text-sm text-text">{team.name}</span>
</div>
{[s.wins, s.draws, s.losses, s.goalsFor, s.goalsAgainst].map((v, i) => (
<span key={i} className="text-center text-sm text-[#4a7a55]">{v}</span>
<span key={i} className="text-center text-sm text-green-mid">{v}</span>
))}
<span className="text-center text-sm text-[#4a7a55]">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span>
<span className="text-center text-sm text-green-mid">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span>
</div>
</div>
</div>
@@ -155,11 +155,11 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Tournament participations */}
{years.length > 0 && (
<div className="mb-8">
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Tournament Participations</h2>
<h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Tournament Participations</h2>
<div className="flex flex-wrap gap-2">
{years.map(year => (
<Link key={year} href={`/tournaments/${year}`}
className="font-['Bebas_Neue'] text-lg px-3 py-1 rounded-lg transition-colors text-[#6abf7a] bg-[rgba(4,18,8,0.78)] border border-[rgba(34,197,94,0.15)] hover:text-[#22c55e] hover:border-[rgba(34,197,94,0.4)] backdrop-blur-sm">
className="font-['Bebas_Neue'] text-lg px-3 py-1 rounded-lg transition-colors text-green-sec bg-bg/[78%] border border-border hover:text-green hover:border-green/40 backdrop-blur-sm">
{year}
</Link>
))}
@@ -170,14 +170,14 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
{/* Match history by year */}
{years.length > 0 && (
<div>
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Match History</h2>
<h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Match History</h2>
<div className="space-y-6">
{years.map(year => {
const yMatches = matchesByYear[year]
return (
<div key={year}>
<Link href={`/tournaments/${year}`}
className="inline-block font-['Bebas_Neue'] text-[22px] text-[#22c55e] mb-2 hover:opacity-70 transition-opacity">
className="inline-block font-['Bebas_Neue'] text-[22px] text-green mb-2 hover:opacity-70 transition-opacity">
{year}
</Link>
<div className="glass-card rounded-xl">
@@ -194,23 +194,22 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
const result = myScore != null && theirScore != null
? myScore > theirScore ? 'W' : myScore < theirScore ? 'L' : 'D'
: null
const resultColor = result === 'W' ? 'text-[#22c55e]' : result === 'L' ? 'text-[#ef4444]' : 'text-[#6abf7a]'
const resultColor = result === 'W' ? 'text-green' : result === 'L' ? 'text-red-500' : 'text-green-sec'
// Display the decisive score (ET score for AET matches, FT for normal, PSO for shootouts)
const displayScore = scoreP ? null : (scoreEt ?? ft)
return (
<Link key={m.id} href={`/tournaments/${m.year}#match-${m.id}`}>
<div className="flex items-center gap-3 px-3 sm:px-4 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] transition-colors"
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i % 2 === 0 ? undefined : 'rgba(34,197,94,0.01)' }}>
<div className={`flex items-center gap-3 px-3 sm:px-4 py-2.5 border-b hover:bg-green/[3%] transition-colors border-green/[6%] ${i % 2 !== 0 ? 'bg-green/[1%]' : ''}`}>
<span className={`text-[11px] font-bold w-4 flex-shrink-0 ${resultColor}`}>{result ?? ''}</span>
<TeamFlag name={opponent.name} iso2={opponent.iso2} size="sm" />
<div className="flex-1 min-w-0">
<div className="text-sm text-[#dff5e8] truncate">{opponent.name}</div>
<div className="text-[10px] text-[#2a5c35]">
<div className="text-sm text-text truncate">{opponent.name}</div>
<div className="text-[10px] text-green-muted">
{m.round}{m.group ? ` · ${m.group}` : ''}{m.date ? ` · ${formatDate(m.date)}` : ''}
</div>
</div>
<div className="text-right flex-shrink-0">
<div className="font-['Bebas_Neue'] text-lg text-[#22c55e] leading-none">
<div className="font-['Bebas_Neue'] text-lg text-green leading-none">
{scoreP
? `${isHome ? scoreP[0] : scoreP[1]}${isHome ? scoreP[1] : scoreP[0]}`
: displayScore
@@ -218,12 +217,12 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
: ''}
</div>
{scoreP && ft && (
<div className="text-[9px] text-[#2a5c35] leading-none">
<div className="text-[9px] text-green-muted leading-none">
{`${isHome ? ft[0] : ft[1]}${isHome ? ft[1] : ft[0]}`} a.e.t.
</div>
)}
{scoreEt && !scoreP && (
<div className="text-[9px] text-[#2a5c35] leading-none">a.e.t.</div>
<div className="text-[9px] text-green-muted leading-none">a.e.t.</div>
)}
</div>
</div>
@@ -243,23 +242,22 @@ export default function TeamPage({ params }: { params: Promise<{ slug: string }>
<div>
{teamScorers.length > 0 && (
<div>
<h2 className="text-[11px] text-[#2a5c35] font-bold tracking-[0.14em] uppercase mb-4">Top Scorers</h2>
<h2 className="text-[11px] text-green-muted font-bold tracking-[0.14em] uppercase mb-4">Top Scorers</h2>
<div className="glass-card">
{teamScorers.map((sc: { playerName: string; goals: number; penalties: number; tournaments: number }, i: number) => (
<Link key={sc.playerName} href={`/players/${encodeURIComponent(sc.playerName)}`}>
<div className="flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}>
<span className="text-[10px] text-[#2a5c35] w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className={`flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-green/[3%] cursor-pointer border-green/[6%] ${i === 0 ? 'bg-green/[4%]' : ''}`}>
<span className="text-[10px] text-green-muted w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className="flex-1 min-w-0">
<div className="text-[13px] font-semibold text-[#dff5e8] truncate">{sc.playerName}</div>
<div className="text-[10px] text-[#2a5c35]">
<div className="text-[13px] font-semibold text-text truncate">{sc.playerName}</div>
<div className="text-[10px] text-green-muted">
{sc.tournaments} WC{sc.tournaments !== 1 ? 's' : ''}{sc.penalties > 0 ? ` · ${sc.penalties}P` : ''}
</div>
</div>
<div className="w-10 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}>
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(sc.goals / maxScorer) * 100}%` }} />
<div className="w-10 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-green" style={{ width: `${(sc.goals / maxScorer) * 100}%` }} />
</div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{sc.goals}</span>
<span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">{sc.goals}</span>
</div>
</Link>
))}
+34 -36
View File
@@ -53,14 +53,14 @@ function GoalList({ match }: { match: MatchData }) {
<span key={i}>
{i > 0 && <span className="mx-0.5">,</span>}
<Link href={`/players/${encodeURIComponent(g.playerName)}`}
className="underline decoration-dotted underline-offset-2 hover:text-[#22c55e] hover:decoration-solid transition-colors">
className="underline decoration-dotted underline-offset-2 hover:text-green hover:decoration-solid transition-colors">
{g.playerName}
</Link>
{' '}{g.minute ?? ''}{g.minuteOffset ? `+${g.minuteOffset}` : ''}'{g.isPenalty ? ' (P)' : g.isOwnGoal ? ' (OG)' : ''}
</span>
)
return (
<div className="flex justify-between gap-4 px-4 pb-2 text-[10px] text-[#2a5c35]">
<div className="flex justify-between gap-4 px-4 pb-2 text-[10px] text-green-muted">
<div className="text-left">{t1Goals.map(renderGoal)}</div>
<div className="text-right">{t2Goals.map(renderGoal)}</div>
</div>
@@ -113,13 +113,13 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
if (loading && !data) {
return (
<div className="max-w-[1200px] mx-auto px-7 py-10">
<div className="h-24 w-48 rounded-xl animate-pulse mb-6" style={{ background: '#0a1810' }} />
<div className="text-[#2a5c35] text-sm">Loading {year} World Cup…</div>
<div className="h-24 w-48 rounded-xl animate-pulse mb-6 bg-card" />
<div className="text-green-muted text-sm">Loading {year} World Cup…</div>
</div>
)
}
if (!t) return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Tournament {year} not found.</div>
if (!t) return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Tournament {year} not found.</div>
return (
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
@@ -128,14 +128,14 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{liveMatches.length > 0 && <div className="mb-3"><LiveBadge label="Live Now" /></div>}
<div className="flex items-start justify-between flex-wrap gap-4">
<div>
<h1 className="font-['Bebas_Neue'] text-[64px] text-[#22c55e] leading-none">{year}</h1>
<p className="text-[#6abf7a] text-lg mt-1">{t.host}</p>
<h1 className="font-['Bebas_Neue'] text-[64px] text-green leading-none">{year}</h1>
<p className="text-green-sec text-lg mt-1">{t.host}</p>
</div>
{t.winner && (
<div className="text-center">
<TeamFlag name={t.winner} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-2xl text-[#dff5e8]">{t.winner}</div>
{t.runnerUp && <div className="text-xs text-[#2a5c35] mt-1">def. {t.runnerUp}</div>}
<div className="font-['Bebas_Neue'] text-2xl text-text">{t.winner}</div>
{t.runnerUp && <div className="text-xs text-green-muted mt-1">def. {t.runnerUp}</div>}
</div>
)}
</div>
@@ -147,8 +147,8 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{ label: 'Goals/Game', value: t.avgGoalsPerGame ? Number(t.avgGoalsPerGame).toFixed(2) : null },
].filter(s => s.value != null).map(s => (
<div key={s.label}>
<div className="text-[9px] text-[#2a5c35] tracking-[0.12em] uppercase">{s.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-[#22c55e]">{s.value}</div>
<div className="text-[9px] text-green-muted tracking-[0.12em] uppercase">{s.label}</div>
<div className="font-['Bebas_Neue'] text-3xl text-green">{s.value}</div>
</div>
))}
</div>
@@ -159,7 +159,7 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Live matches first */}
{liveMatches.length > 0 && (
<div className="mb-8">
<h2 className="font-['Bebas_Neue'] text-2xl text-[#4ade80] mb-4">LIVE</h2>
<h2 className="font-['Bebas_Neue'] text-2xl text-green-light mb-4">LIVE</h2>
<div className="flex flex-col gap-4">
{liveMatches.map(m => (
<div key={m.id} id={`match-${m.id}`}>
@@ -174,26 +174,25 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Group stage */}
{groupRounds.length > 0 && (
<div className="mb-8">
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] mb-5">Group Stage</h2>
<h2 className="font-['Bebas_Neue'] text-2xl text-green mb-5">Group Stage</h2>
{groupRounds.map(([groupName, rows]) => {
const sorted = [...rows].sort((a, b) => b.pts - a.pts || b.goalDiff - a.goalDiff)
const groupMatches = (byRound[groupName] ?? []).sort((a, b) => (a.date ?? '') < (b.date ?? '') ? -1 : 1)
return (
<div key={groupName} className="mb-8">
<h3 className="text-[13px] font-bold text-[#22c55e] tracking-wide uppercase mb-3">{groupName}</h3>
<h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{groupName}</h3>
{/* Standings mini */}
<div className="glass-card rounded-xl mb-3">
{sorted.map((s, i) => (
<Link key={s.team.id} href={`/teams/${s.team.slug}`}>
<div className="flex items-center gap-2 px-3 py-2 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.05)', background: i < 2 ? 'rgba(34,197,94,0.02)' : undefined }}>
<div className={`flex items-center gap-2 px-3 py-2 border-b hover:bg-green/[3%] cursor-pointer border-green/5 ${i < 2 ? 'bg-green/[2%]' : ''}`}>
<TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />
<span className="flex-1 text-[13px] text-[#6abf7a] truncate">{s.team.name}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.played}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.won}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.drawn}</span>
<span className="text-[11px] text-[#4a7a55] w-6 text-center">{s.lost}</span>
<span className="text-[11px] font-bold text-[#22c55e] w-6 text-center">{s.pts}</span>
<span className="flex-1 text-[13px] text-green-sec truncate">{s.team.name}</span>
<span className="text-[11px] text-green-mid w-6 text-center">{s.played}</span>
<span className="text-[11px] text-green-mid w-6 text-center">{s.won}</span>
<span className="text-[11px] text-green-mid w-6 text-center">{s.drawn}</span>
<span className="text-[11px] text-green-mid w-6 text-center">{s.lost}</span>
<span className="text-[11px] font-bold text-green w-6 text-center">{s.pts}</span>
</div>
</Link>
))}
@@ -216,10 +215,10 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Knockout rounds */}
{Object.keys(koByRound).length > 0 && (
<div>
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] mb-5">Knockout Stage</h2>
<h2 className="font-['Bebas_Neue'] text-2xl text-green mb-5">Knockout Stage</h2>
{Object.entries(koByRound).map(([round, roundMatches]) => (
<div key={round} className="mb-6">
<h3 className="text-[13px] font-bold text-[#22c55e] tracking-wide uppercase mb-3">{round}</h3>
<h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{round}</h3>
<div className="flex flex-col gap-3">
{roundMatches.map(m => (
<div key={m.id} id={`match-${m.id}`}>
@@ -237,22 +236,21 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{/* Sidebar: top scorers */}
<div>
<div className="sticky top-[76px]">
<h2 className="font-['Bebas_Neue'] text-xl text-[#22c55e] mb-4">TOP SCORERS</h2>
<h2 className="font-['Bebas_Neue'] text-xl text-green mb-4">TOP SCORERS</h2>
<div className="glass-card">
{t.topScorers?.map((s: { playerName: string; goals: number; penalties: number; team?: { name: string; iso2?: string | null; slug: string } | null }, i: number) => (
<Link key={s.playerName} href={`/players/${encodeURIComponent(s.playerName)}`}>
<div className="flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-[rgba(34,197,94,0.03)] cursor-pointer"
style={{ borderColor: 'rgba(34,197,94,0.06)', background: i === 0 ? 'rgba(34,197,94,0.04)' : undefined }}>
<span className="text-[10px] text-[#2a5c35] w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
<div className={`flex items-center gap-2.5 px-3.5 py-2.5 border-b hover:bg-green/[3%] cursor-pointer border-green/[6%] ${i === 0 ? 'bg-green/[4%]' : ''}`}>
<span className="text-[10px] text-green-muted w-4 text-right font-bold flex-shrink-0">{i + 1}</span>
{s.team && <TeamFlag name={s.team.name} iso2={s.team.iso2} size="sm" />}
<div className="flex-1 min-w-0">
<div className="text-[13px] font-semibold text-[#dff5e8] truncate">{s.playerName}</div>
{s.penalties > 0 && <div className="text-[9px] text-[#2a5c35]">{s.penalties} pen</div>}
<div className="text-[13px] font-semibold text-text truncate">{s.playerName}</div>
{s.penalties > 0 && <div className="text-[9px] text-green-muted">{s.penalties} pen</div>}
</div>
<div className="w-12 h-1 rounded-full flex-shrink-0" style={{ background: 'rgba(34,197,94,0.1)' }}>
<div className="h-full rounded-full bg-[#22c55e]" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
<div className="w-12 h-1 rounded-full flex-shrink-0 bg-green/10">
<div className="h-full rounded-full bg-green" style={{ width: `${(s.goals / maxScorer) * 100}%` }} />
</div>
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{s.goals}</span>
<span className="font-['Bebas_Neue'] text-xl text-green flex-shrink-0">{s.goals}</span>
</div>
</Link>
))}
@@ -260,15 +258,15 @@ export default function TournamentPage({ params }: { params: Promise<{ year: str
{t.thirdPlace && (
<div className="glass-card mt-4 rounded-xl p-4">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2">3rd Place</div>
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2">3rd Place</div>
<div className="flex items-center gap-2">
<TeamFlag name={t.thirdPlace} size="sm" />
<span className="text-sm text-[#6abf7a]">{t.thirdPlace}</span>
<span className="text-sm text-green-sec">{t.thirdPlace}</span>
</div>
{t.fourthPlace && (
<div className="flex items-center gap-2 mt-1.5">
<TeamFlag name={t.fourthPlace} size="sm" />
<span className="text-sm text-[#4a7a55]">{t.fourthPlace}</span>
<span className="text-sm text-green-mid">{t.fourthPlace}</span>
</div>
)}
</div>
+2 -2
View File
@@ -1,8 +1,8 @@
export function LiveBadge({ label = 'Live' }: { label?: string }) {
return (
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-[#4ade80] flex-shrink-0 animate-live" />
<span className="text-[11px] font-bold text-[#4ade80] tracking-[0.14em] uppercase">{label}</span>
<span className="w-2 h-2 rounded-full bg-green-light flex-shrink-0 animate-live" />
<span className="text-[11px] font-bold text-green-light tracking-[0.14em] uppercase">{label}</span>
</div>
)
}
+16 -16
View File
@@ -32,19 +32,19 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
if (compact) {
return (
<Link href={`/tournaments/${match.year}#match-${match.id}`} className="block">
<div className="glass-card rounded-xl p-3.5 hover:border-[rgba(34,197,94,0.22)] transition-colors">
<div className="text-[9px] text-[#2a5c35] tracking-[0.1em] uppercase mb-2.5">
<div className="glass-card rounded-xl p-3.5 hover:border-green/[22%] transition-colors">
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2.5">
{match.round}{match.group ? ` · ${match.group}` : ''} · {match.date ? formatDate(match.date) : ''}
</div>
<div className="flex items-center gap-2">
<div className="flex-1 flex items-center gap-2 overflow-hidden">
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
<span className={`text-sm font-medium truncate ${winner === 'home' ? 'text-[#dff5e8]' : 'text-[#4a7a55]'}`}>
<span className={`text-sm font-medium truncate ${winner === 'home' ? 'text-text' : 'text-green-mid'}`}>
{match.team1.name}
</span>
</div>
<div className="flex-shrink-0 min-w-[52px] text-center">
<div className="font-['Bebas_Neue'] text-xl text-[#22c55e]">
<div className="font-['Bebas_Neue'] text-xl text-green">
{hasScore
? match.scoreP
? `${match.scoreP[0]} ${match.scoreP[1]}`
@@ -54,23 +54,23 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
: match.isLive ? <LiveBadge label="•" /> : ''}
</div>
{match.scoreP && (
<div className="text-[8px] text-[#2a5c35] leading-none">
<div className="text-[8px] text-green-muted leading-none">
{ft![0]}{ft![1]} a.e.t.
</div>
)}
{match.scoreEt && !match.scoreP && (
<div className="text-[8px] text-[#2a5c35] leading-none">a.e.t.</div>
<div className="text-[8px] text-green-muted leading-none">a.e.t.</div>
)}
</div>
<div className="flex-1 flex items-center justify-end gap-2 overflow-hidden">
<span className={`text-sm font-medium truncate ${winner === 'away' ? 'text-[#dff5e8]' : 'text-[#4a7a55]'}`}>
<span className={`text-sm font-medium truncate ${winner === 'away' ? 'text-text' : 'text-green-mid'}`}>
{match.team2.name}
</span>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
</div>
</div>
{match.scoreEt && !match.scoreP && (
<div className="text-[9px] text-[#2a5c35] mt-1 text-center">a.e.t.</div>
<div className="text-[9px] text-green-muted mt-1 text-center">a.e.t.</div>
)}
</div>
</Link>
@@ -80,18 +80,18 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
const matchHref = `/tournaments/${match.year}#match-${match.id}`
return (
<div className="glass-card-hero rounded-2xl px-5 py-6 sm:px-9 sm:py-9 hover:border-[rgba(34,197,94,0.45)] transition-colors">
<div className="glass-card-hero rounded-2xl px-5 py-6 sm:px-9 sm:py-9 hover:border-green/45 transition-colors">
{match.isLive && <div className="mb-4"><LiveBadge label="Live Now" /></div>}
<div className="grid grid-cols-[1fr_auto_1fr] items-center gap-3 sm:gap-8">
<Link href={match.team1.slug ? `/teams/${match.team1.slug}` : matchHref}
className={`text-center block transition-colors hover:text-[#22c55e] ${winner === 'home' ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>
className={`text-center block transition-colors hover:text-green ${winner === 'home' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team1.name}
</div>
</Link>
<Link href={matchHref} className="text-center flex-shrink-0 block">
<div className="font-['Bebas_Neue'] text-[48px] sm:text-[76px] text-[#22c55e] leading-none hover:opacity-80 transition-opacity">
<div className="font-['Bebas_Neue'] text-[48px] sm:text-[76px] text-green leading-none hover:opacity-80 transition-opacity">
{hasScore
? match.scoreP
? `${match.scoreP[0]}${match.scoreP[1]}`
@@ -101,16 +101,16 @@ export function MatchCard({ match, compact = false }: { match: Match; compact?:
: '??'}
</div>
{match.scoreP && (
<div className="text-[10px] text-[#2a5c35] mt-0.5">{ft![0]}{ft![1]} a.e.t.</div>
<div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} a.e.t.</div>
)}
{match.scoreEt && !match.scoreP && (
<div className="text-[10px] text-[#2a5c35] mt-0.5">{ft![0]}{ft![1]} (a.e.t.)</div>
<div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} (a.e.t.)</div>
)}
<div className="text-[9px] text-[#2a5c35] tracking-[0.12em] uppercase mt-1.5">{match.round}</div>
<div className="text-[10px] text-[#1a3a22] mt-0.5">{match.date ? formatDate(match.date) : ''}</div>
<div className="text-[9px] text-green-muted tracking-[0.12em] uppercase mt-1.5">{match.round}</div>
<div className="text-[10px] text-green-dark mt-0.5">{match.date ? formatDate(match.date) : ''}</div>
</Link>
<Link href={match.team2.slug ? `/teams/${match.team2.slug}` : matchHref}
className={`text-center block transition-colors hover:text-[#22c55e] ${winner === 'away' ? 'text-[#dff5e8]' : 'text-[#6abf7a]'}`}>
className={`text-center block transition-colors hover:text-green ${winner === 'away' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team2.name}
+15 -18
View File
@@ -40,15 +40,15 @@ export function Nav() {
return (
<>
<nav
className="fixed top-0 left-0 right-0 z-50 h-[60px]"
style={{ background: 'rgba(4,13,8,0.97)', backdropFilter: 'blur(18px)', borderBottom: '1px solid rgba(34,197,94,0.18)' }}
className="fixed top-0 left-0 right-0 z-50 h-[60px] border-b border-green/[18%]"
style={{ background: 'rgba(4,13,8,0.97)', backdropFilter: 'blur(18px)' }}
>
<div className="max-w-[1200px] mx-auto px-7 h-full flex items-center">
{/* Logo */}
<Link href="/" className="flex items-center gap-2.5 flex-shrink-0 cursor-pointer select-none">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/favicon.svg" style={{ height: '36px', width: 'auto' }} alt="" />
<span className="font-['Bebas_Neue'] text-lg tracking-[3px] text-[#22c55e] whitespace-nowrap">WORLD CUP</span>
<span className="font-['Bebas_Neue'] text-lg tracking-[3px] text-green whitespace-nowrap">WORLD CUP</span>
</Link>
{/* Desktop links */}
@@ -56,7 +56,7 @@ export function Nav() {
{NAV_LINKS.map(({ href, label }) => (
<Link key={href} href={href}
className={`px-3.5 py-1.5 rounded-lg text-[13px] font-medium whitespace-nowrap transition-colors
${isActive(href) ? 'bg-[rgba(34,197,94,0.12)] text-[#22c55e]' : 'text-[#4a7a55] hover:text-[#6abf7a]'}`}>
${isActive(href) ? 'bg-green/[12%] text-green' : 'text-green-mid hover:text-green-sec'}`}>
{label}
</Link>
))}
@@ -67,10 +67,9 @@ export function Nav() {
<input
type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search…"
className="w-44 pl-8 pr-3.5 py-1.5 rounded-[20px] text-[13px] text-[#dff5e8] outline-none"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.18)' }}
className="w-44 pl-8 pr-3.5 py-1.5 rounded-[20px] text-[13px] text-text outline-none bg-green/[6%] border border-green/[18%]"
/>
<svg className="absolute left-2.5 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5">
<svg className="absolute left-2.5 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
</form>
@@ -78,13 +77,12 @@ export function Nav() {
{/* Hamburger */}
<button
onClick={() => setOpen(o => !o)}
className="ml-auto md:hidden flex flex-col justify-center items-center w-9 h-9 gap-[5px] rounded-lg transition-colors"
style={{ background: open ? 'rgba(34,197,94,0.1)' : 'transparent' }}
className={`ml-auto md:hidden flex flex-col justify-center items-center w-9 h-9 gap-[5px] rounded-lg transition-colors ${open ? 'bg-green/10' : ''}`}
aria-label="Menu"
>
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all origin-center ${open ? 'rotate-45 translate-y-[7px]' : ''}`} />
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all ${open ? 'opacity-0' : ''}`} />
<span className={`block w-5 h-[2px] bg-[#22c55e] rounded-full transition-all origin-center ${open ? '-rotate-45 -translate-y-[7px]' : ''}`} />
<span className={`block w-5 h-[2px] bg-green rounded-full transition-all origin-center ${open ? 'rotate-45 translate-y-[7px]' : ''}`} />
<span className={`block w-5 h-[2px] bg-green rounded-full transition-all ${open ? 'opacity-0' : ''}`} />
<span className={`block w-5 h-[2px] bg-green rounded-full transition-all origin-center ${open ? '-rotate-45 -translate-y-[7px]' : ''}`} />
</button>
</div>
</nav>
@@ -100,14 +98,14 @@ export function Nav() {
{/* Mobile menu panel */}
<div
className={`fixed left-0 right-0 z-40 md:hidden transition-all duration-200 ${open ? 'top-[60px] opacity-100' : 'top-[48px] opacity-0 pointer-events-none'}`}
style={{ background: 'rgba(4,13,8,0.98)', borderBottom: '1px solid rgba(34,197,94,0.18)' }}
className={`fixed left-0 right-0 z-40 md:hidden transition-all duration-200 border-b border-green/[18%] ${open ? 'top-[60px] opacity-100' : 'top-[48px] opacity-0 pointer-events-none'}`}
style={{ background: 'rgba(4,13,8,0.98)' }}
>
<div className="px-5 py-4 flex flex-col gap-1">
{NAV_LINKS.map(({ href, label }) => (
<Link key={href} href={href}
className={`px-4 py-3 rounded-xl text-[15px] font-medium transition-colors
${isActive(href) ? 'bg-[rgba(34,197,94,0.12)] text-[#22c55e]' : 'text-[#6abf7a] hover:bg-[rgba(34,197,94,0.06)]'}`}>
${isActive(href) ? 'bg-green/[12%] text-green' : 'text-green-sec hover:bg-green/[6%]'}`}>
{label}
</Link>
))}
@@ -116,10 +114,9 @@ export function Nav() {
<input
type="text" value={q} onChange={e => setQ(e.target.value)}
placeholder="Search players, teams, tournaments…"
className="w-full pl-9 pr-4 py-3 rounded-xl text-[14px] text-[#dff5e8] outline-none"
style={{ background: 'rgba(34,197,94,0.06)', border: '1px solid rgba(34,197,94,0.18)' }}
className="w-full pl-9 pr-4 py-3 rounded-xl text-[14px] text-text outline-none bg-green/[6%] border border-green/[18%]"
/>
<svg className="absolute left-3 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#dff5e8" strokeWidth="2.5">
<svg className="absolute left-3 top-1/2 -translate-y-1/2 opacity-30 pointer-events-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
</form>
+1 -1
View File
@@ -31,7 +31,7 @@ export function TeamFlag({ name, iso2, size = 'md', className = '' }: Props) {
>
<span style={{
fontSize: '0.38em',
color: '#6abf7a',
color: 'var(--color-green-sec)',
fontFamily: 'Space Grotesk, sans-serif',
fontWeight: 700,
letterSpacing: '0.04em',

Some files were not shown because too many files have changed in this diff Show More