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:
+24
-27
@@ -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 · 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>
|
||||
|
||||
Reference in New Issue
Block a user