Compare commits
18 Commits
f885e4312c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ebe4613ce | |||
| c721062560 | |||
| 1fc9c59367 | |||
| 7fb54683e4 | |||
| a494c80a76 | |||
| 2bd32daae1 | |||
| 71e7e47aca | |||
| 76425e7f76 | |||
| 015f6c2ef3 | |||
| 47eb5092e9 | |||
| 7e4bf2d07c | |||
| d37ebe201e | |||
| 9ce2a4e27c | |||
| b141356247 | |||
| 187ee2e312 | |||
| 42063cdfda | |||
| 61c3c3f6cf | |||
| b832b62f5e |
+1
-1
@@ -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"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# World Cup
|
||||
|
||||
A full-stack World Cup statistics web app covering every tournament from 1930 to 2026. Built with Next.js 16, TailwindCSS 4, GraphQL, and PostgreSQL. Data is sourced from [openfootball/worldcup.json](https://github.com/openfootball/worldcup.json) and synced on a schedule so live 2026 results appear within minutes.
|
||||
A full-stack World Cup statistics web app covering every tournament from 1930 to 2026. Built with Next.js 16, TailwindCSS 4, GraphQL, and PostgreSQL. Historical data is scraped from English Wikipedia and committed to the repo; live 2026 results are synced from Wikipedia on a schedule so scores appear within minutes of the final whistle.
|
||||
|
||||
## Features
|
||||
|
||||
- **Live 2026 matches** — detected automatically when today's date matches a scheduled fixture; Apollo polls every 60 seconds for score updates
|
||||
- **All-time statistics** — goals, hat-tricks, biggest wins, highest-scoring games, penalty stats, goals-by-minute heatmap, confederation performance, title counts
|
||||
- **Group standings** — computed from match results for every tournament, pre-seeded from openfootball's standings files where available
|
||||
- **Deep-linked pages** — every tournament, team, and player has a permanent URL (`/tournaments/1966`, `/teams/brazil`, `/players/Pelé`)
|
||||
- **Group standings** — computed from match results for every tournament, with 0-row entries seeded so all groups appear even before any matches are played
|
||||
- **Deep-linked pages** — every tournament, team, and player has a permanent URL (`/tournaments/1966`, `/teams/brazil`, `/players/Pelé`) with server-side metadata for SEO
|
||||
- **Full-text search** — across teams, tournaments, and players
|
||||
- **Squad data** — 26-man rosters for 2026 with position, shirt number, and date of birth
|
||||
- **Qualification playoffs** — 2026 inter-confederation playoff results stored separately
|
||||
@@ -19,9 +19,9 @@ A full-stack World Cup statistics web app covering every tournament from 1930 to
|
||||
| Route | Content |
|
||||
|---|---|
|
||||
| `/` | Home: live matches, stat pills, latest result, upcoming fixtures, Golden Boot race |
|
||||
| `/groups` | All 12 group tables for 2026 (P/W/D/L/GD/Pts) |
|
||||
| `/groups` | All 12 group tables for 2026 (P/W/D/L/GD/Pts) with results and upcoming fixtures |
|
||||
| `/stats` | Historical stats: goals chart, top scorers, hat-tricks, biggest wins, goals by minute, ET/shootout stats, confederation stats |
|
||||
| `/history` | All 23 tournament cards newest-first, each with host, winner, top scorer |
|
||||
| `/history` | All 24 tournament cards newest-first, each with host, winner, top scorer |
|
||||
| `/search?q=…` | Full-text search across teams, players, tournaments |
|
||||
| `/tournaments/[year]` | Tournament detail: group stage with standings + matches, knockout rounds, scorer sidebar |
|
||||
| `/teams/[slug]` | Team profile: all-time record, top scorers, WC appearances |
|
||||
@@ -41,26 +41,69 @@ A full-stack World Cup statistics web app covering every tournament from 1930 to
|
||||
| Fonts | Bebas Neue + Space Grotesk (Google Fonts) |
|
||||
| Container | Docker multi-stage build, Traefik-compatible |
|
||||
|
||||
## Data sources
|
||||
## Data pipeline
|
||||
|
||||
All data is fetched from the [openfootball/worldcup.json](https://github.com/openfootball/worldcup.json) GitHub repository via raw URLs. The sync script fetches up to seven files per tournament year depending on availability:
|
||||
Data flows through three scripts that are run at different times and for different purposes.
|
||||
|
||||
| File | Content | Years available |
|
||||
|---|---|---|
|
||||
| `worldcup.json` | Matches, scores (FT/HT/ET/P), goal-scorer events | All (1930–2026) |
|
||||
| `worldcup.teams.json` | Team details, FIFA codes, confederation | 2014–2026 |
|
||||
| `worldcup.stadiums.json` | Stadium name, city, capacity, coordinates | 2014–2026 |
|
||||
| `worldcup.groups.json` | Group compositions | 2014–2026 |
|
||||
| `worldcup.standings.json` | Pre-computed group standings | 2014, 2018 |
|
||||
| `worldcup.squads.json` | 26-man player rosters | 2026 |
|
||||
| `worldcup.quali_playoffs.json` | Inter-confederation playoff results | 2026 |
|
||||
### 1. Scrape — one-time developer task
|
||||
|
||||
**Note:** Individual goal-scorer records are only available from openfootball for 1930–1950, 1990, 2006, and 2014–2026. Match scores (used for standings, biggest wins, etc.) are complete for all years.
|
||||
```bash
|
||||
pnpm scrape # all years (1930–2022), matches + squads
|
||||
pnpm scrape 2002 # single year
|
||||
pnpm scrape 2002 --matches # matches, meta, stadiums, groups only
|
||||
pnpm scrape 2002 --squads # squads only
|
||||
```
|
||||
|
||||
Fetches structured match data from English Wikipedia using the [MediaWiki parse API](https://en.wikipedia.org/w/api.php) and writes JSON files to `data/{year}/`. These files are **committed to git** so the production build never needs to hit Wikipedia for historical data.
|
||||
|
||||
Each year produces up to five files:
|
||||
|
||||
| File | Content |
|
||||
|---|---|
|
||||
| `worldcup.json` | Matches with scores (FT/HT/ET/P) and goal-scorer events |
|
||||
| `worldcup.meta.json` | Tournament metadata: host, winner, runner-up, team count |
|
||||
| `worldcup.stadiums.json` | Stadium names and cities |
|
||||
| `worldcup.groups.json` | Group compositions (teams per group) |
|
||||
| `worldcup.squads.json` | Player rosters (where available on Wikipedia) |
|
||||
|
||||
The scraper has built-in rate-limit handling: it detects Wikipedia's plain-text `"You are making too many requests"` response, waits 30 seconds, and retries with exponential back-off (up to 6 attempts, 15 s × attempt delay between retries). Group sub-pages are fetched with a 3-second delay between requests.
|
||||
|
||||
### 2. Seed — initial database population
|
||||
|
||||
```bash
|
||||
DATABASE_URL="postgres://wc:wc@localhost:5432/worldcup" pnpm seed
|
||||
DATABASE_URL="..." pnpm seed --force # drop and re-seed from scratch
|
||||
```
|
||||
|
||||
Reads the committed `data/{year}/` JSON files and loads them into the database. Also creates all tables (if they do not exist). Intended for first-time setup and for re-seeding after schema changes. Covers **1930–2022 only** — 2026 data is handled by sync.
|
||||
|
||||
Seed is **idempotent** and skips silently if data is already present (unless `--force` is passed).
|
||||
|
||||
### 3. Sync — scheduled live updates (2026 only)
|
||||
|
||||
```bash
|
||||
DATABASE_URL="..." pnpm sync # normal run
|
||||
DATABASE_URL="..." pnpm sync --force # clear and re-fetch all 2026 data
|
||||
```
|
||||
|
||||
Fetches the current state of the 2026 Wikipedia pages and upserts everything into the database. Historical years (1930–2022) are not touched — they come from the committed JSON files via seed.
|
||||
|
||||
What sync does on each run:
|
||||
|
||||
1. Fetches `2026_FIFA_World_Cup` via the MediaWiki API
|
||||
2. Determines which groups are fully complete (all matches have FT scores) and skips their sub-pages to save requests
|
||||
3. Upserts matches, scores, and goal events
|
||||
4. Fetches `2026_FIFA_World_Cup_squads` and upserts squad rosters
|
||||
5. Recomputes group standings from match results
|
||||
6. Seeds 0-row standing entries for groups with no played matches yet (so all groups appear in the UI)
|
||||
7. Updates tournament aggregates (total goals, matches played, avg goals/game)
|
||||
|
||||
Sync is designed to run on a **10-minute cron** in production. Each run is safe to repeat — all writes use `ON CONFLICT DO UPDATE`.
|
||||
|
||||
## Database schema
|
||||
|
||||
```
|
||||
tournaments year PK, host, winner, runner_up, third, fourth,
|
||||
tournaments year PK, host, winner, runner_up, third_place, fourth_place,
|
||||
teams_count, matches_count, total_goals, avg_goals_per_game
|
||||
|
||||
teams id, name UNIQUE, iso2, fifa_code, continent, confederation
|
||||
@@ -100,10 +143,13 @@ pnpm install
|
||||
# 2. Start the database
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
|
||||
# 3. Seed all 23 tournaments
|
||||
# 3. Seed historical data (1930–2022) from committed JSON files
|
||||
DATABASE_URL="postgres://wc:wc@localhost:5432/worldcup" pnpm seed
|
||||
|
||||
# 4. Sync 2026 data from Wikipedia
|
||||
DATABASE_URL="postgres://wc:wc@localhost:5432/worldcup" pnpm sync
|
||||
|
||||
# 4. Start the dev server
|
||||
# 5. Start the dev server
|
||||
DATABASE_URL="postgres://wc:wc@localhost:5432/worldcup" pnpm dev
|
||||
```
|
||||
|
||||
@@ -111,15 +157,25 @@ Open [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
To stop the database: `docker compose -f docker-compose.dev.yml down`
|
||||
|
||||
If you need to re-scrape historical data (e.g. after a Wikipedia article correction):
|
||||
|
||||
```bash
|
||||
pnpm scrape 2002 # re-scrape a single year
|
||||
git add data/2002/ && git commit -m "chore: refresh 2002 scraped data"
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|---|---|---|
|
||||
| `DATABASE_URL` | Yes | PostgreSQL connection string |
|
||||
| `NEXT_PUBLIC_SITE_URL` | Production | Public base URL, e.g. `https://worldcup.example.com` — used for sitemap and OG metadata |
|
||||
| `DB_PASSWORD` | Production | Password for the `wc` DB user (used by docker-compose.yml) |
|
||||
| `TRAEFIK_ENABLED` | Production | Set to `true` to activate Traefik router labels |
|
||||
| `TRAEFIK_HOST` | Production | Public hostname, e.g. `worldcup.example.com` |
|
||||
| `NETWORK_NAME` | Production | Name of the external Docker network Traefik is attached to |
|
||||
| `UMAMI_ID` | Optional | Umami analytics site ID |
|
||||
| `UMAMI_SRC` | Optional | Umami analytics script URL |
|
||||
|
||||
Copy `.env.example` to `.env` and fill in the values before deploying.
|
||||
|
||||
@@ -134,6 +190,7 @@ In Coolify's environment variable editor set:
|
||||
```
|
||||
DB_PASSWORD=<strong-random-password>
|
||||
DATABASE_URL=postgres://wc:<DB_PASSWORD>@db:5432/worldcup
|
||||
NEXT_PUBLIC_SITE_URL=https://worldcup.yourdomain.com
|
||||
TRAEFIK_ENABLED=true
|
||||
TRAEFIK_HOST=worldcup.yourdomain.com
|
||||
NETWORK_NAME=<your-traefik-network-name>
|
||||
@@ -143,12 +200,14 @@ NETWORK_NAME=<your-traefik-network-name>
|
||||
|
||||
Coolify builds the Docker image via `docker compose up` and attaches the container to the Traefik network automatically. TLS certificates are issued by the `resolver` cert resolver configured in Traefik.
|
||||
|
||||
### 3. Initial data sync
|
||||
### 3. Initial data load
|
||||
|
||||
After the first deployment run the sync once manually in Coolify's terminal:
|
||||
After the first deployment, seed historical data and then sync 2026:
|
||||
|
||||
```bash
|
||||
docker compose exec app pnpm sync
|
||||
# In Coolify's terminal for the app container:
|
||||
pnpm seed # loads 1930–2022 from committed JSON files
|
||||
pnpm sync # fetches 2026 from Wikipedia
|
||||
```
|
||||
|
||||
### 4. Scheduled sync (live updates)
|
||||
@@ -161,34 +220,29 @@ In Coolify → your service → **Scheduled Tasks**, add:
|
||||
| Schedule | `*/10 * * * *` |
|
||||
| Container | `app` |
|
||||
|
||||
This re-syncs from openfootball every 10 minutes. During the 2026 group stage new match results appear within 10 minutes of the final whistle.
|
||||
|
||||
## Running the sync manually
|
||||
|
||||
```bash
|
||||
# From host (dev)
|
||||
DATABASE_URL="postgres://wc:wc@localhost:5432/worldcup" pnpm sync
|
||||
|
||||
# Inside the app container (production)
|
||||
docker compose exec app pnpm sync
|
||||
```
|
||||
|
||||
The sync is fully idempotent — safe to run repeatedly. It upserts every record and recomputes tournament aggregates at the end of each year.
|
||||
This re-syncs 2026 from Wikipedia every 10 minutes. New match results appear within 10 minutes of the final whistle.
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
worldcup/
|
||||
├── app/
|
||||
│ ├── layout.tsx # Root layout: nav, fonts, Apollo provider
|
||||
│ ├── page.tsx # Home page
|
||||
│ ├── groups/page.tsx # 2026 group standings
|
||||
│ ├── stats/page.tsx # All-time statistics
|
||||
│ ├── history/page.tsx # Tournament history cards
|
||||
│ ├── search/page.tsx # Full-text search
|
||||
│ ├── tournaments/[year]/page.tsx # Tournament detail
|
||||
│ ├── teams/[slug]/page.tsx # Team profile
|
||||
│ ├── players/[name]/page.tsx # Player profile
|
||||
│ ├── layout.tsx # Root layout: nav, fonts, Apollo provider, global metadata
|
||||
│ ├── robots.ts # robots.txt (Next.js convention)
|
||||
│ ├── sitemap.ts # sitemap.xml — dynamic, rendered at request time
|
||||
│ ├── page.tsx # Home — server wrapper (exports metadata)
|
||||
│ ├── client.tsx # Home — Apollo/interactive client component
|
||||
│ ├── groups/
|
||||
│ │ ├── page.tsx # Groups — server wrapper
|
||||
│ │ └── client.tsx # Groups — client component
|
||||
│ ├── stats/page.tsx + client.tsx
|
||||
│ ├── history/page.tsx + client.tsx
|
||||
│ ├── search/page.tsx + client.tsx
|
||||
│ ├── tournaments/[year]/
|
||||
│ │ ├── page.tsx # generateMetadata fetches tournament from DB
|
||||
│ │ └── client.tsx # Tournament detail, group standings, bracket
|
||||
│ ├── teams/[slug]/page.tsx + client.tsx
|
||||
│ ├── players/[name]/page.tsx + client.tsx
|
||||
│ └── api/graphql/route.ts # GraphQL Yoga endpoint
|
||||
├── components/
|
||||
│ ├── apollo-provider.tsx # Apollo Client provider wrapper
|
||||
@@ -205,9 +259,20 @@ worldcup/
|
||||
│ │ ├── resolvers/index.ts # All resolvers
|
||||
│ │ ├── hooks.ts # Apollo v4 useQuery wrapper
|
||||
│ │ └── client.ts # Apollo Client factory
|
||||
│ ├── wiki-scraper.ts # Wikipedia HTML parser (cheerio), rate-limit retry
|
||||
│ └── iso-codes.ts # Team name → ISO2 country code map
|
||||
├── scripts/
|
||||
│ └── sync.ts # Data sync script (all years, idempotent)
|
||||
│ ├── scrape-wikipedia.ts # Developer-only: scrape Wikipedia → data/{year}/
|
||||
│ ├── seed.ts # Initial DB load from data/{year}/ JSON files
|
||||
│ └── sync.ts # Scheduled: sync 2026 live data from Wikipedia
|
||||
├── data/
|
||||
│ ├── 1930/ … 2022/ # Committed Wikipedia scrape output (per-year JSON)
|
||||
│ └── {year}/
|
||||
│ ├── worldcup.json # Matches + goals
|
||||
│ ├── worldcup.meta.json # Tournament metadata
|
||||
│ ├── worldcup.stadiums.json # Stadiums
|
||||
│ ├── worldcup.groups.json # Group compositions
|
||||
│ └── worldcup.squads.json # Squad rosters (where available)
|
||||
├── docker-compose.yml # Production (Traefik + external network)
|
||||
├── docker-compose.dev.yml # Local dev (DB only, port 5432 exposed)
|
||||
├── Dockerfile # Multi-stage pnpm build
|
||||
@@ -219,15 +284,21 @@ worldcup/
|
||||
|
||||
## Architecture notes
|
||||
|
||||
**Live match detection** — A match is considered live when its date equals today and the current time is within 5 minutes before kick-off to 125 minutes after. Time zones are stripped; all times are treated as local tournament time. Apollo's `pollInterval: 60_000` re-queries `liveMatches` every minute.
|
||||
**Live match detection** — A match is considered live when its date equals today and the current time falls within 5 minutes before kick-off to 125 minutes after. Kick-off times are stored as `"HH:MM UTC±N"` strings; the resolver computes the UTC timestamp at query time using PostgreSQL interval arithmetic. Apollo's `pollInterval: 60_000` re-queries `liveMatches` and `recentMatches` every minute.
|
||||
|
||||
**UTC kickoff ordering** — Both `upcomingMatches` (ascending) and `recentMatches` (descending) sort by computed UTC kickoff time using a `CASE` expression that parses the `time_local` string and subtracts the UTC offset as an interval. This ensures correct ordering across time zones — a match starting later in a westward timezone is not incorrectly ranked ahead of an earlier match with a higher database ID.
|
||||
|
||||
**Server/client split** — All pages use a server wrapper `page.tsx` that exports `metadata` (or `generateMetadata`) and a `client.tsx` that contains the Apollo query and interactive rendering. This lets Next.js generate accurate `<title>`, OpenGraph, and Twitter card tags for each route without requiring server-side data fetching in client components.
|
||||
|
||||
**`NEXT_PUBLIC_SITE_URL`** — The public hostname is read from this environment variable in `sitemap.ts`, `robots.ts`, and `layout.tsx` (`metadataBase`). All per-page `openGraph.url` values use relative paths (`/groups`, `/tournaments/2026`, etc.) which Next.js resolves against `metadataBase` automatically. The sitemap is marked `export const dynamic = 'force-dynamic'` so it runs at request time when the database is reachable, not at build time.
|
||||
|
||||
**Apollo Client v4** — This project uses Apollo Client 4 which moved hooks to `@apollo/client/react` and core utilities to `@apollo/client/core`. A thin wrapper in `lib/graphql/hooks.ts` re-exports `useQuery` typed as `Record<string, any>` to avoid the v4 `TData = {}` default breaking all field accesses.
|
||||
|
||||
**Standalone Docker output** — `next.config.ts` sets `output: 'standalone'` which produces a self-contained `server.js`. The `scripts/` and `lib/` directories are copied separately into the runner stage so `pnpm sync` works inside the container without needing a full Node/TypeScript toolchain reinstall.
|
||||
**Standalone Docker output** — `next.config.ts` sets `output: 'standalone'` which produces a self-contained `server.js`. The `scripts/`, `lib/`, and `data/` directories are copied separately into the runner stage so `pnpm seed` and `pnpm sync` work inside the container without needing a full Node/TypeScript toolchain reinstall.
|
||||
|
||||
**Group standings** — Pre-computed standings from openfootball are stored directly. For all other years (and 2026 during the tournament) standings are computed live from match results via a SQL `GROUP BY` query in the `groupStandings` resolver.
|
||||
**Group standings** — Standings are computed live from match results via a SQL `GROUP BY` query in the `groupStandings` resolver. After each sync, 0-row standing entries are inserted for all teams in all 2026 groups, ensuring every group appears in the UI even before its first match is played.
|
||||
|
||||
**Total goals** — Tournament goal counts are derived from match score totals (`score_ft_home + score_ft_away`), not from the goals table. This ensures correct numbers for all years, including those where individual scorer records are not available in the openfootball dataset.
|
||||
**Wikipedia scraper rate limits** — The MediaWiki API occasionally returns a plain-text `"You are making too many requests to the API"` response instead of JSON. The scraper detects this by reading the response as text first, then parses JSON only if the body does not start with that phrase. On rate-limit (or HTTP 429), it waits 30 seconds before retrying. Retries use exponential back-off: 15 s × attempt number, up to 6 attempts per page.
|
||||
|
||||
## GraphQL API
|
||||
|
||||
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { LiveBadge } from '@/components/live-badge'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
|
||||
const HOME_QUERY = gql`
|
||||
query Home {
|
||||
tournamentStats { totalTournaments totalMatches totalGoals avgGoalsPerGame }
|
||||
liveMatches {
|
||||
id year round group date time isLive scoreFt scoreEt scoreP isQualiPlayoff
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
recentMatches(limit: 9) {
|
||||
id year round group date time isLive isQualiPlayoff scoreFt scoreEt scoreP
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
upcomingMatches(limit: 9) {
|
||||
id year round group date time isLive isQualiPlayoff scoreFt
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
topScorers(year: 2026, limit: 8) {
|
||||
playerName goals penalties ownGoals
|
||||
team { name iso2 }
|
||||
}
|
||||
tournament(year: 2026) { year totalGoals matchesCount avgGoalsPerGame }
|
||||
}
|
||||
`
|
||||
|
||||
function SectionHeader({ label }: { label: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-2.5 mb-4">
|
||||
<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 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>
|
||||
)
|
||||
}
|
||||
|
||||
interface UpcomingMatch {
|
||||
id: number; year: number; time?: string | null; date?: string | null
|
||||
team1: { name: string; iso2?: string | null }
|
||||
team2: { name: string; iso2?: string | null }
|
||||
}
|
||||
|
||||
function formatKickoff(date: string | null | undefined, time: string | null | undefined): string {
|
||||
if (!date) return ''
|
||||
const today = new Date()
|
||||
const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1)
|
||||
|
||||
if (time) {
|
||||
const m = time.match(/^(\d{2}):(\d{2})(?:\s+UTC([+-]\d+(?:\.\d+)?))?/)
|
||||
if (m) {
|
||||
const [y, mo, d] = date.split('-').map(Number)
|
||||
const h = parseInt(m[1]), min = parseInt(m[2])
|
||||
const offsetH = m[3] ? parseFloat(m[3]) : 0
|
||||
// Compute UTC kickoff, then let the browser render in its local timezone
|
||||
const local = new Date(Date.UTC(y, mo - 1, d, h - offsetH, min))
|
||||
const isToday = local.toDateString() === today.toDateString()
|
||||
const isTomorrow = local.toDateString() === tomorrow.toDateString()
|
||||
const dayLabel = isToday ? 'Today' : isTomorrow ? 'Tomorrow'
|
||||
: local.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })
|
||||
const localTime = local.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
|
||||
return `${dayLabel} · ${localTime}`
|
||||
}
|
||||
}
|
||||
|
||||
// No time — fall back to venue date label only
|
||||
const matchDate = new Date(date + 'T00:00:00')
|
||||
const isToday = matchDate.toDateString() === today.toDateString()
|
||||
const isTomorrow = matchDate.toDateString() === tomorrow.toDateString()
|
||||
return isToday ? 'Today' : isTomorrow ? 'Tomorrow'
|
||||
: matchDate.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })
|
||||
}
|
||||
|
||||
function UpcomingFixture({ match }: { match: UpcomingMatch }) {
|
||||
const label = formatKickoff(match.date, match.time)
|
||||
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-green/20 transition-colors cursor-pointer">
|
||||
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
|
||||
<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" />
|
||||
{label && <div className="text-[11px] text-green-muted whitespace-nowrap ml-1">{label}</div>}
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
interface ScorerEntry {
|
||||
playerName: string; goals: number; penalties: number
|
||||
team?: { name: string; iso2?: string | null } | null
|
||||
}
|
||||
|
||||
interface MatchData {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; time?: string | null; isLive: boolean; isQualiPlayoff: boolean
|
||||
scoreFt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { name: string; iso2?: string | null; slug?: string | null }
|
||||
team2: { name: string; iso2?: string | null; slug?: string | null }
|
||||
}
|
||||
|
||||
export function HomeClient() {
|
||||
const { data, loading } = useQuery(HOME_QUERY, { pollInterval: 60_000 })
|
||||
|
||||
|
||||
const stats = data?.tournamentStats
|
||||
const live: MatchData[] = data?.liveMatches ?? []
|
||||
const recent: MatchData[] = data?.recentMatches ?? []
|
||||
const upcoming: UpcomingMatch[] = data?.upcomingMatches ?? []
|
||||
const scorers: ScorerEntry[] = data?.topScorers ?? []
|
||||
const wc2026 = data?.tournament
|
||||
|
||||
const maxGoals = Math.max(...scorers.map(s => s.goals), 1)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* ── Hero ── */}
|
||||
<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%)',
|
||||
padding: '52px 0 44px',
|
||||
}}>
|
||||
<div className="max-w-[1200px] mx-auto px-7">
|
||||
<div className="mb-4">
|
||||
{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-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-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]">
|
||||
{stats ? <>
|
||||
<StatPill label="Tournaments" value={stats.totalTournaments} />
|
||||
<StatPill label="Matches" value={stats.totalMatches} />
|
||||
<StatPill label="Goals" value={stats.totalGoals} />
|
||||
<StatPill label="Goals/Game" value={stats.avgGoalsPerGame?.toFixed(2) ?? '–'} />
|
||||
{wc2026 && <>
|
||||
<StatPill label="2026 Goals" value={wc2026.totalGoals ?? 0} />
|
||||
<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 bg-green/[4%]" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-[1200px] mx-auto px-7">
|
||||
{/* Live matches */}
|
||||
{live.length > 0 && (
|
||||
<div className="pt-9">
|
||||
<SectionHeader label="Live Now" />
|
||||
<div className="grid gap-4">
|
||||
{live.map(m => <MatchCard key={m.id} match={m} />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Latest result */}
|
||||
{recent.length > 0 && (
|
||||
<div className="pt-9">
|
||||
<SectionHeader label="Latest Result" />
|
||||
<MatchCard match={recent[0]} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recent grid */}
|
||||
{recent.length > 1 && (
|
||||
<div className="pt-8">
|
||||
<SectionHeader label="Recent Results" />
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(290px,1fr))] gap-2.5">
|
||||
{recent.slice(1).map(m => <MatchCard key={m.id} match={m} compact />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Upcoming */}
|
||||
{upcoming.length > 0 && (
|
||||
<div className="pt-8">
|
||||
<SectionHeader label="Upcoming Fixtures" />
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-2">
|
||||
{upcoming.map(m => <UpcomingFixture key={m.id} match={m} />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Golden Boot 2026 */}
|
||||
{scorers.length > 0 && (
|
||||
<div className="pt-8 pb-16">
|
||||
<SectionHeader label="2026 Golden Boot Race" />
|
||||
<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 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-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 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-green min-w-[24px] text-right flex-shrink-0">{s.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<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-green-muted text-sm">Loading live World Cup data…</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
|
+6
-5
@@ -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); }
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
|
||||
const GROUPS_QUERY = gql`
|
||||
query Groups {
|
||||
groupStandings(year: 2026) {
|
||||
groupName pos played won drawn lost goalsFor goalsAgainst goalDiff pts
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
matches(year: 2026, isQuali: false) {
|
||||
id group date time isLive scoreFt
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Standing {
|
||||
groupName: string; pos?: number | null
|
||||
played: number; won: number; drawn: number; lost: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; pts: number
|
||||
team: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
}
|
||||
|
||||
interface MatchRow {
|
||||
id: number; group?: string | null; date?: string | null; time?: string | null
|
||||
isLive: boolean; scoreFt?: number[] | null
|
||||
team1: { name: string; iso2?: string | null; slug: string }
|
||||
team2: { name: string; iso2?: string | null; slug: string }
|
||||
}
|
||||
|
||||
function utcKickoff(date: string, time: string): number {
|
||||
const m = time.match(/^(\d{2}):(\d{2})(?:\s+UTC([+-]\d+(?:\.\d+)?))?/)
|
||||
if (!m) return new Date(date).getTime()
|
||||
const [y, mo, d] = date.split('-').map(Number)
|
||||
const offsetH = m[3] ? parseFloat(m[3]) : 0
|
||||
return Date.UTC(y, mo - 1, d, parseInt(m[1]) - offsetH, parseInt(m[2]))
|
||||
}
|
||||
|
||||
function formatKickoff(date: string, time: string | null | undefined): string {
|
||||
if (!time) return new Date(date + 'T00:00:00').toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })
|
||||
const ms = utcKickoff(date, time)
|
||||
const local = new Date(ms)
|
||||
const today = new Date()
|
||||
const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1)
|
||||
const isToday = local.toDateString() === today.toDateString()
|
||||
const isTomorrow = local.toDateString() === tomorrow.toDateString()
|
||||
const day = isToday ? 'Today' : isTomorrow ? 'Tomorrow'
|
||||
: local.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })
|
||||
return `${day} · ${local.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })}`
|
||||
}
|
||||
|
||||
export function GroupsClient() {
|
||||
const { data, loading } = useQuery(GROUPS_QUERY, { pollInterval: 60_000 })
|
||||
|
||||
|
||||
const standings: Standing[] = data?.groupStandings ?? []
|
||||
const allMatches: MatchRow[] = data?.matches ?? []
|
||||
|
||||
const byGroup = standings.reduce<Record<string, Standing[]>>((acc, s) => {
|
||||
acc[s.groupName] = [...(acc[s.groupName] ?? []), s]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const matchesByGroup = allMatches
|
||||
.filter(m => m.group)
|
||||
.reduce<Record<string, MatchRow[]>>((acc, m) => {
|
||||
acc[m.group!] = [...(acc[m.group!] ?? []), m]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const groups = Object.entries(byGroup).sort(([a], [b]) => a.localeCompare(b))
|
||||
|
||||
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-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(300px,1fr))] gap-3.5">
|
||||
{Array.from({ length: 12 }).map((_, i) => (
|
||||
<div key={i} className="h-72 rounded-2xl animate-pulse bg-card" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-3.5">
|
||||
{groups.map(([groupName, rows]) => {
|
||||
const sorted = [...rows].sort((a, b) => {
|
||||
if (b.pts !== a.pts) return b.pts - a.pts
|
||||
if (b.goalDiff !== a.goalDiff) return b.goalDiff - a.goalDiff
|
||||
return b.goalsFor - a.goalsFor
|
||||
})
|
||||
const letter = groupName.replace('Group ', '')
|
||||
|
||||
const groupMatches = (matchesByGroup[groupName] ?? [])
|
||||
.sort((a, b) => {
|
||||
if (!a.date) return 1
|
||||
if (!b.date) return -1
|
||||
const ta = a.time ? utcKickoff(a.date, a.time) : new Date(a.date).getTime()
|
||||
const tb = b.time ? utcKickoff(b.date!, b.time) : new Date(b.date!).getTime()
|
||||
return ta - tb
|
||||
})
|
||||
const played = groupMatches.filter(m => m.scoreFt)
|
||||
const upcoming = groupMatches.filter(m => !m.scoreFt && !m.isLive)
|
||||
const live = groupMatches.filter(m => m.isLive)
|
||||
|
||||
return (
|
||||
<div key={groupName} className="glass-card">
|
||||
{/* Header */}
|
||||
<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>
|
||||
|
||||
{/* Standings */}
|
||||
<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>
|
||||
<span className="text-center">D</span><span className="text-center">L</span>
|
||||
<span className="text-center">GD</span><span className="text-center">Pts</span>
|
||||
</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 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-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-green-mid">{v}</span>
|
||||
))}
|
||||
<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-green">{t.pts}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{/* Live matches */}
|
||||
{live.length > 0 && (
|
||||
<div className="border-t border-green/10 px-4 py-2.5 space-y-1.5">
|
||||
{live.map(m => (
|
||||
<Link key={m.id} href={`/tournaments/2026#match-${m.id}`}>
|
||||
<div className="flex items-center gap-2 py-1 hover:opacity-80">
|
||||
<span className="text-[9px] font-bold text-green-light tracking-wider animate-pulse">LIVE</span>
|
||||
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
|
||||
<span className="text-[12px] text-text font-medium">{m.team1.name}</span>
|
||||
<span className="text-[11px] text-green-muted mx-0.5">vs</span>
|
||||
<span className="text-[12px] text-text font-medium">{m.team2.name}</span>
|
||||
<TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" />
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Results */}
|
||||
{played.length > 0 && (
|
||||
<div className="border-t border-green/10 px-4 py-2.5 space-y-1">
|
||||
{played.map(m => (
|
||||
<Link key={m.id} href={`/tournaments/2026#match-${m.id}`}>
|
||||
<div className="flex items-center gap-2 py-1 text-[12px] hover:opacity-80">
|
||||
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
|
||||
<span className="text-green-sec truncate flex-1">{m.team1.name}</span>
|
||||
<span className="font-['Bebas_Neue'] text-[15px] text-green tabular-nums">
|
||||
{m.scoreFt![0]}–{m.scoreFt![1]}
|
||||
</span>
|
||||
<span className="text-green-sec truncate flex-1 text-right">{m.team2.name}</span>
|
||||
<TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" />
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Upcoming */}
|
||||
{upcoming.length > 0 && (
|
||||
<div className="border-t border-green/[6%] px-4 py-2.5 space-y-1">
|
||||
{upcoming.map(m => (
|
||||
<Link key={m.id} href={`/tournaments/2026#match-${m.id}`}>
|
||||
<div className="flex items-center gap-2 py-1 text-[12px] hover:opacity-80">
|
||||
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
|
||||
<span className="text-green-sec truncate flex-1">{m.team1.name}</span>
|
||||
<span className="text-[10px] text-green-muted whitespace-nowrap tabular-nums">
|
||||
{m.date ? formatKickoff(m.date, m.time) : '–'}
|
||||
</span>
|
||||
<span className="text-green-sec truncate flex-1 text-right">{m.team2.name}</span>
|
||||
<TeamFlag name={m.team2.name} iso2={m.team2.iso2} size="sm" />
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+11
-98
@@ -1,103 +1,16 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import type { Metadata } from 'next'
|
||||
import { GroupsClient } from './client'
|
||||
|
||||
const GROUPS_QUERY = gql`
|
||||
query Groups {
|
||||
groupStandings(year: 2026) {
|
||||
groupName pos played won drawn lost goalsFor goalsAgainst goalDiff pts
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Standing {
|
||||
groupName: string; pos?: number | null
|
||||
played: number; won: number; drawn: number; lost: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; pts: number
|
||||
team: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
export const metadata: Metadata = {
|
||||
title: '2026 Group Stage',
|
||||
description: 'Live standings for all 12 groups at the 2026 FIFA World Cup — results, upcoming fixtures and qualification picture.',
|
||||
openGraph: {
|
||||
title: '2026 FIFA World Cup Group Stage',
|
||||
description: 'Live standings for all 12 groups at the 2026 FIFA World Cup.',
|
||||
url: '/groups',
|
||||
},
|
||||
}
|
||||
|
||||
export default function GroupsPage() {
|
||||
const { data, loading } = useQuery(GROUPS_QUERY, { pollInterval: 60_000 })
|
||||
|
||||
useEffect(() => { document.title = 'Group Stage · World Cup' }, [])
|
||||
|
||||
const standings: Standing[] = data?.groupStandings ?? []
|
||||
const byGroup = standings.reduce<Record<string, Standing[]>>((acc, s) => {
|
||||
acc[s.groupName] = [...(acc[s.groupName] ?? []), s]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const groups = Object.entries(byGroup).sort(([a], [b]) => a.localeCompare(b))
|
||||
|
||||
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>
|
||||
</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>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(268px,1fr))] gap-3.5">
|
||||
{groups.map(([groupName, rows]) => {
|
||||
const sorted = [...rows].sort((a, b) => {
|
||||
if (b.pts !== a.pts) return b.pts - a.pts
|
||||
if (b.goalDiff !== a.goalDiff) return b.goalDiff - a.goalDiff
|
||||
return b.goalsFor - a.goalsFor
|
||||
})
|
||||
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>
|
||||
<div className="grid px-4 py-2 text-[9px] text-[#2a5c35] 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>
|
||||
<span className="text-center">D</span><span className="text-center">L</span>
|
||||
<span className="text-center">GD</span><span className="text-center">Pts</span>
|
||||
</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="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>
|
||||
</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 className="text-center text-[13px] text-[#4a7a55]">
|
||||
{t.goalDiff > 0 ? `+${t.goalDiff}` : t.goalDiff}
|
||||
</span>
|
||||
<span className="text-center text-[13px] font-bold text-[#22c55e]">{t.pts}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return <GroupsClient />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { FireIcon, CalendarDaysIcon, TrophyIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
const HISTORY_QUERY = gql`
|
||||
query History {
|
||||
tournaments {
|
||||
year host winner runnerUp thirdPlace fourthPlace
|
||||
totalGoals matchesCount teamsCount avgGoalsPerGame
|
||||
topScorers(limit: 1) { playerName goals team { name iso2 } }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Tournament {
|
||||
year: number; host: string; winner?: string | null; runnerUp?: string | null
|
||||
thirdPlace?: string | null; fourthPlace?: string | null
|
||||
totalGoals?: number | null; matchesCount?: number | null; teamsCount?: number | null
|
||||
avgGoalsPerGame?: string | number | null
|
||||
topScorers: Array<{ playerName: string; goals: number; team?: { name: string; iso2?: string | null } | null }>
|
||||
}
|
||||
|
||||
|
||||
export function HistoryClient() {
|
||||
|
||||
const { data, loading } = useQuery(HISTORY_QUERY)
|
||||
const tournaments: Tournament[] = data?.tournaments ?? []
|
||||
const is2026InProgress = !tournaments.find(t => t.year === 2026)?.winner
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-green leading-none mb-2">
|
||||
World Cup History
|
||||
</h1>
|
||||
<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 bg-card" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
|
||||
{tournaments.map(t => {
|
||||
const inProgress = t.year === 2026 && is2026InProgress
|
||||
const topScorer = t.topScorers?.[0]
|
||||
return (
|
||||
<Link key={t.year} href={`/tournaments/${t.year}`}>
|
||||
<div className="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 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-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-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-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-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-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-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>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+11
-108
@@ -1,113 +1,16 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { FireIcon, CalendarDaysIcon, TrophyIcon } from '@heroicons/react/24/outline'
|
||||
import type { Metadata } from 'next'
|
||||
import { HistoryClient } from './client'
|
||||
|
||||
const HISTORY_QUERY = gql`
|
||||
query History {
|
||||
tournaments {
|
||||
year host winner runnerUp thirdPlace fourthPlace
|
||||
totalGoals matchesCount teamsCount avgGoalsPerGame
|
||||
topScorers(limit: 1) { playerName goals team { name iso2 } }
|
||||
export const metadata: Metadata = {
|
||||
title: 'Tournament History',
|
||||
description: 'Every FIFA World Cup from Uruguay 1930 to USA/Canada/Mexico 2026 — hosts, winners, and key statistics.',
|
||||
openGraph: {
|
||||
title: 'FIFA World Cup Tournament History (1930–2026)',
|
||||
description: 'Every FIFA World Cup from Uruguay 1930 to USA/Canada/Mexico 2026.',
|
||||
url: '/history',
|
||||
},
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Tournament {
|
||||
year: number; host: string; winner?: string | null; runnerUp?: string | null
|
||||
thirdPlace?: string | null; fourthPlace?: string | null
|
||||
totalGoals?: number | null; matchesCount?: number | null; teamsCount?: number | null
|
||||
avgGoalsPerGame?: string | number | null
|
||||
topScorers: Array<{ playerName: string; goals: number; team?: { name: string; iso2?: string | null } | null }>
|
||||
}
|
||||
|
||||
|
||||
export default function HistoryPage() {
|
||||
useEffect(() => { document.title = 'History · World Cup' }, [])
|
||||
|
||||
const { data, loading } = useQuery(HISTORY_QUERY)
|
||||
const tournaments: Tournament[] = data?.tournaments ?? []
|
||||
const is2026InProgress = !tournaments.find(t => t.year === 2026)?.winner
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
<h1 className="font-['Bebas_Neue'] text-[52px] tracking-[0.04em] text-[#22c55e] leading-none mb-2">
|
||||
World Cup History
|
||||
</h1>
|
||||
<p className="text-[#2a5c35] text-sm mb-9">
|
||||
Every edition — Uruguay 1930 through 2026 · {tournaments.length} tournaments
|
||||
</p>
|
||||
|
||||
{loading && !data && (
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
|
||||
{Array.from({ length: 24 }).map((_, i) => (
|
||||
<div key={i} className="h-52 rounded-2xl animate-pulse" style={{ background: '#0a1810' }} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(238px,1fr))] gap-3.5">
|
||||
{tournaments.map(t => {
|
||||
const inProgress = t.year === 2026 && is2026InProgress
|
||||
const topScorer = t.topScorers?.[0]
|
||||
return (
|
||||
<Link key={t.year} href={`/tournaments/${t.year}`}>
|
||||
<div className="glass-card p-5 relative cursor-pointer hover:border-[rgba(34,197,94,0.3)] 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)' }}>
|
||||
{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">
|
||||
{t.host}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{inProgress
|
||||
? <div className="text-[10px] text-[#22c55e] font-bold tracking-[0.12em] bg-[rgba(34,197,94,0.1)] px-2.5 py-1 rounded-full mt-1">
|
||||
IN PROGRESS
|
||||
</div>
|
||||
: t.winner && (
|
||||
<div className="text-right">
|
||||
<TeamFlag name={t.winner} size="md" />
|
||||
<div className="text-[11px] text-[#6abf7a] mt-0.5">{t.winner}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!inProgress && t.winner && t.runnerUp && (
|
||||
<div className="rounded-lg px-3 py-2 text-xs text-[#6abf7a] mb-3"
|
||||
style={{ background: 'rgba(34,197,94,0.07)' }}>
|
||||
<span className="font-semibold text-[#dff5e8]">{t.winner}</span>
|
||||
<span className="mx-2 text-[#2a5c35]">def.</span>
|
||||
{t.runnerUp}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-3.5 text-[11px] text-[#2a5c35] flex-wrap">
|
||||
{t.totalGoals != null && <span 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>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return <HistoryClient />
|
||||
}
|
||||
|
||||
+23
-9
@@ -8,17 +8,31 @@ import { AppApolloProvider } from '@/components/apollo-provider'
|
||||
const bebasNeue = Bebas_Neue({ weight: '400', subsets: ['latin'], variable: '--font-bebas' })
|
||||
const spaceGrotesk = Space_Grotesk({ subsets: ['latin'], variable: '--font-space' })
|
||||
|
||||
const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: { default: 'World Cup', template: '%s · World Cup' },
|
||||
description: 'Comprehensive World Cup statistics from 1930 to 2026',
|
||||
metadataBase: new URL(BASE_URL),
|
||||
title: { default: 'World Cup Stats', template: '%s · World Cup' },
|
||||
description: 'Live scores, group standings, results and statistics for every FIFA World Cup from 1930 to 2026.',
|
||||
keywords: ['World Cup', 'FIFA', 'football', 'soccer', 'statistics', 'live scores', 'standings', '2026'],
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
siteName: 'World Cup Stats',
|
||||
url: '/',
|
||||
title: 'World Cup Stats',
|
||||
description: 'Live scores, group standings, results and statistics for every FIFA World Cup from 1930 to 2026.',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary',
|
||||
title: 'World Cup Stats',
|
||||
description: 'Live scores, group standings, results and statistics for every FIFA World Cup from 1930 to 2026.',
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||
{ url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
|
||||
],
|
||||
apple: [
|
||||
{ url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' },
|
||||
],
|
||||
apple: [{ url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -35,11 +49,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]">
|
||||
<span>© {new Date().getFullYear()} World Cup Statistics. Data via openfootball.</span>
|
||||
<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
@@ -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'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>
|
||||
|
||||
+11
-210
@@ -1,215 +1,16 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { LiveBadge } from '@/components/live-badge'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
import type { Metadata } from 'next'
|
||||
import { HomeClient } from './client'
|
||||
|
||||
const HOME_QUERY = gql`
|
||||
query Home {
|
||||
tournamentStats { totalTournaments totalMatches totalGoals avgGoalsPerGame }
|
||||
liveMatches {
|
||||
id year round group date time isLive scoreFt scoreEt scoreP isQualiPlayoff
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
recentMatches(limit: 9) {
|
||||
id year round group date time isLive isQualiPlayoff scoreFt scoreEt scoreP
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
upcomingMatches(limit: 9) {
|
||||
id year round group date time isLive isQualiPlayoff scoreFt
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
topScorers(year: 2026, limit: 8) {
|
||||
playerName goals penalties ownGoals
|
||||
team { name iso2 }
|
||||
}
|
||||
tournament(year: 2026) { year totalGoals matchesCount avgGoalsPerGame }
|
||||
}
|
||||
`
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
interface UpcomingMatch {
|
||||
id: number; year: number; time?: string | null; date?: string | null
|
||||
team1: { name: string; iso2?: string | null }
|
||||
team2: { name: string; iso2?: string | null }
|
||||
}
|
||||
|
||||
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">
|
||||
<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>
|
||||
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
|
||||
{time && <div className="text-[11px] text-[#2a5c35] whitespace-nowrap ml-1">{time}</div>}
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
interface ScorerEntry {
|
||||
playerName: string; goals: number; penalties: number
|
||||
team?: { name: string; iso2?: string | null } | null
|
||||
}
|
||||
|
||||
interface MatchData {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; time?: string | null; isLive: boolean; isQualiPlayoff: boolean
|
||||
scoreFt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { name: string; iso2?: string | null; slug?: string | null }
|
||||
team2: { name: string; iso2?: string | null; slug?: string | null }
|
||||
export const metadata: Metadata = {
|
||||
title: 'World Cup 2026 — Live Scores, Groups & Stats',
|
||||
description: 'Live scores, group standings, upcoming fixtures and all-time top scorers for the 2026 FIFA World Cup in USA, Canada & Mexico.',
|
||||
openGraph: {
|
||||
title: 'World Cup 2026 — Live Scores, Groups & Stats',
|
||||
description: 'Live scores, group standings, upcoming fixtures and all-time top scorers for the 2026 FIFA World Cup.',
|
||||
url: '/',
|
||||
},
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const { data, loading } = useQuery(HOME_QUERY, { pollInterval: 60_000 })
|
||||
|
||||
useEffect(() => { document.title = 'World Cup' }, [])
|
||||
|
||||
const stats = data?.tournamentStats
|
||||
const live: MatchData[] = data?.liveMatches ?? []
|
||||
const recent: MatchData[] = data?.recentMatches ?? []
|
||||
const upcoming: UpcomingMatch[] = data?.upcomingMatches ?? []
|
||||
const scorers: ScorerEntry[] = data?.topScorers ?? []
|
||||
const wc2026 = data?.tournament
|
||||
|
||||
const maxGoals = Math.max(...scorers.map(s => s.goals), 1)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* ── Hero ── */}
|
||||
<div className="pitch-grid border-b" 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">
|
||||
<div className="mb-4">
|
||||
{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>
|
||||
</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">
|
||||
USA · Canada · Mexico · 11 June – 19 July 2026 · 48 Teams
|
||||
</p>
|
||||
<div className="flex gap-2.5 flex-wrap max-w-[760px]">
|
||||
{stats ? <>
|
||||
<StatPill label="Tournaments" value={stats.totalTournaments} />
|
||||
<StatPill label="Matches" value={stats.totalMatches} />
|
||||
<StatPill label="Goals" value={stats.totalGoals} />
|
||||
<StatPill label="Goals/Game" value={stats.avgGoalsPerGame?.toFixed(2) ?? '–'} />
|
||||
{wc2026 && <>
|
||||
<StatPill label="2026 Goals" value={wc2026.totalGoals ?? 0} />
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-[1200px] mx-auto px-7">
|
||||
{/* Live matches */}
|
||||
{live.length > 0 && (
|
||||
<div className="pt-9">
|
||||
<SectionHeader label="Live Now" />
|
||||
<div className="grid gap-4">
|
||||
{live.map(m => <MatchCard key={m.id} match={m} />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Latest result */}
|
||||
{recent.length > 0 && (
|
||||
<div className="pt-9">
|
||||
<SectionHeader label="Latest Result" />
|
||||
<MatchCard match={recent[0]} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recent grid */}
|
||||
{recent.length > 1 && (
|
||||
<div className="pt-8">
|
||||
<SectionHeader label="Recent Results" />
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(290px,1fr))] gap-2.5">
|
||||
{recent.slice(1).map(m => <MatchCard key={m.id} match={m} compact />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Upcoming */}
|
||||
{upcoming.length > 0 && (
|
||||
<div className="pt-8">
|
||||
<SectionHeader label="Upcoming Fixtures" />
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-2">
|
||||
{upcoming.map(m => <UpcomingFixture key={m.id} match={m} />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Golden Boot 2026 */}
|
||||
{scorers.length > 0 && (
|
||||
<div className="pt-8 pb-16">
|
||||
<SectionHeader label="2026 Golden Boot Race" />
|
||||
<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>
|
||||
{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>
|
||||
<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>
|
||||
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] 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>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading && !data && (
|
||||
<div className="py-16 text-center text-[#2a5c35] text-sm">Loading live World Cup data…</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return <HomeClient />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
|
||||
const PLAYER_QUERY = gql`
|
||||
query Player($name: String!) {
|
||||
player(name: $name) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const PLAYER_MATCHES_QUERY = gql`
|
||||
query PlayerMatches($name: String!) {
|
||||
tournaments { year }
|
||||
}
|
||||
`
|
||||
|
||||
interface PlayerData {
|
||||
playerName: string; goals: number; penalties: number; ownGoals: number; tournaments: number
|
||||
team?: { id: number; name: string; iso2?: string | null; slug: string } | null
|
||||
}
|
||||
|
||||
export function PlayerClient({ params }: { params: Promise<{ name: string }> }) {
|
||||
const { name: encodedName } = use(params)
|
||||
const name = decodeURIComponent(encodedName)
|
||||
|
||||
const { data, loading } = useQuery(PLAYER_QUERY, { variables: { name } })
|
||||
const player: PlayerData | null = data?.player ?? null
|
||||
|
||||
useEffect(() => {
|
||||
}, [player, name])
|
||||
|
||||
// Fetch all goals for this player broken down by year
|
||||
const { data: goalsData } = useQuery(gql`
|
||||
query PlayerGoalsByYear {
|
||||
tournaments { year }
|
||||
topScorers(limit: 1000) {
|
||||
playerName goals team { id }
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
if (loading && !data) {
|
||||
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-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>
|
||||
)
|
||||
}
|
||||
|
||||
const normalGoals = player.goals - player.penalties - player.ownGoals
|
||||
|
||||
return (
|
||||
<div className="max-w-[900px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Hero */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
<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-green leading-none">{player.playerName}</h1>
|
||||
{player.team && (
|
||||
<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-green leading-none">{player.goals}</div>
|
||||
<div className="text-[10px] text-green-muted tracking-[0.12em] uppercase">World Cup Goals</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats breakdown */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8">
|
||||
{[
|
||||
{ label: 'Total Goals', value: player.goals },
|
||||
{ label: 'Open Play', value: normalGoals },
|
||||
{ label: 'Penalties', value: player.penalties },
|
||||
{ label: 'Tournaments', value: player.tournaments },
|
||||
].map(item => (
|
||||
<div key={item.label} className="glass-card rounded-xl p-4">
|
||||
<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-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-green text-sm hover:underline">← All-time scorers</Link>
|
||||
{player.team && (
|
||||
<Link href={`/teams/${player.team.slug}`} className="text-green text-sm hover:underline">
|
||||
→ {player.team.name} team page
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+13
-111
@@ -1,118 +1,20 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
import type { Metadata } from 'next'
|
||||
import { PlayerClient } from './client'
|
||||
|
||||
const PLAYER_QUERY = gql`
|
||||
query Player($name: String!) {
|
||||
player(name: $name) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
type Props = { params: Promise<{ name: string }> }
|
||||
|
||||
const PLAYER_MATCHES_QUERY = gql`
|
||||
query PlayerMatches($name: String!) {
|
||||
tournaments { year }
|
||||
}
|
||||
`
|
||||
|
||||
interface PlayerData {
|
||||
playerName: string; goals: number; penalties: number; ownGoals: number; tournaments: number
|
||||
team?: { id: number; name: string; iso2?: string | null; slug: string } | null
|
||||
}
|
||||
|
||||
export default function PlayerPage({ params }: { params: Promise<{ name: string }> }) {
|
||||
const { name: encodedName } = use(params)
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { name: encodedName } = await params
|
||||
const name = decodeURIComponent(encodedName)
|
||||
|
||||
const { data, loading } = useQuery(PLAYER_QUERY, { variables: { name } })
|
||||
const player: PlayerData | null = data?.player ?? null
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${player?.playerName ?? name} · World Cup`
|
||||
}, [player, name])
|
||||
|
||||
// Fetch all goals for this player broken down by year
|
||||
const { data: goalsData } = useQuery(gql`
|
||||
query PlayerGoalsByYear {
|
||||
tournaments { year }
|
||||
topScorers(limit: 1000) {
|
||||
playerName goals team { id }
|
||||
const title = `${name} — World Cup Goals & Stats`
|
||||
const description = `${name}'s FIFA World Cup career: goals by tournament, match history and career statistics.`
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
openGraph: { title, description, url: `/players/${encodedName}` },
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
if (loading && !data) {
|
||||
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const normalGoals = player.goals - player.penalties - player.ownGoals
|
||||
|
||||
return (
|
||||
<div className="max-w-[900px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Hero */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
<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>
|
||||
{player.team && (
|
||||
<Link href={`/teams/${player.team.slug}`} className="text-[#6abf7a] text-sm mt-1 hover:text-[#dff5e8] 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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats breakdown */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8">
|
||||
{[
|
||||
{ label: 'Total Goals', value: player.goals },
|
||||
{ label: 'Open Play', value: normalGoals },
|
||||
{ label: 'Penalties', value: player.penalties },
|
||||
{ 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>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{player.ownGoals > 0 && (
|
||||
<div className="mb-6 glass-card rounded-xl p-3 px-4 text-sm text-[#2a5c35]">
|
||||
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>
|
||||
{player.team && (
|
||||
<Link href={`/teams/${player.team.slug}`} className="text-[#22c55e] text-sm hover:underline">
|
||||
→ {player.team.name} team page
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
export default function PlayerPage({ params }: Props) {
|
||||
return <PlayerClient params={params} />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { MetadataRoute } from 'next'
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: { userAgent: '*', allow: '/' },
|
||||
sitemap: `${(process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000').replace(/\/$/, '')}/sitemap.xml`,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useSearchParams, useRouter } from 'next/navigation'
|
||||
import { useState, useEffect, Suspense } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { TrophyIcon, FireIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
const SEARCH_QUERY = gql`
|
||||
query Search($q: String!) {
|
||||
search(query: $q) {
|
||||
tournaments { year host winner totalGoals matchesCount }
|
||||
teams { name iso2 slug stats { appearances titles } }
|
||||
players { playerName goals tournaments team { name iso2 } }
|
||||
matches {
|
||||
id year round group date scoreFt isQualiPlayoff
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface SearchMatch {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; scoreFt?: number[] | null; isQualiPlayoff: boolean
|
||||
team1: { name: string; iso2?: string | null }
|
||||
team2: { name: string; iso2?: string | null }
|
||||
}
|
||||
|
||||
function SearchContent() {
|
||||
const searchParams = useSearchParams()
|
||||
const router = useRouter()
|
||||
const initialQ = searchParams.get('q') ?? ''
|
||||
const [q, setQ] = useState(initialQ)
|
||||
const [debouncedQ, setDebouncedQ] = useState(initialQ)
|
||||
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => {
|
||||
setDebouncedQ(q)
|
||||
if (q.trim()) router.replace(`/search?q=${encodeURIComponent(q.trim())}`, { scroll: false })
|
||||
}, 300)
|
||||
return () => clearTimeout(t)
|
||||
}, [q, router])
|
||||
|
||||
useEffect(() => {
|
||||
}, [q])
|
||||
|
||||
const skip = debouncedQ.trim().length < 2
|
||||
const { data, loading } = useQuery(SEARCH_QUERY, {
|
||||
variables: { q: debouncedQ },
|
||||
skip,
|
||||
})
|
||||
|
||||
const results = data?.search
|
||||
const total = skip ? 0 : (
|
||||
(results?.tournaments?.length ?? 0) +
|
||||
(results?.teams?.length ?? 0) +
|
||||
(results?.players?.length ?? 0) +
|
||||
(results?.matches?.length ?? 0)
|
||||
)
|
||||
|
||||
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-green leading-none mb-6">Search</h1>
|
||||
|
||||
{/* Search input */}
|
||||
<div className="relative max-w-lg mb-8">
|
||||
<input
|
||||
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-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="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-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-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-green-dark py-16 text-sm">No results for "{debouncedQ}"</div>
|
||||
)}
|
||||
|
||||
{/* Results count */}
|
||||
{!skip && total > 0 && (
|
||||
<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-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-green/25 transition-colors cursor-pointer">
|
||||
<TeamFlag name={t.name} iso2={t.iso2} size="md" />
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Players */}
|
||||
{results?.players?.length > 0 && (
|
||||
<section>
|
||||
<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-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-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-green flex-shrink-0 inline-flex items-center gap-0.5">{p.goals}<FireIcon className="w-3.5 h-3.5" /></span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Tournaments */}
|
||||
{results?.tournaments?.length > 0 && (
|
||||
<section>
|
||||
<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-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>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Matches */}
|
||||
{results?.matches?.length > 0 && (
|
||||
<section>
|
||||
<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-green/25 transition-colors cursor-pointer">
|
||||
<TeamFlag name={m.team1.name} iso2={m.team1.iso2} size="sm" />
|
||||
<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-green-muted whitespace-nowrap">{m.year} · {m.round}</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function SearchClient() {
|
||||
return (
|
||||
<Suspense fallback={<div className="p-10 text-green-muted">Loading…</div>}>
|
||||
<SearchContent />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
+7
-189
@@ -1,194 +1,12 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useSearchParams, useRouter } from 'next/navigation'
|
||||
import { useState, useEffect, Suspense } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { TrophyIcon, FireIcon } from '@heroicons/react/24/outline'
|
||||
import type { Metadata } from 'next'
|
||||
import { SearchClient } from './client'
|
||||
|
||||
const SEARCH_QUERY = gql`
|
||||
query Search($q: String!) {
|
||||
search(query: $q) {
|
||||
tournaments { year host winner totalGoals matchesCount }
|
||||
teams { name iso2 slug stats { appearances titles } }
|
||||
players { playerName goals tournaments team { name iso2 } }
|
||||
matches {
|
||||
id year round group date scoreFt isQualiPlayoff
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface SearchMatch {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; scoreFt?: number[] | null; isQualiPlayoff: boolean
|
||||
team1: { name: string; iso2?: string | null }
|
||||
team2: { name: string; iso2?: string | null }
|
||||
}
|
||||
|
||||
function SearchContent() {
|
||||
const searchParams = useSearchParams()
|
||||
const router = useRouter()
|
||||
const initialQ = searchParams.get('q') ?? ''
|
||||
const [q, setQ] = useState(initialQ)
|
||||
const [debouncedQ, setDebouncedQ] = useState(initialQ)
|
||||
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => {
|
||||
setDebouncedQ(q)
|
||||
if (q.trim()) router.replace(`/search?q=${encodeURIComponent(q.trim())}`, { scroll: false })
|
||||
}, 300)
|
||||
return () => clearTimeout(t)
|
||||
}, [q, router])
|
||||
|
||||
useEffect(() => {
|
||||
document.title = q.trim() ? `"${q.trim()}" · World Cup` : 'Search · World Cup'
|
||||
}, [q])
|
||||
|
||||
const skip = debouncedQ.trim().length < 2
|
||||
const { data, loading } = useQuery(SEARCH_QUERY, {
|
||||
variables: { q: debouncedQ },
|
||||
skip,
|
||||
})
|
||||
|
||||
const results = data?.search
|
||||
const total = skip ? 0 : (
|
||||
(results?.tournaments?.length ?? 0) +
|
||||
(results?.teams?.length ?? 0) +
|
||||
(results?.players?.length ?? 0) +
|
||||
(results?.matches?.length ?? 0)
|
||||
)
|
||||
|
||||
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>
|
||||
|
||||
{/* Search input */}
|
||||
<div className="relative max-w-lg mb-8">
|
||||
<input
|
||||
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)' }}
|
||||
/>
|
||||
<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">
|
||||
<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" />}
|
||||
</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>
|
||||
)}
|
||||
|
||||
{/* No results */}
|
||||
{!skip && !loading && total === 0 && (
|
||||
<div className="text-center text-[#1a3a22] 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="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>
|
||||
<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">
|
||||
<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]">
|
||||
{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>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Players */}
|
||||
{results?.players?.length > 0 && (
|
||||
<section>
|
||||
<h3 className="text-[11px] text-[#2a5c35] 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">
|
||||
{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>
|
||||
<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>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Tournaments */}
|
||||
{results?.tournaments?.length > 0 && (
|
||||
<section>
|
||||
<h3 className="text-[11px] text-[#2a5c35] 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>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Matches */}
|
||||
{results?.matches?.length > 0 && (
|
||||
<section>
|
||||
<h3 className="text-[11px] text-[#2a5c35] 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">
|
||||
<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>}
|
||||
<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>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
export const metadata: Metadata = {
|
||||
title: 'Search',
|
||||
description: 'Search for teams, players, tournaments and stadiums across all FIFA World Cups.',
|
||||
robots: { index: false },
|
||||
}
|
||||
|
||||
export default function SearchPage() {
|
||||
return (
|
||||
<Suspense fallback={<div className="p-10 text-[#2a5c35]">Loading…</div>}>
|
||||
<SearchContent />
|
||||
</Suspense>
|
||||
)
|
||||
return <SearchClient />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { MetadataRoute } from 'next'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
import { db } from '@/lib/db'
|
||||
import { tournaments, teams, goals } from '@/lib/db/schema'
|
||||
import { asc } from 'drizzle-orm'
|
||||
|
||||
const BASE = (process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000').replace(/\/$/, '')
|
||||
|
||||
function slugify(name: string) {
|
||||
return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
|
||||
}
|
||||
|
||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
const now = new Date()
|
||||
|
||||
const [allTournaments, allTeams, allPlayers] = await Promise.all([
|
||||
db.select({ year: tournaments.year }).from(tournaments).orderBy(asc(tournaments.year)),
|
||||
db.select({ name: teams.name }).from(teams).orderBy(asc(teams.name)),
|
||||
db.selectDistinct({ playerName: goals.playerName }).from(goals),
|
||||
])
|
||||
|
||||
return [
|
||||
{ url: BASE, lastModified: now, changeFrequency: 'hourly', priority: 1 },
|
||||
{ url: `${BASE}/groups`, lastModified: now, changeFrequency: 'hourly', priority: 0.9 },
|
||||
{ url: `${BASE}/history`, changeFrequency: 'monthly', priority: 0.7 },
|
||||
{ url: `${BASE}/stats`, changeFrequency: 'daily', priority: 0.7 },
|
||||
...allTournaments.map(t => ({
|
||||
url: `${BASE}/tournaments/${t.year}`,
|
||||
changeFrequency: (t.year === 2026 ? 'hourly' : 'monthly') as 'hourly' | 'monthly',
|
||||
priority: t.year === 2026 ? 0.95 : 0.6,
|
||||
})),
|
||||
...allTeams.map(t => ({
|
||||
url: `${BASE}/teams/${slugify(t.name)}`,
|
||||
changeFrequency: 'weekly' as const,
|
||||
priority: 0.5,
|
||||
})),
|
||||
...allPlayers.map(p => ({
|
||||
url: `${BASE}/players/${encodeURIComponent(p.playerName)}`,
|
||||
changeFrequency: 'monthly' as const,
|
||||
priority: 0.4,
|
||||
})),
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import {
|
||||
ChartBarIcon, StarIcon, TrophyIcon, ClockIcon, BoltIcon,
|
||||
FireIcon, SparklesIcon, ArrowPathIcon, GlobeEuropeAfricaIcon, TableCellsIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
|
||||
const STATS_QUERY = gql`
|
||||
query Stats {
|
||||
tournaments { year host totalGoals matchesCount avgGoalsPerGame winner }
|
||||
topScorers(limit: 20) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { name iso2 slug }
|
||||
}
|
||||
teams {
|
||||
id name iso2 slug
|
||||
stats { appearances titles wins draws losses goalsFor goalsAgainst goalDiff winPct }
|
||||
}
|
||||
goalsByMinute { bucket count }
|
||||
confederationStats { confederation appearances titles totalGoals }
|
||||
hatTricks {
|
||||
playerName year round goals
|
||||
team { name iso2 }
|
||||
opponent { name iso2 }
|
||||
}
|
||||
biggestWins(limit: 10) {
|
||||
id year round date margin totalGoals scoreFt
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
highestScoringMatches(limit: 10) {
|
||||
id year round date totalGoals scoreFt
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
extraTimeStats {
|
||||
totalKnockoutMatches wentToExtraTime wentToPenalties extraTimePct penaltiesPct
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
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-green-muted mb-4">
|
||||
<Icon className="w-3.5 h-3.5 flex-shrink-0" />
|
||||
{children}
|
||||
</h2>
|
||||
)
|
||||
}
|
||||
|
||||
function Card({ children, className = '' }: { children: React.ReactNode; className?: string }) {
|
||||
return (
|
||||
<div className={`glass-card ${className}`}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface Tournament { year: number; host: string; totalGoals?: number | null; matchesCount?: number | null; avgGoalsPerGame?: string | number | null; winner?: string | null }
|
||||
interface Scorer { playerName: string; goals: number; penalties: number; ownGoals: number; tournaments: number; team?: { name: string; iso2?: string | null; slug: string } | null }
|
||||
interface TeamRow { id: number; name: string; iso2?: string | null; slug: string; stats?: { appearances: number; titles: number; wins: number; draws: number; losses: number; goalsFor: number; goalsAgainst: number; winPct: number } | null }
|
||||
interface MinuteBucket { bucket: string; count: number }
|
||||
interface ConfStat { confederation: string; appearances: number; titles: number; totalGoals: number }
|
||||
interface HatTrick { playerName: string; year: number; round: string; goals: number; team?: { name: string; iso2?: string | null } | null; opponent?: { name: string; iso2?: string | null } | null }
|
||||
interface MatchRow { id: number; year: number; round: string; date?: string | null; margin?: number | null; totalGoals?: number | null; scoreFt?: number[] | null; team1: { name: string; iso2?: string | null }; team2: { name: string; iso2?: string | null } }
|
||||
interface ETStats { totalKnockoutMatches: number; wentToExtraTime: number; wentToPenalties: number; extraTimePct: number; penaltiesPct: number }
|
||||
|
||||
export function StatsClient() {
|
||||
|
||||
const { data, loading } = useQuery(STATS_QUERY)
|
||||
|
||||
const tournaments: Tournament[] = (data?.tournaments ?? []).filter((t: Tournament) => t.totalGoals != null).sort((a: Tournament, b: Tournament) => a.year - b.year)
|
||||
const scorers: Scorer[] = data?.topScorers ?? []
|
||||
const teams: TeamRow[] = (data?.teams ?? []).filter((t: TeamRow) => t.stats && t.stats.appearances > 0).sort((a: TeamRow, b: TeamRow) => (b.stats?.appearances ?? 0) - (a.stats?.appearances ?? 0))
|
||||
const minuteBuckets: MinuteBucket[] = data?.goalsByMinute ?? []
|
||||
const confStats: ConfStat[] = data?.confederationStats ?? []
|
||||
const hatTricks: HatTrick[] = data?.hatTricks ?? []
|
||||
const biggestWins: MatchRow[] = data?.biggestWins ?? []
|
||||
const highScoring: MatchRow[] = data?.highestScoringMatches ?? []
|
||||
const etStats: ETStats | null = data?.extraTimeStats ?? null
|
||||
|
||||
const titlesByNation = teams
|
||||
.filter(t => (t.stats?.titles ?? 0) > 0)
|
||||
.sort((a, b) => (b.stats?.titles ?? 0) - (a.stats?.titles ?? 0))
|
||||
.slice(0, 10)
|
||||
|
||||
const maxGoals = Math.max(...tournaments.map(t => t.totalGoals ?? 0), 1)
|
||||
const maxScorer = Math.max(...scorers.map(s => s.goals), 1)
|
||||
const maxMinute = Math.max(...minuteBuckets.map(b => b.count), 1)
|
||||
|
||||
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-green leading-none mb-10">Historical Statistics</h1>
|
||||
|
||||
{loading && !data && (
|
||||
<div className="text-green-muted text-sm py-16 text-center">Loading statistics…</div>
|
||||
)}
|
||||
|
||||
{/* ── Goals per tournament bar chart ── */}
|
||||
{tournaments.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ChartBarIcon}>Goals Scored per Tournament</SectionTitle>
|
||||
<Card>
|
||||
<div className="px-3 pt-4 pb-0 sm:px-7 sm:pt-7">
|
||||
<div className="flex items-end gap-[2px] sm:gap-[3px] h-[170px]">
|
||||
{tournaments.map(t => {
|
||||
const h = Math.max(4, Math.round(((t.totalGoals ?? 0) / maxGoals) * 140))
|
||||
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-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 border-green/[6%]">
|
||||
{tournaments.map(t => (
|
||||
<div key={t.year} className="flex-1 text-center text-[6px] text-green-dark" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}>
|
||||
{t.year}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
|
||||
{/* ── All-time top scorers ── */}
|
||||
<div>
|
||||
<SectionTitle icon={StarIcon}>All-Time Top Scorers</SectionTitle>
|
||||
<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-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-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 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-green min-w-[28px] text-right flex-shrink-0">{s.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* ── World Cup titles ── */}
|
||||
<div>
|
||||
<SectionTitle icon={TrophyIcon}>World Cup Titles by Nation</SectionTitle>
|
||||
<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 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-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-green" />
|
||||
))}
|
||||
</div>
|
||||
<span className="font-['Bebas_Neue'] text-[28px] text-green flex-shrink-0">{t.stats?.titles}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Goals by minute heatmap ── */}
|
||||
{minuteBuckets.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ClockIcon}>Goals by Minute (All-Time)</SectionTitle>
|
||||
<Card>
|
||||
<div className="px-3 py-4 sm:p-6">
|
||||
<div className="flex items-end gap-1 sm:gap-3 h-24">
|
||||
{minuteBuckets.map(b => {
|
||||
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-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>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
|
||||
{/* ── Biggest wins ── */}
|
||||
<div>
|
||||
<SectionTitle icon={BoltIcon}>Biggest Victories</SectionTitle>
|
||||
<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 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-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-green flex-shrink-0">
|
||||
{m.scoreFt?.[0]}–{m.scoreFt?.[1]}
|
||||
</span>
|
||||
<span className="text-[10px] text-green-muted flex-shrink-0">+{m.margin}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* ── Highest scoring matches ── */}
|
||||
<div>
|
||||
<SectionTitle icon={FireIcon}>Highest Scoring Matches</SectionTitle>
|
||||
<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 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-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-green flex-shrink-0">
|
||||
{m.scoreFt?.[0]}–{m.scoreFt?.[1]}
|
||||
</span>
|
||||
<span className="text-[10px] text-green-light flex-shrink-0">{m.totalGoals} goals</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Hat-tricks ── */}
|
||||
{hatTricks.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={SparklesIcon}>Hat-Tricks</SectionTitle>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] gap-3">
|
||||
{hatTricks.map((h, i) => (
|
||||
<div key={i} className="glass-card rounded-xl p-4">
|
||||
<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-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-green">{h.goals}</span>
|
||||
</div>
|
||||
<div className="text-[10px] text-green-muted">
|
||||
{h.year} · {h.round}
|
||||
{h.opponent && <span> vs {h.opponent.name}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── ET & Penalty stats ── */}
|
||||
{etStats && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ArrowPathIcon}>Extra Time & Penalty Shootouts</SectionTitle>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ label: 'Knockout Matches', value: etStats.totalKnockoutMatches },
|
||||
{ label: 'Went to AET', value: `${etStats.wentToExtraTime} (${etStats.extraTimePct}%)` },
|
||||
{ label: 'Decided by PSO', value: `${etStats.wentToPenalties} (${etStats.penaltiesPct}%)` },
|
||||
{ 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-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>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Confederation stats ── */}
|
||||
{confStats.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={GlobeEuropeAfricaIcon}>Performance by Confederation</SectionTitle>
|
||||
<Card>
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<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 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>
|
||||
</table>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── All-time team table ── */}
|
||||
{teams.length > 0 && (
|
||||
<div>
|
||||
<SectionTitle icon={TableCellsIcon}>All-Time Team Table</SectionTitle>
|
||||
<Card>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full" style={{ minWidth: '560px' }}>
|
||||
<thead>
|
||||
<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-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 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-text whitespace-nowrap">{t.name}</span>
|
||||
</Link>
|
||||
</td>
|
||||
<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-green">{t.stats?.winPct}%</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+11
-369
@@ -1,374 +1,16 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import {
|
||||
ChartBarIcon, StarIcon, TrophyIcon, ClockIcon, BoltIcon,
|
||||
FireIcon, SparklesIcon, ArrowPathIcon, GlobeEuropeAfricaIcon, TableCellsIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import type { Metadata } from 'next'
|
||||
import { StatsClient } from './client'
|
||||
|
||||
const STATS_QUERY = gql`
|
||||
query Stats {
|
||||
tournaments { year host totalGoals matchesCount avgGoalsPerGame winner }
|
||||
topScorers(limit: 20) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { name iso2 slug }
|
||||
export const metadata: Metadata = {
|
||||
title: 'All-Time Statistics',
|
||||
description: 'All-time FIFA World Cup statistics: top scorers, hat-tricks, penalty records, biggest victories, and goals by tournament from 1930 to 2026.',
|
||||
openGraph: {
|
||||
title: 'FIFA World Cup All-Time Statistics',
|
||||
description: 'All-time World Cup statistics: top scorers, hat-tricks, records and more.',
|
||||
url: '/stats',
|
||||
},
|
||||
}
|
||||
teams {
|
||||
id name iso2 slug
|
||||
stats { appearances titles wins draws losses goalsFor goalsAgainst goalDiff winPct }
|
||||
}
|
||||
goalsByMinute { bucket count }
|
||||
confederationStats { confederation appearances titles totalGoals }
|
||||
hatTricks {
|
||||
playerName year round goals
|
||||
team { name iso2 }
|
||||
opponent { name iso2 }
|
||||
}
|
||||
biggestWins(limit: 10) {
|
||||
id year round date margin totalGoals scoreFt
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
highestScoringMatches(limit: 10) {
|
||||
id year round date totalGoals scoreFt
|
||||
team1 { name iso2 } team2 { name iso2 }
|
||||
}
|
||||
extraTimeStats {
|
||||
totalKnockoutMatches wentToExtraTime wentToPenalties extraTimePct penaltiesPct
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
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">
|
||||
<Icon className="w-3.5 h-3.5 flex-shrink-0" />
|
||||
{children}
|
||||
</h2>
|
||||
)
|
||||
}
|
||||
|
||||
function Card({ children, className = '' }: { children: React.ReactNode; className?: string }) {
|
||||
return (
|
||||
<div className={`glass-card ${className}`}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface Tournament { year: number; host: string; totalGoals?: number | null; matchesCount?: number | null; avgGoalsPerGame?: string | number | null; winner?: string | null }
|
||||
interface Scorer { playerName: string; goals: number; penalties: number; ownGoals: number; tournaments: number; team?: { name: string; iso2?: string | null; slug: string } | null }
|
||||
interface TeamRow { id: number; name: string; iso2?: string | null; slug: string; stats?: { appearances: number; titles: number; wins: number; draws: number; losses: number; goalsFor: number; goalsAgainst: number; winPct: number } | null }
|
||||
interface MinuteBucket { bucket: string; count: number }
|
||||
interface ConfStat { confederation: string; appearances: number; titles: number; totalGoals: number }
|
||||
interface HatTrick { playerName: string; year: number; round: string; goals: number; team?: { name: string; iso2?: string | null } | null; opponent?: { name: string; iso2?: string | null } | null }
|
||||
interface MatchRow { id: number; year: number; round: string; date?: string | null; margin?: number | null; totalGoals?: number | null; scoreFt?: number[] | null; team1: { name: string; iso2?: string | null }; team2: { name: string; iso2?: string | null } }
|
||||
interface ETStats { totalKnockoutMatches: number; wentToExtraTime: number; wentToPenalties: number; extraTimePct: number; penaltiesPct: number }
|
||||
|
||||
export default function StatsPage() {
|
||||
useEffect(() => { document.title = 'Statistics · World Cup' }, [])
|
||||
|
||||
const { data, loading } = useQuery(STATS_QUERY)
|
||||
|
||||
const tournaments: Tournament[] = (data?.tournaments ?? []).filter((t: Tournament) => t.totalGoals != null).sort((a: Tournament, b: Tournament) => a.year - b.year)
|
||||
const scorers: Scorer[] = data?.topScorers ?? []
|
||||
const teams: TeamRow[] = (data?.teams ?? []).filter((t: TeamRow) => t.stats && t.stats.appearances > 0).sort((a: TeamRow, b: TeamRow) => (b.stats?.appearances ?? 0) - (a.stats?.appearances ?? 0))
|
||||
const minuteBuckets: MinuteBucket[] = data?.goalsByMinute ?? []
|
||||
const confStats: ConfStat[] = data?.confederationStats ?? []
|
||||
const hatTricks: HatTrick[] = data?.hatTricks ?? []
|
||||
const biggestWins: MatchRow[] = data?.biggestWins ?? []
|
||||
const highScoring: MatchRow[] = data?.highestScoringMatches ?? []
|
||||
const etStats: ETStats | null = data?.extraTimeStats ?? null
|
||||
|
||||
const titlesByNation = teams
|
||||
.filter(t => (t.stats?.titles ?? 0) > 0)
|
||||
.sort((a, b) => (b.stats?.titles ?? 0) - (a.stats?.titles ?? 0))
|
||||
.slice(0, 10)
|
||||
|
||||
const maxGoals = Math.max(...tournaments.map(t => t.totalGoals ?? 0), 1)
|
||||
const maxScorer = Math.max(...scorers.map(s => s.goals), 1)
|
||||
const maxMinute = Math.max(...minuteBuckets.map(b => b.count), 1)
|
||||
|
||||
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>
|
||||
|
||||
{loading && !data && (
|
||||
<div className="text-[#2a5c35] text-sm py-16 text-center">Loading statistics…</div>
|
||||
)}
|
||||
|
||||
{/* ── Goals per tournament bar chart ── */}
|
||||
{tournaments.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ChartBarIcon}>Goals Scored per Tournament</SectionTitle>
|
||||
<Card>
|
||||
<div className="px-3 pt-4 pb-0 sm:px-7 sm:pt-7">
|
||||
<div className="flex items-end gap-[2px] sm:gap-[3px] h-[170px]">
|
||||
{tournaments.map(t => {
|
||||
const h = Math.max(4, Math.round(((t.totalGoals ?? 0) / maxGoals) * 140))
|
||||
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)' }}
|
||||
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)' }}>
|
||||
{tournaments.map(t => (
|
||||
<div key={t.year} className="flex-1 text-center text-[6px] text-[#1a3a22]" style={{ transform: 'rotate(-45deg)', transformOrigin: 'center top' }}>
|
||||
{t.year}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
|
||||
{/* ── All-time top scorers ── */}
|
||||
<div>
|
||||
<SectionTitle icon={StarIcon}>All-Time Top Scorers</SectionTitle>
|
||||
<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>
|
||||
{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>
|
||||
<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>
|
||||
<span className="font-['Bebas_Neue'] text-[22px] text-[#22c55e] min-w-[28px] text-right flex-shrink-0">{s.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* ── World Cup titles ── */}
|
||||
<div>
|
||||
<SectionTitle icon={TrophyIcon}>World Cup Titles by Nation</SectionTitle>
|
||||
<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>
|
||||
<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="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]" />
|
||||
))}
|
||||
</div>
|
||||
<span className="font-['Bebas_Neue'] text-[28px] text-[#22c55e] flex-shrink-0">{t.stats?.titles}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Goals by minute heatmap ── */}
|
||||
{minuteBuckets.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ClockIcon}>Goals by Minute (All-Time)</SectionTitle>
|
||||
<Card>
|
||||
<div className="px-3 py-4 sm:p-6">
|
||||
<div className="flex items-end gap-1 sm:gap-3 h-24">
|
||||
{minuteBuckets.map(b => {
|
||||
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>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
|
||||
{/* ── Biggest wins ── */}
|
||||
<div>
|
||||
<SectionTitle icon={BoltIcon}>Biggest Victories</SectionTitle>
|
||||
<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)' }}>
|
||||
<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>
|
||||
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">
|
||||
{m.scoreFt?.[0]}–{m.scoreFt?.[1]}
|
||||
</span>
|
||||
<span className="text-[10px] text-[#2a5c35] flex-shrink-0">+{m.margin}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* ── Highest scoring matches ── */}
|
||||
<div>
|
||||
<SectionTitle icon={FireIcon}>Highest Scoring Matches</SectionTitle>
|
||||
<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)' }}>
|
||||
<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>
|
||||
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">
|
||||
{m.scoreFt?.[0]}–{m.scoreFt?.[1]}
|
||||
</span>
|
||||
<span className="text-[10px] text-[#4ade80] flex-shrink-0">{m.totalGoals} goals</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Hat-tricks ── */}
|
||||
{hatTricks.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={SparklesIcon}>Hat-Tricks</SectionTitle>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] gap-3">
|
||||
{hatTricks.map((h, i) => (
|
||||
<div key={i} className="glass-card rounded-xl p-4">
|
||||
<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>
|
||||
<span className="ml-auto font-['Bebas_Neue'] text-2xl text-[#22c55e]">{h.goals}</span>
|
||||
</div>
|
||||
<div className="text-[10px] text-[#2a5c35]">
|
||||
{h.year} · {h.round}
|
||||
{h.opponent && <span> vs {h.opponent.name}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── ET & Penalty stats ── */}
|
||||
{etStats && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={ArrowPathIcon}>Extra Time & Penalty Shootouts</SectionTitle>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ label: 'Knockout Matches', value: etStats.totalKnockoutMatches },
|
||||
{ label: 'Went to AET', value: `${etStats.wentToExtraTime} (${etStats.extraTimePct}%)` },
|
||||
{ label: 'Decided by PSO', value: `${etStats.wentToPenalties} (${etStats.penaltiesPct}%)` },
|
||||
{ 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>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Confederation stats ── */}
|
||||
{confStats.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<SectionTitle icon={GlobeEuropeAfricaIcon}>Performance by Confederation</SectionTitle>
|
||||
<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>
|
||||
</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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── All-time team table ── */}
|
||||
{teams.length > 0 && (
|
||||
<div>
|
||||
<SectionTitle icon={TableCellsIcon}>All-Time Team Table</SectionTitle>
|
||||
<Card>
|
||||
<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)' }}>
|
||||
{['#', '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>
|
||||
))}
|
||||
</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>
|
||||
<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>
|
||||
</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]">
|
||||
{(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>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
return <StatsClient />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { TrophyIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
const TEAM_QUERY = gql`
|
||||
query Team($slug: String!) {
|
||||
team(slug: $slug) {
|
||||
id name iso2 slug fifaCode continent confederation
|
||||
stats { appearances wins draws losses goalsFor goalsAgainst goalDiff titles winPct }
|
||||
}
|
||||
}
|
||||
`
|
||||
const TEAM_MATCHES_QUERY = gql`
|
||||
query TeamMatches($teamId: Int!) {
|
||||
matches(teamId: $teamId, isQuali: false) {
|
||||
id year round group date isLive scoreFt scoreEt scoreP
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface TeamData {
|
||||
id: number; name: string; iso2?: string | null; slug: string
|
||||
fifaCode?: string | null; continent?: string | null; confederation?: string | null
|
||||
stats?: {
|
||||
appearances: number; wins: number; draws: number; losses: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; titles: number; winPct: number
|
||||
} | null
|
||||
}
|
||||
|
||||
interface MatchRow {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; isLive: boolean
|
||||
scoreFt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { name: string; iso2?: string | null; slug?: string | null }
|
||||
team2: { name: string; iso2?: string | null; slug?: string | null }
|
||||
}
|
||||
|
||||
function formatDate(d: string) {
|
||||
return new Date(d).toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })
|
||||
}
|
||||
|
||||
export function TeamClient({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = use(params)
|
||||
const { data: teamData, loading } = useQuery(TEAM_QUERY, { variables: { slug } })
|
||||
const team: TeamData | null = teamData?.team ?? null
|
||||
|
||||
useEffect(() => {
|
||||
}, [team])
|
||||
|
||||
const { data: matchesData } = useQuery(TEAM_MATCHES_QUERY, {
|
||||
variables: { teamId: team?.id },
|
||||
skip: !team?.id,
|
||||
})
|
||||
|
||||
const { data: scorerData } = useQuery(gql`
|
||||
query TeamScorers($teamId: Int!) {
|
||||
topScorers(teamId: $teamId, limit: 30) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { id name iso2 }
|
||||
}
|
||||
}
|
||||
`, { variables: { teamId: team?.id ?? 0 }, skip: !team?.id })
|
||||
|
||||
const teamScorers = scorerData?.topScorers ?? []
|
||||
const teamMatches: MatchRow[] = matchesData?.matches ?? []
|
||||
|
||||
// Group matches by year for the history display
|
||||
const matchesByYear = teamMatches.reduce((acc: Record<number, MatchRow[]>, m) => {
|
||||
;(acc[m.year] ??= []).push(m)
|
||||
return acc
|
||||
}, {})
|
||||
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-green-muted">Loading team…</div>
|
||||
}
|
||||
|
||||
if (!team) {
|
||||
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-green-muted">Team not found.</div>
|
||||
}
|
||||
|
||||
const s = team.stats
|
||||
const played = (s?.wins ?? 0) + (s?.draws ?? 0) + (s?.losses ?? 0)
|
||||
const maxScorer = Math.max(...teamScorers.map((sc: { goals: number }) => sc.goals), 1)
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Hero */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
<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-green leading-none">{team.name}</h1>
|
||||
<div className="flex gap-3 mt-2 flex-wrap">
|
||||
{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-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>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_260px] gap-8">
|
||||
<div>
|
||||
{/* Stats grid */}
|
||||
{s && (
|
||||
<div className="mb-8">
|
||||
<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 },
|
||||
{ label: 'Matches', value: played },
|
||||
{ label: 'Win %', value: `${s.winPct}%` },
|
||||
{ label: 'Goals For', value: s.goalsFor },
|
||||
].map(item => (
|
||||
<div key={item.label} className="glass-card rounded-xl p-4">
|
||||
<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-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 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-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-green-mid">{v}</span>
|
||||
))}
|
||||
<span className="text-center text-sm text-green-mid">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tournament participations */}
|
||||
{years.length > 0 && (
|
||||
<div className="mb-8">
|
||||
<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-green-sec bg-bg/[78%] border border-border hover:text-green hover:border-green/40 backdrop-blur-sm">
|
||||
{year}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Match history by year */}
|
||||
{years.length > 0 && (
|
||||
<div>
|
||||
<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-green mb-2 hover:opacity-70 transition-opacity">
|
||||
{year}
|
||||
</Link>
|
||||
<div className="glass-card rounded-xl">
|
||||
{yMatches.map((m, i) => {
|
||||
const isHome = m.team1.name === team.name
|
||||
const opponent = isHome ? m.team2 : m.team1
|
||||
const ft = m.scoreFt
|
||||
const scoreEt = m.scoreEt
|
||||
const scoreP = m.scoreP
|
||||
// Winner: PSO first, then ET, then FT
|
||||
const decisive = scoreP ?? scoreEt ?? ft
|
||||
const myScore = decisive ? (isHome ? decisive[0] : decisive[1]) : null
|
||||
const theirScore = decisive ? (isHome ? decisive[1] : decisive[0]) : null
|
||||
const result = myScore != null && theirScore != null
|
||||
? myScore > theirScore ? 'W' : myScore < theirScore ? 'L' : 'D'
|
||||
: null
|
||||
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-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-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-green leading-none">
|
||||
{scoreP
|
||||
? `${isHome ? scoreP[0] : scoreP[1]}–${isHome ? scoreP[1] : scoreP[0]}`
|
||||
: displayScore
|
||||
? `${isHome ? displayScore[0] : displayScore[1]}–${isHome ? displayScore[1] : displayScore[0]}`
|
||||
: '–'}
|
||||
</div>
|
||||
{scoreP && ft && (
|
||||
<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-green-muted leading-none">a.e.t.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sidebar: top scorers */}
|
||||
<div>
|
||||
{teamScorers.length > 0 && (
|
||||
<div>
|
||||
<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-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-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 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-green flex-shrink-0">{sc.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+20
-265
@@ -1,273 +1,28 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { TrophyIcon } from '@heroicons/react/24/outline'
|
||||
import type { Metadata } from 'next'
|
||||
import { db } from '@/lib/db'
|
||||
import { teams } from '@/lib/db/schema'
|
||||
import { TeamClient } from './client'
|
||||
|
||||
const TEAM_QUERY = gql`
|
||||
query Team($slug: String!) {
|
||||
team(slug: $slug) {
|
||||
id name iso2 slug fifaCode continent confederation
|
||||
stats { appearances wins draws losses goalsFor goalsAgainst goalDiff titles winPct }
|
||||
}
|
||||
}
|
||||
`
|
||||
const TEAM_MATCHES_QUERY = gql`
|
||||
query TeamMatches($teamId: Int!) {
|
||||
matches(teamId: $teamId, isQuali: false) {
|
||||
id year round group date isLive scoreFt scoreEt scoreP
|
||||
team1 { name iso2 slug } team2 { name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
type Props = { params: Promise<{ slug: string }> }
|
||||
|
||||
interface TeamData {
|
||||
id: number; name: string; iso2?: string | null; slug: string
|
||||
fifaCode?: string | null; continent?: string | null; confederation?: string | null
|
||||
stats?: {
|
||||
appearances: number; wins: number; draws: number; losses: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; titles: number; winPct: number
|
||||
} | null
|
||||
function slugify(name: string) {
|
||||
return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
|
||||
}
|
||||
|
||||
interface MatchRow {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; isLive: boolean
|
||||
scoreFt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { name: string; iso2?: string | null; slug?: string | null }
|
||||
team2: { name: string; iso2?: string | null; slug?: string | null }
|
||||
}
|
||||
|
||||
function formatDate(d: string) {
|
||||
return new Date(d).toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })
|
||||
}
|
||||
|
||||
export default function TeamPage({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = use(params)
|
||||
const { data: teamData, loading } = useQuery(TEAM_QUERY, { variables: { slug } })
|
||||
const team: TeamData | null = teamData?.team ?? null
|
||||
|
||||
useEffect(() => {
|
||||
document.title = team ? `${team.name} · World Cup` : 'Team · World Cup'
|
||||
}, [team])
|
||||
|
||||
const { data: matchesData } = useQuery(TEAM_MATCHES_QUERY, {
|
||||
variables: { teamId: team?.id },
|
||||
skip: !team?.id,
|
||||
})
|
||||
|
||||
const { data: scorerData } = useQuery(gql`
|
||||
query TeamScorers($teamId: Int!) {
|
||||
topScorers(teamId: $teamId, limit: 30) {
|
||||
playerName goals penalties ownGoals tournaments
|
||||
team { id name iso2 }
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { slug } = await params
|
||||
const allTeams = await db.select({ name: teams.name }).from(teams)
|
||||
const team = allTeams.find(t => slugify(t.name) === slug)
|
||||
const name = team?.name ?? slug
|
||||
const title = `${name} at the FIFA World Cup`
|
||||
const description = `${name} World Cup history — all matches, results, goals and top scorers across every tournament appearance.`
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
openGraph: { title, description, url: `/teams/${slug}` },
|
||||
}
|
||||
}
|
||||
`, { variables: { teamId: team?.id ?? 0 }, skip: !team?.id })
|
||||
|
||||
const teamScorers = scorerData?.topScorers ?? []
|
||||
const teamMatches: MatchRow[] = matchesData?.matches ?? []
|
||||
|
||||
// Group matches by year for the history display
|
||||
const matchesByYear = teamMatches.reduce((acc: Record<number, MatchRow[]>, m) => {
|
||||
;(acc[m.year] ??= []).push(m)
|
||||
return acc
|
||||
}, {})
|
||||
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>
|
||||
}
|
||||
|
||||
if (!team) {
|
||||
return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Team not found.</div>
|
||||
}
|
||||
|
||||
const s = team.stats
|
||||
const played = (s?.wins ?? 0) + (s?.draws ?? 0) + (s?.losses ?? 0)
|
||||
const maxScorer = Math.max(...teamScorers.map((sc: { goals: number }) => sc.goals), 1)
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Hero */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
<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>
|
||||
<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>}
|
||||
{(s?.titles ?? 0) > 0 && (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] text-[#22c55e] 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>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_260px] gap-8">
|
||||
<div>
|
||||
{/* 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>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-3">
|
||||
{[
|
||||
{ label: 'Appearances', value: s.appearances },
|
||||
{ label: 'Matches', value: played },
|
||||
{ label: 'Win %', value: `${s.winPct}%` },
|
||||
{ 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>
|
||||
))}
|
||||
</div>
|
||||
<div className="glass-card rounded-xl">
|
||||
<div className="grid px-4 py-2.5 text-[9px] text-[#2a5c35] 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="flex items-center gap-2">
|
||||
<TeamFlag name={team.name} iso2={team.iso2} size="sm" />
|
||||
<span className="text-sm text-[#dff5e8]">{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 className="text-center text-sm text-[#4a7a55]">{s.goalDiff >= 0 ? `+${s.goalDiff}` : s.goalDiff}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 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>
|
||||
<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">
|
||||
{year}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 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>
|
||||
<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">
|
||||
{year}
|
||||
</Link>
|
||||
<div className="glass-card rounded-xl">
|
||||
{yMatches.map((m, i) => {
|
||||
const isHome = m.team1.name === team.name
|
||||
const opponent = isHome ? m.team2 : m.team1
|
||||
const ft = m.scoreFt
|
||||
const scoreEt = m.scoreEt
|
||||
const scoreP = m.scoreP
|
||||
// Winner: PSO first, then ET, then FT
|
||||
const decisive = scoreP ?? scoreEt ?? ft
|
||||
const myScore = decisive ? (isHome ? decisive[0] : decisive[1]) : null
|
||||
const theirScore = decisive ? (isHome ? decisive[1] : decisive[0]) : null
|
||||
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]'
|
||||
// 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)' }}>
|
||||
<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]">
|
||||
{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">
|
||||
{scoreP
|
||||
? `${isHome ? scoreP[0] : scoreP[1]}–${isHome ? scoreP[1] : scoreP[0]}`
|
||||
: displayScore
|
||||
? `${isHome ? displayScore[0] : displayScore[1]}–${isHome ? displayScore[1] : displayScore[0]}`
|
||||
: '–'}
|
||||
</div>
|
||||
{scoreP && ft && (
|
||||
<div className="text-[9px] text-[#2a5c35] 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>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sidebar: top scorers */}
|
||||
<div>
|
||||
{teamScorers.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-[11px] text-[#2a5c35] 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-1 min-w-0">
|
||||
<div className="text-[13px] font-semibold text-[#dff5e8] truncate">{sc.playerName}</div>
|
||||
<div className="text-[10px] text-[#2a5c35]">
|
||||
{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>
|
||||
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{sc.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
export default function TeamPage({ params }: Props) {
|
||||
return <TeamClient params={params} />
|
||||
}
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
import { LiveBadge } from '@/components/live-badge'
|
||||
|
||||
const TOURNAMENT_QUERY = gql`
|
||||
query Tournament($year: Int!) {
|
||||
tournament(year: $year) {
|
||||
year host winner runnerUp thirdPlace fourthPlace
|
||||
totalGoals matchesCount teamsCount avgGoalsPerGame
|
||||
topScorers(limit: 10) {
|
||||
playerName goals penalties ownGoals
|
||||
team { name iso2 slug }
|
||||
}
|
||||
matches {
|
||||
id year round group date time isLive isQualiPlayoff
|
||||
scoreFt scoreHt scoreEt scoreP
|
||||
team1 { id name iso2 slug } team2 { id name iso2 slug }
|
||||
goals { playerName minute minuteOffset isPenalty isOwnGoal team { id } }
|
||||
}
|
||||
}
|
||||
groupStandings(year: $year) {
|
||||
groupName pos played won drawn lost goalsFor goalsAgainst goalDiff pts
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface MatchData {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; time?: string | null; isLive: boolean; isQualiPlayoff: boolean
|
||||
scoreFt?: number[] | null; scoreHt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
team2: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
goals: Array<{ playerName: string; minute?: number | null; minuteOffset?: number | null; isPenalty: boolean; isOwnGoal: boolean; team: { id: number } }>
|
||||
}
|
||||
|
||||
interface Standing {
|
||||
groupName: string; pos?: number | null
|
||||
played: number; won: number; drawn: number; lost: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; pts: number
|
||||
team: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
}
|
||||
|
||||
function GoalList({ match }: { match: MatchData }) {
|
||||
if (!match.goals?.length) return null
|
||||
const t1Goals = match.goals.filter(g => !g.isOwnGoal ? g.team.id === match.team1.id : g.team.id !== match.team1.id)
|
||||
const t2Goals = match.goals.filter(g => !g.isOwnGoal ? g.team.id === match.team2.id : g.team.id !== match.team2.id)
|
||||
const renderGoal = (g: MatchData['goals'][0], i: number) => (
|
||||
<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-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-green-muted">
|
||||
<div className="text-left">{t1Goals.map(renderGoal)}</div>
|
||||
<div className="text-right">{t2Goals.map(renderGoal)}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function TournamentClient({ params }: { params: Promise<{ year: string }> }) {
|
||||
const { year: yearStr } = use(params)
|
||||
const year = parseInt(yearStr)
|
||||
const { data, loading } = useQuery(TOURNAMENT_QUERY, { variables: { year }, pollInterval: year === 2026 ? 60_000 : 0 })
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
const hash = window.location.hash
|
||||
if (!hash) return
|
||||
// double-rAF: first frame commits React's DOM, second frame lets the browser lay out
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
const el = document.getElementById(hash.slice(1))
|
||||
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}))
|
||||
}, [data])
|
||||
|
||||
|
||||
const t = data?.tournament
|
||||
const standings: Standing[] = data?.groupStandings ?? []
|
||||
const byGroup = standings.reduce<Record<string, Standing[]>>((acc, s) => {
|
||||
acc[s.groupName] = [...(acc[s.groupName] ?? []), s]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const allMatches: MatchData[] = t?.matches ?? []
|
||||
const byRound = allMatches.reduce<Record<string, MatchData[]>>((acc, m) => {
|
||||
const key = m.group ?? m.round
|
||||
acc[key] = [...(acc[key] ?? []), m]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// Union of groups from standings + groups from match data (handles groups with no played matches yet)
|
||||
const groupNames = new Set([
|
||||
...Object.keys(byGroup),
|
||||
...allMatches.filter(m => m.group).map(m => m.group!),
|
||||
])
|
||||
const groupRounds = [...groupNames].sort().map(g => [g, byGroup[g] ?? []] as [string, Standing[]])
|
||||
const koRounds = allMatches.filter(m => !m.group && !m.isQualiPlayoff)
|
||||
const koByRound = koRounds.reduce<Record<string, MatchData[]>>((acc, m) => {
|
||||
acc[m.round] = [...(acc[m.round] ?? []), m]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const liveMatches = allMatches.filter(m => m.isLive)
|
||||
const maxScorer = Math.max(...(t?.topScorers?.map((s: { goals: number }) => s.goals) ?? [1]), 1)
|
||||
|
||||
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 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-green-muted">Tournament {year} not found.</div>
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Header */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
{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-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-text">{t.winner}</div>
|
||||
{t.runnerUp && <div className="text-xs text-green-muted mt-1">def. {t.runnerUp}</div>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-6 mt-4 flex-wrap">
|
||||
{[
|
||||
{ label: 'Teams', value: t.teamsCount },
|
||||
{ label: 'Matches', value: t.matchesCount },
|
||||
{ label: 'Goals', value: t.totalGoals },
|
||||
{ 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-green-muted tracking-[0.12em] uppercase">{s.label}</div>
|
||||
<div className="font-['Bebas_Neue'] text-3xl text-green">{s.value}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_280px] gap-8">
|
||||
<div>
|
||||
{/* Live matches first */}
|
||||
{liveMatches.length > 0 && (
|
||||
<div className="mb-8">
|
||||
<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}`} className="scroll-mt-20">
|
||||
<MatchCard match={m} />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Group stage */}
|
||||
{groupRounds.length > 0 && (
|
||||
<div className="mb-8">
|
||||
<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) => {
|
||||
if (!a.date) return 1; if (!b.date) return -1
|
||||
const cmp = a.date.localeCompare(b.date)
|
||||
if (cmp !== 0) return cmp
|
||||
return (a.time ?? '').localeCompare(b.time ?? '')
|
||||
})
|
||||
return (
|
||||
<div key={groupName} className="mb-8">
|
||||
<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-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-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>
|
||||
))}
|
||||
</div>
|
||||
{/* Group matches */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{groupMatches.map(m => (
|
||||
<div key={m.id} id={`match-${m.id}`} className="scroll-mt-20">
|
||||
<MatchCard match={m} compact />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Knockout rounds */}
|
||||
{Object.keys(koByRound).length > 0 && (
|
||||
<div>
|
||||
<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-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}`} className="scroll-mt-20">
|
||||
<MatchCard match={m} compact />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sidebar: top scorers */}
|
||||
<div>
|
||||
<div className="sticky top-[76px]">
|
||||
<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-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-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 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-green flex-shrink-0">{s.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{t.thirdPlace && (
|
||||
<div className="glass-card mt-4 rounded-xl p-4">
|
||||
<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-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-green-mid">{t.fourthPlace}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+20
-275
@@ -1,281 +1,26 @@
|
||||
'use client'
|
||||
import { useQuery, gql } from '@/lib/graphql/hooks'
|
||||
import { use, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { TeamFlag } from '@/components/team-flag'
|
||||
import { MatchCard } from '@/components/match-card'
|
||||
import { LiveBadge } from '@/components/live-badge'
|
||||
import type { Metadata } from 'next'
|
||||
import { db } from '@/lib/db'
|
||||
import { tournaments } from '@/lib/db/schema'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { TournamentClient } from './client'
|
||||
|
||||
const TOURNAMENT_QUERY = gql`
|
||||
query Tournament($year: Int!) {
|
||||
tournament(year: $year) {
|
||||
year host winner runnerUp thirdPlace fourthPlace
|
||||
totalGoals matchesCount teamsCount avgGoalsPerGame
|
||||
topScorers(limit: 10) {
|
||||
playerName goals penalties ownGoals
|
||||
team { name iso2 slug }
|
||||
}
|
||||
matches {
|
||||
id year round group date time isLive isQualiPlayoff
|
||||
scoreFt scoreHt scoreEt scoreP
|
||||
team1 { id name iso2 slug } team2 { id name iso2 slug }
|
||||
goals { playerName minute minuteOffset isPenalty isOwnGoal team { id } }
|
||||
}
|
||||
}
|
||||
groupStandings(year: $year) {
|
||||
groupName pos played won drawn lost goalsFor goalsAgainst goalDiff pts
|
||||
team { id name iso2 slug }
|
||||
}
|
||||
}
|
||||
`
|
||||
type Props = { params: Promise<{ year: string }> }
|
||||
|
||||
interface MatchData {
|
||||
id: number; year: number; round: string; group?: string | null
|
||||
date?: string | null; time?: string | null; isLive: boolean; isQualiPlayoff: boolean
|
||||
scoreFt?: number[] | null; scoreHt?: number[] | null; scoreEt?: number[] | null; scoreP?: number[] | null
|
||||
team1: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
team2: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
goals: Array<{ playerName: string; minute?: number | null; minuteOffset?: number | null; isPenalty: boolean; isOwnGoal: boolean; team: { id: number } }>
|
||||
}
|
||||
|
||||
interface Standing {
|
||||
groupName: string; pos?: number | null
|
||||
played: number; won: number; drawn: number; lost: number
|
||||
goalsFor: number; goalsAgainst: number; goalDiff: number; pts: number
|
||||
team: { id: number; name: string; iso2?: string | null; slug: string }
|
||||
}
|
||||
|
||||
function GoalList({ match }: { match: MatchData }) {
|
||||
if (!match.goals?.length) return null
|
||||
const t1Goals = match.goals.filter(g => !g.isOwnGoal ? g.team.id === match.team1.id : g.team.id !== match.team1.id)
|
||||
const t2Goals = match.goals.filter(g => !g.isOwnGoal ? g.team.id === match.team2.id : g.team.id !== match.team2.id)
|
||||
const renderGoal = (g: MatchData['goals'][0], i: number) => (
|
||||
<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">
|
||||
{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="text-left">{t1Goals.map(renderGoal)}</div>
|
||||
<div className="text-right">{t2Goals.map(renderGoal)}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function TournamentPage({ params }: { params: Promise<{ year: string }> }) {
|
||||
const { year: yearStr } = use(params)
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { year: yearStr } = await params
|
||||
const year = parseInt(yearStr)
|
||||
const { data, loading } = useQuery(TOURNAMENT_QUERY, { variables: { year }, pollInterval: year === 2026 ? 60_000 : 0 })
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
const hash = window.location.hash
|
||||
if (!hash) return
|
||||
const el = document.getElementById(hash.slice(1))
|
||||
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}, [data])
|
||||
|
||||
useEffect(() => {
|
||||
document.title = data?.tournament
|
||||
? `${year} World Cup · World Cup`
|
||||
: `${year} · World Cup`
|
||||
}, [data, year])
|
||||
|
||||
const t = data?.tournament
|
||||
const standings: Standing[] = data?.groupStandings ?? []
|
||||
const byGroup = standings.reduce<Record<string, Standing[]>>((acc, s) => {
|
||||
acc[s.groupName] = [...(acc[s.groupName] ?? []), s]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const allMatches: MatchData[] = t?.matches ?? []
|
||||
const byRound = allMatches.reduce<Record<string, MatchData[]>>((acc, m) => {
|
||||
const key = m.group ?? m.round
|
||||
acc[key] = [...(acc[key] ?? []), m]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const groupRounds = Object.entries(byGroup).sort(([a], [b]) => a.localeCompare(b))
|
||||
const koRounds = allMatches.filter(m => !m.group && !m.isQualiPlayoff)
|
||||
const koByRound = koRounds.reduce<Record<string, MatchData[]>>((acc, m) => {
|
||||
acc[m.round] = [...(acc[m.round] ?? []), m]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const liveMatches = allMatches.filter(m => m.isLive)
|
||||
const maxScorer = Math.max(...(t?.topScorers?.map((s: { goals: number }) => s.goals) ?? [1]), 1)
|
||||
|
||||
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>
|
||||
)
|
||||
const [t] = await db.select().from(tournaments).where(eq(tournaments.year, year)).limit(1)
|
||||
const title = `${year} FIFA World Cup`
|
||||
const description = t
|
||||
? `${year} FIFA World Cup hosted by ${t.host}.${t.winner ? ` Winner: ${t.winner}.` : ''} Matches, scores, group standings and statistics.`
|
||||
: `${year} FIFA World Cup — matches, scores and statistics.`
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
openGraph: { title, description, url: `/tournaments/${year}` },
|
||||
}
|
||||
}
|
||||
|
||||
if (!t) return <div className="max-w-[1200px] mx-auto px-7 py-10 text-[#2a5c35]">Tournament {year} not found.</div>
|
||||
|
||||
return (
|
||||
<div className="max-w-[1200px] mx-auto px-7 py-10 pb-16">
|
||||
{/* Header */}
|
||||
<div className="pitch-grid glass-card-hero rounded-2xl p-8 mb-8">
|
||||
{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>
|
||||
</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>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-6 mt-4 flex-wrap">
|
||||
{[
|
||||
{ label: 'Teams', value: t.teamsCount },
|
||||
{ label: 'Matches', value: t.matchesCount },
|
||||
{ label: 'Goals', value: t.totalGoals },
|
||||
{ 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>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_280px] gap-8">
|
||||
<div>
|
||||
{/* Live matches first */}
|
||||
{liveMatches.length > 0 && (
|
||||
<div className="mb-8">
|
||||
<h2 className="font-['Bebas_Neue'] text-2xl text-[#4ade80] mb-4">LIVE</h2>
|
||||
<div className="flex flex-col gap-4">
|
||||
{liveMatches.map(m => (
|
||||
<div key={m.id} id={`match-${m.id}`}>
|
||||
<MatchCard match={m} />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Group stage */}
|
||||
{groupRounds.length > 0 && (
|
||||
<div className="mb-8">
|
||||
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] 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>
|
||||
{/* 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 }}>
|
||||
<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>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
{/* Group matches */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{groupMatches.map(m => (
|
||||
<div key={m.id} id={`match-${m.id}`}>
|
||||
<MatchCard match={m} compact />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Knockout rounds */}
|
||||
{Object.keys(koByRound).length > 0 && (
|
||||
<div>
|
||||
<h2 className="font-['Bebas_Neue'] text-2xl text-[#22c55e] 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>
|
||||
<div className="flex flex-col gap-3">
|
||||
{roundMatches.map(m => (
|
||||
<div key={m.id} id={`match-${m.id}`}>
|
||||
<MatchCard match={m} compact />
|
||||
<GoalList match={m} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sidebar: top scorers */}
|
||||
<div>
|
||||
<div className="sticky top-[76px]">
|
||||
<h2 className="font-['Bebas_Neue'] text-xl text-[#22c55e] 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>
|
||||
{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>
|
||||
<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>
|
||||
<span className="font-['Bebas_Neue'] text-xl text-[#22c55e] flex-shrink-0">{s.goals}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{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="flex items-center gap-2">
|
||||
<TeamFlag name={t.thirdPlace} size="sm" />
|
||||
<span className="text-sm text-[#6abf7a]">{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>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
export default function TournamentPage({ params }: Props) {
|
||||
return <TournamentClient params={params} />
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
+18
-18
@@ -32,45 +32,45 @@ 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]}`
|
||||
: match.scoreEt
|
||||
? `${match.scoreEt[0]} – ${match.scoreEt[1]}`
|
||||
: `${ft![0]} – ${ft![1]}`
|
||||
: match.isLive ? <LiveBadge label="•" /> : '–'}
|
||||
: match.isLive ? '0 – 0' : '–'}
|
||||
</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,37 +80,37 @@ 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]}`
|
||||
: match.scoreEt
|
||||
? `${match.scoreEt[0]}–${match.scoreEt[1]}`
|
||||
: `${ft![0]}–${ft![1]}`
|
||||
: '?–?'}
|
||||
: match.isLive ? '0–0' : '?–?'}
|
||||
</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
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -15,25 +15,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "L. Laurent",
|
||||
"name": "Lucien Laurent",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Langiller",
|
||||
"name": "Marcel Langiller",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Maschinot",
|
||||
"name": "André Maschinot",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Maschinot",
|
||||
"name": "André Maschinot",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Carreño",
|
||||
"name": "Juan Carreño",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
@@ -54,7 +54,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Monti",
|
||||
"name": "Luis Monti",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -75,15 +75,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vidal",
|
||||
"name": "Carlos Vidal",
|
||||
"minute": 3
|
||||
},
|
||||
{
|
||||
"name": "Vidal",
|
||||
"name": "Carlos Vidal",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "M. Rosas",
|
||||
"name": "Manuel Rosas",
|
||||
"minute": 52,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -105,7 +105,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Subiabre",
|
||||
"name": "Guillermo Subiabre",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -126,42 +126,42 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Zumelzú",
|
||||
"name": "Adolfo Zumelzú",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Zumelzú",
|
||||
"name": "Adolfo Zumelzú",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Varallo",
|
||||
"name": "Francisco Varallo",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "M. Rosas",
|
||||
"name": "Manuel Rosas",
|
||||
"minute": 42,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "M. Rosas",
|
||||
"name": "Manuel Rosas",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Gayón",
|
||||
"name": "Roberto Gayón",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -182,21 +182,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "M. Evaristo",
|
||||
"name": "Mario Evaristo",
|
||||
"minute": 51
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Subiabre",
|
||||
"name": "Guillermo Subiabre",
|
||||
"minute": 15
|
||||
}
|
||||
],
|
||||
@@ -217,11 +217,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Tirnanić",
|
||||
"name": "Aleksandar Tirnanić",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Bek",
|
||||
"name": "Ivan Bek",
|
||||
"minute": 30
|
||||
}
|
||||
],
|
||||
@@ -248,19 +248,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bek",
|
||||
"name": "Ivan Bek",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Bek",
|
||||
"name": "Ivan Bek",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Marjanović",
|
||||
"name": "Blagoje Marjanović",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Vujadinović",
|
||||
"name": "Đorđe Vujadinović",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -281,11 +281,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Moderato",
|
||||
"name": "Moderato Wisintainer",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Moderato",
|
||||
"name": "Moderato Wisintainer",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
@@ -314,21 +314,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Deșu",
|
||||
"name": "Adalbert Deșu",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Stanciu",
|
||||
"name": "Constantin Stanciu",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
"name": "Kovács",
|
||||
"name": "Miklós Kovács",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "De Souza",
|
||||
"name": "Luis de Souza",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -349,7 +349,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Castro",
|
||||
"name": "Héctor Castro",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -370,19 +370,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dorado",
|
||||
"name": "Pablo Dorado",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Scarone",
|
||||
"name": "Héctor Scarone",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Anselmo",
|
||||
"name": "Peregrino Anselmo",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Cea",
|
||||
"name": "Pedro Cea",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -403,15 +403,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "McGhee",
|
||||
"name": "Bart McGhee",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Florie",
|
||||
"name": "Tom Florie",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "Patenaude",
|
||||
"name": "Bert Patenaude",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -432,15 +432,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Patenaude",
|
||||
"name": "Bert Patenaude",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Patenaude",
|
||||
"name": "Bert Patenaude",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Patenaude",
|
||||
"name": "Bert Patenaude",
|
||||
"minute": 50
|
||||
}
|
||||
],
|
||||
@@ -461,7 +461,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vargas Peña",
|
||||
"name": "Luis Vargas Peña",
|
||||
"minute": 40
|
||||
}
|
||||
],
|
||||
@@ -481,33 +481,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Monti",
|
||||
"name": "Luis Monti",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Scopelli",
|
||||
"name": "Alejandro Scopelli",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 87
|
||||
},
|
||||
{
|
||||
"name": "Peucelle",
|
||||
"name": "Carlos Peucelle",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Peucelle",
|
||||
"name": "Carlos Peucelle",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brown",
|
||||
"name": "Jim Brown",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -527,33 +527,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cea",
|
||||
"name": "Pedro Cea",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Cea",
|
||||
"name": "Pedro Cea",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Cea",
|
||||
"name": "Pedro Cea",
|
||||
"minute": 72
|
||||
},
|
||||
{
|
||||
"name": "Anselmo",
|
||||
"name": "Peregrino Anselmo",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Anselmo",
|
||||
"name": "Peregrino Anselmo",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Iriarte",
|
||||
"name": "Santos Iriarte",
|
||||
"minute": 61
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Vujadinović",
|
||||
"name": "Đorđe Vujadinović",
|
||||
"minute": 4
|
||||
}
|
||||
],
|
||||
@@ -573,29 +573,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dorado",
|
||||
"name": "Pablo Dorado",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Cea",
|
||||
"name": "Pedro Cea",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Iriarte",
|
||||
"name": "Santos Iriarte",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Castro",
|
||||
"name": "Héctor Castro",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Peucelle",
|
||||
"name": "Carlos Peucelle",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Stábile",
|
||||
"name": "Guillermo Stábile",
|
||||
"minute": 37
|
||||
}
|
||||
],
|
||||
@@ -14,16 +14,16 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Iraragorri",
|
||||
"name": "José Iraragorri",
|
||||
"minute": 18,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Iraragorri",
|
||||
"name": "José Iraragorri",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Lángara",
|
||||
"name": "Isidro Lángara",
|
||||
"minute": 29
|
||||
}
|
||||
],
|
||||
@@ -49,29 +49,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Teleki",
|
||||
"name": "Pál Teleki",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Toldi",
|
||||
"name": "Géza Toldi",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Toldi",
|
||||
"name": "Géza Toldi",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "Vincze",
|
||||
"name": "Jenő Vincze",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fawzi",
|
||||
"name": "Abdulrahman Fawzi",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Fawzi",
|
||||
"name": "Abdulrahman Fawzi",
|
||||
"minute": 39
|
||||
}
|
||||
],
|
||||
@@ -91,25 +91,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kielholz",
|
||||
"name": "Leopold Kielholz",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Kielholz",
|
||||
"name": "Leopold Kielholz",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Abegglen",
|
||||
"name": "André Abegglen",
|
||||
"minute": 66
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Smit",
|
||||
"name": "Kick Smit",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Vente",
|
||||
"name": "Leen Vente",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -129,37 +129,37 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schiavio",
|
||||
"name": "Angelo Schiavio",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Schiavio",
|
||||
"name": "Angelo Schiavio",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Schiavio",
|
||||
"name": "Angelo Schiavio",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Orsi",
|
||||
"name": "Raimundo Orsi",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Orsi",
|
||||
"name": "Raimundo Orsi",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Ferrari",
|
||||
"name": "Giovanni Ferrari",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Meazza",
|
||||
"name": "Giuseppe Meazza",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Donelli",
|
||||
"name": "Aldo Donelli",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -179,17 +179,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Puč",
|
||||
"name": "Antonín Puč",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dobay",
|
||||
"name": "Ștefan Dobay",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -209,25 +209,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Jonasson",
|
||||
"name": "Sven Jonasson",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Jonasson",
|
||||
"name": "Sven Jonasson",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Kroon",
|
||||
"name": "Knut Kroon",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Belis",
|
||||
"name": "Ernesto Belis",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Galateo",
|
||||
"name": "Alberto Galateo",
|
||||
"minute": 48
|
||||
}
|
||||
],
|
||||
@@ -251,25 +251,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sindelar",
|
||||
"name": "Matthias Sindelar",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Schall",
|
||||
"name": "Anton Schall",
|
||||
"minute": 93
|
||||
},
|
||||
{
|
||||
"name": "Bican",
|
||||
"name": "Josef Bican",
|
||||
"minute": 109
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nicolas",
|
||||
"name": "Jean Nicolas",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Verriest",
|
||||
"name": "Georges Verriest",
|
||||
"minute": 116,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -290,33 +290,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kobierski",
|
||||
"name": "Stanislaus Kobierski",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Siffling",
|
||||
"name": "Otto Siffling",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Conen",
|
||||
"name": "Edmund Conen",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Conen",
|
||||
"name": "Edmund Conen",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Conen",
|
||||
"name": "Edmund Conen",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Voorhoof",
|
||||
"name": "Bernard Voorhoof",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Voorhoof",
|
||||
"name": "Bernard Voorhoof",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -336,17 +336,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Horvath",
|
||||
"name": "Johann Horvath",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Zischek",
|
||||
"name": "Karl Zischek",
|
||||
"minute": 51
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 60,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -371,13 +371,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ferrari",
|
||||
"name": "Giovanni Ferrari",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Regueiro",
|
||||
"name": "Luis Regueiro",
|
||||
"minute": 30
|
||||
}
|
||||
],
|
||||
@@ -397,17 +397,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hohmann",
|
||||
"name": "Karl Hohmann",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Hohmann",
|
||||
"name": "Karl Hohmann",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dunker",
|
||||
"name": "Gösta Dunker",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -427,25 +427,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Svoboda",
|
||||
"name": "František Svoboda",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Sobotka",
|
||||
"name": "Jiří Sobotka",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Kielholz",
|
||||
"name": "Leopold Kielholz",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Jäggi",
|
||||
"name": "Willy Jäggi",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
@@ -465,7 +465,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Meazza",
|
||||
"name": "Giuseppe Meazza",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -485,7 +485,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Guaita",
|
||||
"name": "Enrique Guaita",
|
||||
"minute": 19
|
||||
}
|
||||
],
|
||||
@@ -505,21 +505,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Noack",
|
||||
"name": "Rudolf Noack",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -539,25 +539,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lehner",
|
||||
"name": "Ernst Lehner",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Lehner",
|
||||
"name": "Ernst Lehner",
|
||||
"minute": 42
|
||||
},
|
||||
{
|
||||
"name": "Conen",
|
||||
"name": "Edmund Conen",
|
||||
"minute": 27
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Horvath",
|
||||
"name": "Johann Horvath",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Sesta",
|
||||
"name": "Karl Sesta",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
@@ -581,17 +581,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Orsi",
|
||||
"name": "Raimundo Orsi",
|
||||
"minute": 81
|
||||
},
|
||||
{
|
||||
"name": "Schiavio",
|
||||
"name": "Angelo Schiavio",
|
||||
"minute": 95
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Puč",
|
||||
"name": "Antonín Puč",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
@@ -18,13 +18,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Abegglen",
|
||||
"name": "André Abegglen",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Gauchel",
|
||||
"name": "Josef Gauchel",
|
||||
"minute": 29
|
||||
}
|
||||
],
|
||||
@@ -44,27 +44,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kohut",
|
||||
"name": "Vilmos Kohut",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "Toldi",
|
||||
"name": "Géza Toldi",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "G. Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "G. Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 89
|
||||
},
|
||||
{
|
||||
"name": "Zsengellér",
|
||||
"name": "Gyula Zsengellér",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Zsengellér",
|
||||
"name": "Gyula Zsengellér",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -95,29 +95,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Socorro",
|
||||
"name": "Héctor Socorro",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Socorro",
|
||||
"name": "Héctor Socorro",
|
||||
"minute": 103
|
||||
},
|
||||
{
|
||||
"name": "Magriñá",
|
||||
"name": "José Magriñá",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bindea",
|
||||
"name": "Silviu Bindea",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Barátky",
|
||||
"name": "Iuliu Barátky",
|
||||
"minute": 88
|
||||
},
|
||||
{
|
||||
"name": "Dobay",
|
||||
"name": "Ștefan Dobay",
|
||||
"minute": 105
|
||||
}
|
||||
],
|
||||
@@ -137,21 +137,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Veinante",
|
||||
"name": "Émile Veinante",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Nicolas",
|
||||
"name": "Jean Nicolas",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Nicolas",
|
||||
"name": "Jean Nicolas",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Isemborghs",
|
||||
"name": "Hendrik Isemborghs",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -175,17 +175,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ferraris",
|
||||
"name": "Pietro Ferraris",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Piola",
|
||||
"name": "Silvio Piola",
|
||||
"minute": 94
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brustad",
|
||||
"name": "Arne Brustad",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -209,50 +209,50 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 93
|
||||
},
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 104
|
||||
},
|
||||
{
|
||||
"name": "Romeu",
|
||||
"name": "Romeu Pellicciari",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Perácio",
|
||||
"name": "José Perácio",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Perácio",
|
||||
"name": "José Perácio",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Scherfke",
|
||||
"name": "Friedrich Scherfke",
|
||||
"minute": 23,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Wilimowski",
|
||||
"name": "Ernst Wilimowski",
|
||||
"minute": 53
|
||||
},
|
||||
{
|
||||
"name": "Wilimowski",
|
||||
"name": "Ernst Wilimowski",
|
||||
"minute": 59
|
||||
},
|
||||
{
|
||||
"name": "Wilimowski",
|
||||
"name": "Ernst Wilimowski",
|
||||
"minute": 89
|
||||
},
|
||||
{
|
||||
"name": "Wilimowski",
|
||||
"name": "Ernst Wilimowski",
|
||||
"minute": 118
|
||||
}
|
||||
],
|
||||
@@ -276,15 +276,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Košťálek",
|
||||
"name": "Josef Košťálek",
|
||||
"minute": 96
|
||||
},
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 111
|
||||
},
|
||||
{
|
||||
"name": "Zeman",
|
||||
"name": "Josef Zeman",
|
||||
"minute": 118
|
||||
}
|
||||
],
|
||||
@@ -304,29 +304,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Walaschek",
|
||||
"name": "Eugen Walaschek",
|
||||
"minute": 42
|
||||
},
|
||||
{
|
||||
"name": "Bickel",
|
||||
"name": "Alfred Bickel",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Abegglen",
|
||||
"name": "André Abegglen",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Abegglen",
|
||||
"name": "André Abegglen",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hahnemann",
|
||||
"name": "Wilhelm Hahnemann",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Lörtscher",
|
||||
"name": "Ernst Lörtscher",
|
||||
"minute": 22,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -347,17 +347,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Socorro",
|
||||
"name": "Héctor Socorro",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Fernández",
|
||||
"name": "Tomás Fernández",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dobay",
|
||||
"name": "Ștefan Dobay",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -377,11 +377,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "G. Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Zsengellér",
|
||||
"name": "Gyula Zsengellér",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -401,35 +401,35 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "H. Andersson",
|
||||
"name": "Harry Andersson",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "H. Andersson",
|
||||
"name": "Harry Andersson",
|
||||
"minute": 81
|
||||
},
|
||||
{
|
||||
"name": "H. Andersson",
|
||||
"name": "Harry Andersson",
|
||||
"minute": 89
|
||||
},
|
||||
{
|
||||
"name": "Wetterström",
|
||||
"name": "Gustav Wetterström",
|
||||
"minute": 22
|
||||
},
|
||||
{
|
||||
"name": "Wetterström",
|
||||
"name": "Gustav Wetterström",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Wetterström",
|
||||
"name": "Gustav Wetterström",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Keller",
|
||||
"name": "Tore Keller",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Nyberg",
|
||||
"name": "Arne Nyberg",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -449,21 +449,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Colaussi",
|
||||
"name": "Gino Colaussi",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Piola",
|
||||
"name": "Silvio Piola",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Piola",
|
||||
"name": "Silvio Piola",
|
||||
"minute": 72
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Heisserer",
|
||||
"name": "Oscar Heisserer",
|
||||
"minute": 10
|
||||
}
|
||||
],
|
||||
@@ -487,13 +487,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 30
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nejedlý",
|
||||
"name": "Oldřich Nejedlý",
|
||||
"minute": 65,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -514,17 +514,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Roberto",
|
||||
"name": "Roberto Emílio da Cunha",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Kopecký",
|
||||
"name": "Vlastimil Kopecký",
|
||||
"minute": 25
|
||||
}
|
||||
],
|
||||
@@ -544,30 +544,30 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Jacobsson",
|
||||
"name": "Sven Jacobsson",
|
||||
"minute": 19,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Titkos",
|
||||
"name": "Pál Titkos",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Zsengellér",
|
||||
"name": "Gyula Zsengellér",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Zsengellér",
|
||||
"name": "Gyula Zsengellér",
|
||||
"minute": 85
|
||||
},
|
||||
{
|
||||
"name": "G. Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nyberg",
|
||||
"name": "Arne Nyberg",
|
||||
"minute": 1
|
||||
}
|
||||
],
|
||||
@@ -587,18 +587,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Colaussi",
|
||||
"name": "Gino Colaussi",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Meazza",
|
||||
"name": "Giuseppe Meazza",
|
||||
"minute": 60,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Romeu",
|
||||
"name": "Romeu Pellicciari",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
@@ -618,29 +618,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Romeu",
|
||||
"name": "Romeu Pellicciari",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Leônidas",
|
||||
"name": "Leônidas da Silva",
|
||||
"minute": 74
|
||||
},
|
||||
{
|
||||
"name": "Perácio",
|
||||
"name": "José Perácio",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jonasson",
|
||||
"name": "Sven Jonasson",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Nyberg",
|
||||
"name": "Arne Nyberg",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -660,29 +660,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Colaussi",
|
||||
"name": "Gino Colaussi",
|
||||
"minute": 6
|
||||
},
|
||||
{
|
||||
"name": "Colaussi",
|
||||
"name": "Gino Colaussi",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Piola",
|
||||
"name": "Silvio Piola",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Piola",
|
||||
"name": "Silvio Piola",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Titkos",
|
||||
"name": "Pál Titkos",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "G. Sárosi",
|
||||
"name": "György Sárosi",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
@@ -15,15 +15,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
"name": "Jair",
|
||||
"name": "Jair da Rosa Pinto",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
@@ -48,15 +48,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mitić",
|
||||
"name": "Rajko Mitić",
|
||||
"minute": 59
|
||||
},
|
||||
{
|
||||
"name": "Tomašević",
|
||||
"name": "Kosta Tomašević",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Ognjanov",
|
||||
"name": "Tihomir Ognjanov",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -77,7 +77,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Alfredo",
|
||||
"name": "Alfredo dos Santos",
|
||||
"minute": 3
|
||||
},
|
||||
{
|
||||
@@ -87,11 +87,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fatton",
|
||||
"name": "Jacques Fatton",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Fatton",
|
||||
"name": "Jacques Fatton",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -112,25 +112,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bobek",
|
||||
"name": "Stjepan Bobek",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Ž. Čajkovski",
|
||||
"name": "Željko Čajkovski",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Ž. Čajkovski",
|
||||
"name": "Željko Čajkovski",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Tomašević",
|
||||
"name": "Kosta Tomašević",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ortiz",
|
||||
"name": "Héctor Ortiz",
|
||||
"minute": 89,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -152,11 +152,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Zizinho",
|
||||
"name": "Thomaz Soares da Silva",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -177,17 +177,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bader",
|
||||
"name": "René Bader",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Antenen",
|
||||
"name": "Charles Antenen",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Casarín",
|
||||
"name": "Horacio Casarín",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -208,11 +208,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mortensen",
|
||||
"name": "Stan Mortensen",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Mannion",
|
||||
"name": "Wilf Mannion",
|
||||
"minute": 51
|
||||
}
|
||||
],
|
||||
@@ -233,21 +233,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Igoa",
|
||||
"name": "Silvestre Igoa",
|
||||
"minute": 81
|
||||
},
|
||||
{
|
||||
"name": "Basora",
|
||||
"name": "Estanislau Basora",
|
||||
"minute": 83
|
||||
},
|
||||
{
|
||||
"name": "Zarra",
|
||||
"name": "Telmo Zarra",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Pariani",
|
||||
"name": "Gino Pariani",
|
||||
"minute": 17
|
||||
}
|
||||
],
|
||||
@@ -268,11 +268,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Basora",
|
||||
"name": "Estanislau Basora",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Zarra",
|
||||
"name": "Telmo Zarra",
|
||||
"minute": 30
|
||||
}
|
||||
],
|
||||
@@ -293,7 +293,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Gaetjens",
|
||||
"name": "Joe Gaetjens",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -314,7 +314,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Zarra",
|
||||
"name": "Telmo Zarra",
|
||||
"minute": 48
|
||||
}
|
||||
],
|
||||
@@ -335,33 +335,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Robledo",
|
||||
"name": "George Robledo",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Cremaschi",
|
||||
"name": "Atilio Cremaschi",
|
||||
"minute": 32
|
||||
},
|
||||
{
|
||||
"name": "Cremaschi",
|
||||
"name": "Atilio Cremaschi",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Prieto",
|
||||
"name": "Andrés Prieto",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Riera",
|
||||
"name": "Fernando Riera",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Wallace",
|
||||
"name": "Frank Wallace",
|
||||
"minute": 47
|
||||
},
|
||||
{
|
||||
"name": "Maca",
|
||||
"name": "Joe Maca",
|
||||
"minute": 48,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -383,25 +383,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Jeppson",
|
||||
"name": "Hasse Jeppson",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Jeppson",
|
||||
"name": "Hasse Jeppson",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Andersson",
|
||||
"name": "Sune Andersson",
|
||||
"minute": 33
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Carapellese",
|
||||
"name": "Riccardo Carapellese",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Muccinelli",
|
||||
"name": "Ermes Muccinelli",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -422,21 +422,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sundqvist",
|
||||
"name": "Stig Sundqvist",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Palmér",
|
||||
"name": "Karl-Erik Palmér",
|
||||
"minute": 26
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "López",
|
||||
"name": "Atilio López",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "López Fretes",
|
||||
"name": "César López Fretes",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -457,11 +457,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Carapellese",
|
||||
"name": "Riccardo Carapellese",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Pandolfini",
|
||||
"name": "Egisto Pandolfini",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -482,35 +482,35 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Vidal",
|
||||
"name": "Ernesto Vidal",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Schiaffino",
|
||||
"name": "Juan Alberto Schiaffino",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Schiaffino",
|
||||
"name": "Juan Alberto Schiaffino",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Pérez",
|
||||
"name": "Julio Pérez",
|
||||
"minute": 83
|
||||
},
|
||||
{
|
||||
"name": "Ghiggia",
|
||||
"name": "Alcides Ghiggia",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
@@ -530,21 +530,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ghiggia",
|
||||
"name": "Alcides Ghiggia",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Varela",
|
||||
"name": "Obdulio Varela",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Basora",
|
||||
"name": "Estanislau Basora",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Basora",
|
||||
"name": "Estanislau Basora",
|
||||
"minute": 39
|
||||
}
|
||||
],
|
||||
@@ -564,27 +564,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 36
|
||||
},
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir Marques de Menezes",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Chico",
|
||||
"name": "Francisco Aramburu",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Chico",
|
||||
"name": "Francisco Aramburu",
|
||||
"minute": 88
|
||||
},
|
||||
{
|
||||
@@ -594,7 +594,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Andersson",
|
||||
"name": "Sune Andersson",
|
||||
"minute": 67,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -615,33 +615,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir de Menezes",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Ademir",
|
||||
"name": "Ademir de Menezes",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Jair",
|
||||
"name": "Jair da Rosa Pinto",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Chico",
|
||||
"name": "Francisco Aramburu",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Chico",
|
||||
"name": "Francisco Aramburu",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Zizinho",
|
||||
"name": "Thomaz Soares da Silva",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Igoa",
|
||||
"name": "Silvestre Igoa",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
@@ -661,25 +661,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ghiggia",
|
||||
"name": "Alcides Ghiggia",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 77
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Palmér",
|
||||
"name": "Karl-Erik Palmér",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Sundqvist",
|
||||
"name": "Stig Sundqvist",
|
||||
"minute": 40
|
||||
}
|
||||
],
|
||||
@@ -699,21 +699,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sundqvist",
|
||||
"name": "Stig Sundqvist",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Mellberg",
|
||||
"name": "Bror Mellberg",
|
||||
"minute": 33
|
||||
},
|
||||
{
|
||||
"name": "Palmér",
|
||||
"name": "Karl-Erik Palmér",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zarra",
|
||||
"name": "Telmo Zarra",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -733,11 +733,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schiaffino",
|
||||
"name": "Juan Alberto Schiaffino",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Ghiggia",
|
||||
"name": "Alcides Ghiggia",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"name": "Group 2",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Turkey",
|
||||
"Hungary",
|
||||
"South Korea"
|
||||
@@ -52,7 +52,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Milutinović",
|
||||
"name": "Miloš Milutinović",
|
||||
"minute": 15
|
||||
}
|
||||
],
|
||||
@@ -83,7 +83,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zebec",
|
||||
"name": "Branko Zebec",
|
||||
"minute": 48
|
||||
}
|
||||
],
|
||||
@@ -104,27 +104,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vincent",
|
||||
"name": "Jean Vincent",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Cárdenas",
|
||||
"name": "Raúl Cárdenas",
|
||||
"minute": 46,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Kopa",
|
||||
"name": "Raymond Kopa",
|
||||
"minute": 88,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lamadrid",
|
||||
"name": "José Luis Lamadrid",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Balcázar",
|
||||
"name": "Tomás Balcázar",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -135,7 +135,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1954-06-17",
|
||||
"time": "18:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Turkey",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -145,25 +145,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Klodt",
|
||||
"name": "Bernhard Klodt",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "O. Walter",
|
||||
"name": "Ottmar Walter",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Mamat",
|
||||
"name": "Suat Mamat",
|
||||
"minute": 2
|
||||
}
|
||||
],
|
||||
@@ -184,39 +184,39 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Puskás",
|
||||
"name": "Ferenc Puskás",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Puskás",
|
||||
"name": "Ferenc Puskás",
|
||||
"minute": 89
|
||||
},
|
||||
{
|
||||
"name": "Lantos",
|
||||
"name": "Mihály Lantos",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 36
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Czibor",
|
||||
"name": "Zoltán Czibor",
|
||||
"minute": 59
|
||||
},
|
||||
{
|
||||
"name": "Palotás",
|
||||
"name": "Péter Palotás",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Palotás",
|
||||
"name": "Péter Palotás",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -228,7 +228,7 @@
|
||||
"date": "1954-06-20",
|
||||
"time": "16:50",
|
||||
"team1": "Hungary",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
8,
|
||||
@@ -237,49 +237,49 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 3
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 78
|
||||
},
|
||||
{
|
||||
"name": "Puskás",
|
||||
"name": "Ferenc Puskás",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Hidegkuti",
|
||||
"name": "Nándor Hidegkuti",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Hidegkuti",
|
||||
"name": "Nándor Hidegkuti",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "J. Tóth",
|
||||
"name": "József Tóth",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Pfaff",
|
||||
"name": "Alfred Pfaff",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 77
|
||||
},
|
||||
{
|
||||
"name": "Herrmann",
|
||||
"name": "Richard Herrmann",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -300,31 +300,31 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mamat",
|
||||
"name": "Suat Mamat",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Mamat",
|
||||
"name": "Suat Mamat",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Küçükandonyadis",
|
||||
"name": "Lefter Küçükandonyadis",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Sargun",
|
||||
"name": "Burhan Sargun",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Sargun",
|
||||
"name": "Burhan Sargun",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Sargun",
|
||||
"name": "Burhan Sargun",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Keskin",
|
||||
"name": "Erol Keskin",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -335,7 +335,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1954-06-23",
|
||||
"time": "18:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Turkey",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -345,41 +345,41 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "O. Walter",
|
||||
"name": "Ottmar Walter",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 77
|
||||
},
|
||||
{
|
||||
"name": "F. Walter",
|
||||
"name": "Fritz Walter",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ertan",
|
||||
"name": "Mustafa Ertan",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Lefter",
|
||||
"name": "Lefter Küçükandonyadis",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -400,11 +400,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "Schiaffino",
|
||||
"name": "Juan Alberto Schiaffino",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -425,7 +425,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 33
|
||||
}
|
||||
],
|
||||
@@ -446,31 +446,31 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Borges",
|
||||
"name": "Carlos Borges",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Borges",
|
||||
"name": "Carlos Borges",
|
||||
"minute": 47
|
||||
},
|
||||
{
|
||||
"name": "Borges",
|
||||
"name": "Carlos Borges",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Míguez",
|
||||
"name": "Óscar Míguez",
|
||||
"minute": 83
|
||||
},
|
||||
{
|
||||
"name": "Abbadie",
|
||||
"name": "Julio Abbadie",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Abbadie",
|
||||
"name": "Julio Abbadie",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -491,23 +491,23 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Stojaspal",
|
||||
"name": "Ernst Stojaspal",
|
||||
"minute": 3
|
||||
},
|
||||
{
|
||||
"name": "Stojaspal",
|
||||
"name": "Ernst Stojaspal",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 24
|
||||
}
|
||||
],
|
||||
@@ -528,17 +528,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ballaman",
|
||||
"name": "Robert Ballaman",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Boniperti",
|
||||
"name": "Giampiero Boniperti",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
@@ -563,37 +563,37 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Broadis",
|
||||
"name": "Ivor Broadis",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Broadis",
|
||||
"name": "Ivor Broadis",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Lofthouse",
|
||||
"name": "Nat Lofthouse",
|
||||
"minute": 36
|
||||
},
|
||||
{
|
||||
"name": "Lofthouse",
|
||||
"name": "Nat Lofthouse",
|
||||
"minute": 91
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Anoul",
|
||||
"name": "Léopold Anoul",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Anoul",
|
||||
"name": "Léopold Anoul",
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "Coppens",
|
||||
"name": "Henri Coppens",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Dickinson",
|
||||
"name": "Jimmy Dickinson",
|
||||
"minute": 94,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -615,26 +615,26 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Pandolfini",
|
||||
"name": "Egisto Pandolfini",
|
||||
"minute": 41,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Galli",
|
||||
"name": "Carlo Galli",
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Frignani",
|
||||
"name": "Amleto Frignani",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Lorenzi",
|
||||
"name": "Benito Lorenzi",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Anoul",
|
||||
"name": "Léopold Anoul",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -655,11 +655,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mullen",
|
||||
"name": "Jimmy Mullen",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Wilshaw",
|
||||
"name": "Dennis Wilshaw",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -680,25 +680,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 85
|
||||
},
|
||||
{
|
||||
"name": "Ballaman",
|
||||
"name": "Robert Ballaman",
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Fatton",
|
||||
"name": "Jacques Fatton",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nesti",
|
||||
"name": "Fulvio Nesti",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -718,53 +718,53 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Wagner",
|
||||
"name": "Theodor Wagner",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Wagner",
|
||||
"name": "Theodor Wagner",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Wagner",
|
||||
"name": "Theodor Wagner",
|
||||
"minute": 53
|
||||
},
|
||||
{
|
||||
"name": "A. Körner",
|
||||
"name": "Alfred Körner",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "A. Körner",
|
||||
"name": "Alfred Körner",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Ocwirk",
|
||||
"name": "Ernst Ocwirk",
|
||||
"minute": 32
|
||||
},
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ballaman",
|
||||
"name": "Robert Ballaman",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Ballaman",
|
||||
"name": "Robert Ballaman",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Hügi",
|
||||
"name": "Josef Hügi",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
@@ -784,29 +784,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Borges",
|
||||
"name": "Carlos Borges",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Varela",
|
||||
"name": "Obdulio Varela",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Schiaffino",
|
||||
"name": "Juan Alberto Schiaffino",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Ambrois",
|
||||
"name": "Javier Ambrois",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lofthouse",
|
||||
"name": "Nat Lofthouse",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Finney",
|
||||
"name": "Tom Finney",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -816,7 +816,7 @@
|
||||
"round": "Quarter-finals",
|
||||
"date": "1954-06-27",
|
||||
"time": "17:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Yugoslavia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -826,12 +826,12 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Horvat",
|
||||
"name": "Ivica Horvat",
|
||||
"minute": 9,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -851,19 +851,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hidegkuti",
|
||||
"name": "Nándor Hidegkuti",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 88
|
||||
},
|
||||
{
|
||||
"name": "Lantos",
|
||||
"name": "Mihály Lantos",
|
||||
"minute": 60,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -875,7 +875,7 @@
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Julinho",
|
||||
"name": "Júlio Botelho",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -885,7 +885,7 @@
|
||||
"round": "Semi-finals",
|
||||
"date": "1954-06-30",
|
||||
"time": "18:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Austria",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -895,35 +895,35 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 47
|
||||
},
|
||||
{
|
||||
"name": "F. Walter",
|
||||
"name": "Fritz Walter",
|
||||
"minute": 54,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "F. Walter",
|
||||
"name": "Fritz Walter",
|
||||
"minute": 64,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "O. Walter",
|
||||
"name": "Ottmar Walter",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "O. Walter",
|
||||
"name": "Ottmar Walter",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Probst",
|
||||
"name": "Erich Probst",
|
||||
"minute": 51
|
||||
}
|
||||
],
|
||||
@@ -947,29 +947,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Czibor",
|
||||
"name": "Zoltán Czibor",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "Hidegkuti",
|
||||
"name": "Nándor Hidegkuti",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 111
|
||||
},
|
||||
{
|
||||
"name": "Kocsis",
|
||||
"name": "Sándor Kocsis",
|
||||
"minute": 116
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hohberg",
|
||||
"name": "Juan Hohberg",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Hohberg",
|
||||
"name": "Juan Hohberg",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
@@ -989,23 +989,23 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Stojaspal",
|
||||
"name": "Ernst Stojaspal",
|
||||
"minute": 16,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Cruz",
|
||||
"name": "Luis Cruz",
|
||||
"minute": 59,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Ocwirk",
|
||||
"name": "Ernst Ocwirk",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hohberg",
|
||||
"name": "Juan Hohberg",
|
||||
"minute": 22
|
||||
}
|
||||
],
|
||||
@@ -1015,7 +1015,7 @@
|
||||
"round": "Final",
|
||||
"date": "1954-07-04",
|
||||
"time": "17:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Hungary",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1025,25 +1025,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Morlock",
|
||||
"name": "Max Morlock",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Puskás",
|
||||
"name": "Ferenc Puskás",
|
||||
"minute": 6
|
||||
},
|
||||
{
|
||||
"name": "Czibor",
|
||||
"name": "Zoltán Czibor",
|
||||
"minute": 8
|
||||
}
|
||||
],
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"host": "Switzerland",
|
||||
"teams_count": 16,
|
||||
"winner": "West Germany",
|
||||
"winner": "Germany",
|
||||
"runner_up": "Hungary",
|
||||
"third_place": "Austria",
|
||||
"fourth_place": "Uruguay"
|
||||
@@ -4,7 +4,7 @@
|
||||
"name": "Group 1",
|
||||
"teams": [
|
||||
"Argentina",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Northern Ireland",
|
||||
"Czechoslovakia"
|
||||
]
|
||||
@@ -6,7 +6,7 @@
|
||||
"date": "1958-06-08",
|
||||
"time": "19:00",
|
||||
"team1": "Argentina",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -15,21 +15,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Corbatta",
|
||||
"name": "Omar Oreste Corbatta",
|
||||
"minute": 3
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 32
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 42
|
||||
}
|
||||
],
|
||||
@@ -50,7 +50,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cush",
|
||||
"name": "Wilbur Cush",
|
||||
"minute": 21
|
||||
}
|
||||
],
|
||||
@@ -61,7 +61,7 @@
|
||||
"group": "Group 1",
|
||||
"date": "1958-06-11",
|
||||
"time": "19:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Czechoslovakia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -71,22 +71,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dvořák",
|
||||
"name": "Milan Dvořák",
|
||||
"minute": 24,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Zikán",
|
||||
"name": "Zdeněk Zikán",
|
||||
"minute": 42
|
||||
}
|
||||
],
|
||||
@@ -107,22 +107,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Corbatta",
|
||||
"name": "Omar Oreste Corbatta",
|
||||
"minute": 37,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Menéndez",
|
||||
"name": "Norberto Menéndez",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Avio",
|
||||
"name": "Ludovico Avio",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "McParland",
|
||||
"name": "Peter McParland",
|
||||
"minute": 4
|
||||
}
|
||||
],
|
||||
@@ -133,7 +133,7 @@
|
||||
"group": "Group 1",
|
||||
"date": "1958-06-15",
|
||||
"time": "19:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Northern Ireland",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -143,21 +143,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "McParland",
|
||||
"name": "Peter McParland",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "McParland",
|
||||
"name": "Peter McParland",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
@@ -178,33 +178,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dvořák",
|
||||
"name": "Milan Dvořák",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Zikán",
|
||||
"name": "Zdeněk Zikán",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Zikán",
|
||||
"name": "Zdeněk Zikán",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Feureisl",
|
||||
"name": "Jiří Feureisl",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Hovorka",
|
||||
"name": "Václav Hovorka",
|
||||
"minute": 82
|
||||
},
|
||||
{
|
||||
"name": "Hovorka",
|
||||
"name": "Václav Hovorka",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Corbatta",
|
||||
"name": "Omar Oreste Corbatta",
|
||||
"minute": 65,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -230,17 +230,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "McParland",
|
||||
"name": "Peter McParland",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "McParland",
|
||||
"name": "Peter McParland",
|
||||
"minute": 97
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zikán",
|
||||
"name": "Zdeněk Zikán",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -261,46 +261,46 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Piantoni",
|
||||
"name": "Roger Piantoni",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Wisnieski",
|
||||
"name": "Maryan Wisnieski",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "Kopa",
|
||||
"name": "Raymond Kopa",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Vincent",
|
||||
"name": "Jean Vincent",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Amarilla",
|
||||
"name": "Florencio Amarilla",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Amarilla",
|
||||
"name": "Florencio Amarilla",
|
||||
"minute": 44,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Romero",
|
||||
"name": "Jorge Lino Romero",
|
||||
"minute": 50
|
||||
}
|
||||
],
|
||||
@@ -321,13 +321,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Petaković",
|
||||
"name": "Aleksandar Petaković",
|
||||
"minute": 6
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Murray",
|
||||
"name": "Jimmy Murray",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
@@ -348,25 +348,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Petaković",
|
||||
"name": "Aleksandar Petaković",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Veselinović",
|
||||
"name": "Todor Veselinović",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Veselinović",
|
||||
"name": "Todor Veselinović",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -387,25 +387,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Agüero",
|
||||
"name": "Juan Bautista Agüero",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Ré",
|
||||
"name": "Cayetano Ré",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "Parodi",
|
||||
"name": "José Parodi",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Mudie",
|
||||
"name": "Jackie Mudie",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Collins",
|
||||
"name": "Bobby Collins",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -426,17 +426,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kopa",
|
||||
"name": "Raymond Kopa",
|
||||
"minute": 22
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Baird",
|
||||
"name": "Sammy Baird",
|
||||
"minute": 58
|
||||
}
|
||||
],
|
||||
@@ -457,29 +457,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Parodi",
|
||||
"name": "José Parodi",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Agüero",
|
||||
"name": "Juan Bautista Agüero",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Romero",
|
||||
"name": "Jorge Lino Romero",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ognjanović",
|
||||
"name": "Radivoje Ognjanović",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Veselinović",
|
||||
"name": "Todor Veselinović",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Rajkov",
|
||||
"name": "Zdravko Rajkov",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -500,15 +500,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Simonsson",
|
||||
"name": "Agne Simonsson",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Simonsson",
|
||||
"name": "Agne Simonsson",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Liedholm",
|
||||
"name": "Nils Liedholm",
|
||||
"minute": 57,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -530,13 +530,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bozsik",
|
||||
"name": "József Bozsik",
|
||||
"minute": 5
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "J. Charles",
|
||||
"name": "John Charles",
|
||||
"minute": 27
|
||||
}
|
||||
],
|
||||
@@ -557,13 +557,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Belmonte",
|
||||
"name": "Jaime Belmonte",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "I. Allchurch",
|
||||
"name": "Ivor Allchurch",
|
||||
"minute": 32
|
||||
}
|
||||
],
|
||||
@@ -584,17 +584,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hamrin",
|
||||
"name": "Kurt Hamrin",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Hamrin",
|
||||
"name": "Kurt Hamrin",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 77
|
||||
}
|
||||
],
|
||||
@@ -630,19 +630,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Sándor",
|
||||
"name": "Károly Sándor",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Bencsics",
|
||||
"name": "József Bencsics",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -663,17 +663,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "I. Allchurch",
|
||||
"name": "Ivor Allchurch",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Medwin",
|
||||
"name": "Terry Medwin",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 33
|
||||
}
|
||||
],
|
||||
@@ -694,11 +694,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Altafini",
|
||||
"name": "José Altafini",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Altafini",
|
||||
"name": "José Altafini",
|
||||
"minute": 85
|
||||
},
|
||||
{
|
||||
@@ -723,21 +723,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Simonyan",
|
||||
"name": "Nikita Simonyan",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "A. Ivanov",
|
||||
"name": "Aleksandr Ivanov",
|
||||
"minute": 56
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Kevan",
|
||||
"name": "Derek Kevan",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Finney",
|
||||
"name": "Tom Finney",
|
||||
"minute": 85,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -774,11 +774,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ilyin",
|
||||
"name": "Anatoli Ilyin",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "V. Ivanov",
|
||||
"name": "Valentin Kozmich Ivanov",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -799,21 +799,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Haynes",
|
||||
"name": "Johnny Haynes",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Kevan",
|
||||
"name": "Derek Kevan",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Koller",
|
||||
"name": "Karl Koller",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Körner",
|
||||
"name": "Alfred Körner",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
@@ -859,7 +859,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ilyin",
|
||||
"name": "Anatoli Ilyin",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -899,19 +899,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Wisnieski",
|
||||
"name": "Maryan Wisnieski",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Piantoni",
|
||||
"name": "Roger Piantoni",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -931,11 +931,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hamrin",
|
||||
"name": "Kurt Hamrin",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Simonsson",
|
||||
"name": "Agne Simonsson",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -945,7 +945,7 @@
|
||||
"round": "Quarter-finals",
|
||||
"date": "1958-06-19",
|
||||
"time": "19:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Yugoslavia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -955,7 +955,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 12
|
||||
}
|
||||
],
|
||||
@@ -997,11 +997,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Piantoni",
|
||||
"name": "Roger Piantoni",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -1012,7 +1012,7 @@
|
||||
"date": "1958-06-24",
|
||||
"time": "19:00",
|
||||
"team1": "Sweden",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
3,
|
||||
@@ -1021,21 +1021,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Skoglund",
|
||||
"name": "Lennart Skoglund",
|
||||
"minute": 32
|
||||
},
|
||||
{
|
||||
"name": "Gren",
|
||||
"name": "Gunnar Gren",
|
||||
"minute": 81
|
||||
},
|
||||
{
|
||||
"name": "Hamrin",
|
||||
"name": "Kurt Hamrin",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 24
|
||||
}
|
||||
],
|
||||
@@ -1046,7 +1046,7 @@
|
||||
"date": "1958-06-28",
|
||||
"time": "17:00",
|
||||
"team1": "France",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
6,
|
||||
@@ -1055,42 +1055,42 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 36
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 78
|
||||
},
|
||||
{
|
||||
"name": "Fontaine",
|
||||
"name": "Just Fontaine",
|
||||
"minute": 89
|
||||
},
|
||||
{
|
||||
"name": "Kopa",
|
||||
"name": "Raymond Kopa",
|
||||
"minute": 27,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Douis",
|
||||
"name": "Yvon Douis",
|
||||
"minute": 50
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Cieslarczyk",
|
||||
"name": "Hans Cieslarczyk",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Rahn",
|
||||
"name": "Helmut Rahn",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Schäfer",
|
||||
"name": "Hans Schäfer",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -1126,17 +1126,17 @@
|
||||
"minute": 90
|
||||
},
|
||||
{
|
||||
"name": "Zagallo",
|
||||
"name": "Mário Zagallo",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Liedholm",
|
||||
"name": "Nils Liedholm",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Simonsson",
|
||||
"name": "Agne Simonsson",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -4,5 +4,5 @@
|
||||
"winner": "Brazil",
|
||||
"runner_up": "Sweden",
|
||||
"third_place": "France",
|
||||
"fourth_place": "West Germany"
|
||||
"fourth_place": "Germany"
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
"teams": [
|
||||
"Chile",
|
||||
"Switzerland",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Italy"
|
||||
]
|
||||
},
|
||||
@@ -14,17 +14,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "L. Sánchez",
|
||||
"name": "Leonel Sánchez",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Rojas",
|
||||
"name": "Eladio Rojas",
|
||||
"minute": 29
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Chislenko",
|
||||
"name": "Igor Chislenko",
|
||||
"minute": 26
|
||||
}
|
||||
],
|
||||
@@ -44,7 +44,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Scherer",
|
||||
"name": "Adolf Scherer",
|
||||
"minute": 13
|
||||
}
|
||||
],
|
||||
@@ -78,7 +78,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hitchens",
|
||||
"name": "Gerry Hitchens",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -89,7 +89,7 @@
|
||||
"date": "1962-06-10",
|
||||
"time": "14:30",
|
||||
"team1": "Yugoslavia",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -98,7 +98,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Radaković",
|
||||
"name": "Petar Radaković",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -118,22 +118,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kadraba",
|
||||
"name": "Josef Kadraba",
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Scherer",
|
||||
"name": "Adolf Scherer",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Scherer",
|
||||
"name": "Adolf Scherer",
|
||||
"minute": 84,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jerković",
|
||||
"name": "Dražan Jerković",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
@@ -171,11 +171,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Toro",
|
||||
"name": "Jorge Toro",
|
||||
"minute": 42
|
||||
},
|
||||
{
|
||||
"name": "L. Sánchez",
|
||||
"name": "Leonel Sánchez",
|
||||
"minute": 61,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -196,7 +196,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rojas",
|
||||
"name": "Eladio Rojas",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
@@ -216,7 +216,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Amarildo",
|
||||
"name": "Amarildo Tavares da Silveira",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
@@ -230,7 +230,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Masopust",
|
||||
"name": "Josef Masopust",
|
||||
"minute": 15
|
||||
}
|
||||
],
|
||||
@@ -251,17 +251,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cubilla",
|
||||
"name": "Luis Cubilla",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Sasía",
|
||||
"name": "José Sasía",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zuluaga",
|
||||
"name": "Francisco Zuluaga",
|
||||
"minute": 19,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -283,11 +283,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ivanov",
|
||||
"name": "Valentin Kozmich Ivanov",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Ponedelnik",
|
||||
"name": "Viktor Ponedelnik",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -308,22 +308,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Skoblar",
|
||||
"name": "Josip Skoblar",
|
||||
"minute": 25,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Galić",
|
||||
"name": "Milan Galić",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Jerković",
|
||||
"name": "Dražan Jerković",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Cabrera",
|
||||
"name": "Ángel Cabrera",
|
||||
"minute": 19
|
||||
}
|
||||
],
|
||||
@@ -344,37 +344,37 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ivanov",
|
||||
"name": "Valentin Kozmich Ivanov",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Ivanov",
|
||||
"name": "Valentin Kozmich Ivanov",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Chislenko",
|
||||
"name": "Igor Chislenko",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Ponedelnik",
|
||||
"name": "Viktor Ponedelnik",
|
||||
"minute": 56
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Aceros",
|
||||
"name": "Germán Aceros",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Coll",
|
||||
"name": "Marcos Coll",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Rada",
|
||||
"name": "Antonio Rada",
|
||||
"minute": 72
|
||||
},
|
||||
{
|
||||
"name": "Klinger",
|
||||
"name": "Marino Klinger",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
@@ -395,17 +395,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mamykin",
|
||||
"name": "Aleksei Mamykin",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Ivanov",
|
||||
"name": "Valentin Kozmich Ivanov",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sasía",
|
||||
"name": "José Sasía",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
@@ -426,23 +426,23 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Galić",
|
||||
"name": "Milan Galić",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Galić",
|
||||
"name": "Milan Galić",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "Jerković",
|
||||
"name": "Dražan Jerković",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Jerković",
|
||||
"name": "Dražan Jerković",
|
||||
"minute": 87
|
||||
},
|
||||
{
|
||||
"name": "Melić",
|
||||
"name": "Vojislav Melić",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -463,21 +463,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "L. Sánchez",
|
||||
"name": "Leonel Sanchez",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "L. Sánchez",
|
||||
"name": "Leonel Sanchez",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Ramírez",
|
||||
"name": "Jaime Ramírez",
|
||||
"minute": 51
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Wüthrich",
|
||||
"name": "Rolf Wüthrich",
|
||||
"minute": 6
|
||||
}
|
||||
],
|
||||
@@ -488,7 +488,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1962-05-31",
|
||||
"time": "15:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Italy",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -513,11 +513,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ramírez",
|
||||
"name": "Jaime Ramírez",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
"name": "Toro",
|
||||
"name": "Jorge Toro",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
@@ -528,7 +528,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1962-06-03",
|
||||
"time": "15:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Switzerland",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -538,17 +538,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brülls",
|
||||
"name": "Albert Brülls",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 59
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schneiter",
|
||||
"name": "Heinz Schneiter",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -559,7 +559,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1962-06-06",
|
||||
"time": "15:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Chile",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -569,12 +569,12 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Szymaniak",
|
||||
"name": "Horst Szymaniak",
|
||||
"minute": 21,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -595,15 +595,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mora",
|
||||
"name": "Bruno Mora",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Bulgarelli",
|
||||
"name": "Giacomo Bulgarelli",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Bulgarelli",
|
||||
"name": "Giacomo Bulgarelli",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -624,7 +624,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Zagallo",
|
||||
"name": "Mário Zagallo",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
@@ -649,7 +649,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Štibrányi",
|
||||
"name": "Jozef Štibrányi",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -685,7 +685,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Peiró",
|
||||
"name": "Joaquín Peiró",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
@@ -706,17 +706,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Amarildo",
|
||||
"name": "Amarildo Tavares da Silveira",
|
||||
"minute": 72
|
||||
},
|
||||
{
|
||||
"name": "Amarildo",
|
||||
"name": "Amarildo Tavares da Silveira",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Adelardo",
|
||||
"name": "Adelardo Rodríguez",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -737,22 +737,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Díaz",
|
||||
"name": "Isidoro Díaz",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Del Águila",
|
||||
"name": "Alfredo del Águila",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Hernández",
|
||||
"name": "Héctor Hernández",
|
||||
"minute": 90,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Mašek",
|
||||
"name": "Václav Mašek",
|
||||
"minute": 1
|
||||
}
|
||||
],
|
||||
@@ -773,7 +773,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Facundo",
|
||||
"name": "Héctor Facundo",
|
||||
"minute": 4
|
||||
}
|
||||
],
|
||||
@@ -794,17 +794,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Albert",
|
||||
"name": "Flórián Albert",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Flowers",
|
||||
"name": "Ron Flowers",
|
||||
"minute": 60,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -826,22 +826,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Flowers",
|
||||
"name": "Ron Flowers",
|
||||
"minute": 17,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Charlton",
|
||||
"name": "Bobby Charlton",
|
||||
"minute": 42
|
||||
},
|
||||
{
|
||||
"name": "Greaves",
|
||||
"name": "Jimmy Greaves",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sanfilippo",
|
||||
"name": "José Sanfilippo",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -862,33 +862,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Albert",
|
||||
"name": "Flórián Albert",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Albert",
|
||||
"name": "Flórián Albert",
|
||||
"minute": 6
|
||||
},
|
||||
{
|
||||
"name": "Albert",
|
||||
"name": "Flórián Albert",
|
||||
"minute": 53
|
||||
},
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Tichy",
|
||||
"name": "Lajos Tichy",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Solymosi",
|
||||
"name": "Ernő Solymosi",
|
||||
"minute": 12
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sokolov",
|
||||
"name": "Georgi Sokolov",
|
||||
"minute": 64
|
||||
}
|
||||
],
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"name": "Group 2",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Switzerland",
|
||||
"Argentina",
|
||||
"Spain"
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hurst",
|
||||
"name": "Geoff Hurst",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
@@ -24,7 +24,7 @@
|
||||
"round": "Quarter-finals",
|
||||
"date": "1966-07-23",
|
||||
"time": "15:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Uruguay",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -34,19 +34,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 83
|
||||
},
|
||||
{
|
||||
"name": "Beckenbauer",
|
||||
"name": "Franz Beckenbauer",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -66,17 +66,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Chislenko",
|
||||
"name": "Igor Chislenko",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Porkuyan",
|
||||
"name": "Valeriy Porkujan",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bene",
|
||||
"name": "Ferenc Bene",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -114,7 +114,7 @@
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "José Augusto",
|
||||
"name": "José Augusto de Almeida",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -138,7 +138,7 @@
|
||||
"round": "Semi-finals",
|
||||
"date": "1966-07-25",
|
||||
"time": "19:30",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Soviet Union",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -148,17 +148,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Beckenbauer",
|
||||
"name": "Franz Beckenbauer",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Porkuyan",
|
||||
"name": "Valeriy Porkujan",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -178,11 +178,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "B. Charlton",
|
||||
"name": "Bobby Charlton",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "B. Charlton",
|
||||
"name": "Bobby Charlton",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -214,13 +214,13 @@
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Torres",
|
||||
"name": "José Augusto Torres",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Malofeyev",
|
||||
"name": "Eduard Malofeyev",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -231,7 +231,7 @@
|
||||
"date": "1966-07-30",
|
||||
"time": "15:00",
|
||||
"team1": "England",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
2,
|
||||
@@ -244,29 +244,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hurst",
|
||||
"name": "Geoff Hurst",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Hurst",
|
||||
"name": "Geoff Hurst",
|
||||
"minute": 101
|
||||
},
|
||||
{
|
||||
"name": "Hurst",
|
||||
"name": "Geoff Hurst",
|
||||
"minute": 120
|
||||
},
|
||||
{
|
||||
"name": "Peters",
|
||||
"name": "Martin Peters",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Weber",
|
||||
"name": "Wolfgang Weber",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -302,13 +302,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hausser",
|
||||
"name": "Gérard Hausser",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Borja",
|
||||
"name": "Enrique Borja",
|
||||
"minute": 48
|
||||
}
|
||||
],
|
||||
@@ -329,17 +329,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rocha",
|
||||
"name": "Pedro Rocha",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Cortés",
|
||||
"name": "Julio César Cortés",
|
||||
"minute": 31
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "De Bourgoing",
|
||||
"name": "Héctor De Bourgoing",
|
||||
"minute": 15,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -361,11 +361,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "B. Charlton",
|
||||
"name": "Bobby Charlton",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Hunt",
|
||||
"name": "Roger Hunt",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -401,11 +401,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hunt",
|
||||
"name": "Roger Hunt",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Hunt",
|
||||
"name": "Roger Hunt",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -416,7 +416,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1966-07-12",
|
||||
"time": "19:30",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Switzerland",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -426,24 +426,24 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Held",
|
||||
"name": "Sigfried Held",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Haller",
|
||||
"name": "Helmut Haller",
|
||||
"minute": 77,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Beckenbauer",
|
||||
"name": "Franz Beckenbauer",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Beckenbauer",
|
||||
"name": "Franz Beckenbauer",
|
||||
"minute": 52
|
||||
}
|
||||
],
|
||||
@@ -464,17 +464,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Artime",
|
||||
"name": "Luis Artime",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Artime",
|
||||
"name": "Luis Artime",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Roma",
|
||||
"name": "Antonio Roma",
|
||||
"minute": 72,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -496,17 +496,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sanchís",
|
||||
"name": "Manuel Sanchís Martínez",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Amancio",
|
||||
"name": "Amancio Amaro",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Quentin",
|
||||
"name": "René-Pierre Quentin",
|
||||
"minute": 31
|
||||
}
|
||||
],
|
||||
@@ -518,7 +518,7 @@
|
||||
"date": "1966-07-16",
|
||||
"time": "15:00",
|
||||
"team1": "Argentina",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -542,11 +542,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Artime",
|
||||
"name": "Luis Artime",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Onega",
|
||||
"name": "Ermindo Onega",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -557,7 +557,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1966-07-20",
|
||||
"time": "19:30",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Spain",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -567,17 +567,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Emmerich",
|
||||
"name": "Lothar Emmerich",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fusté",
|
||||
"name": "Josep Maria Fusté",
|
||||
"minute": 23
|
||||
}
|
||||
],
|
||||
@@ -623,21 +623,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "José Augusto",
|
||||
"name": "José Augusto de Almeida",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "José Augusto",
|
||||
"name": "José Augusto de Almeida",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Torres",
|
||||
"name": "José Augusto Torres",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bene",
|
||||
"name": "Ferenc Bene",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
@@ -658,15 +658,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bene",
|
||||
"name": "Ferenc Bene",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Farkas",
|
||||
"name": "János Farkas",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Mészöly",
|
||||
"name": "Kálmán Mészöly",
|
||||
"minute": 73,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -694,7 +694,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vutsov",
|
||||
"name": "Ivan Vutsov",
|
||||
"minute": 7,
|
||||
"owngoal": true
|
||||
},
|
||||
@@ -703,7 +703,7 @@
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Torres",
|
||||
"name": "José Augusto Torres",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -724,7 +724,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Simões",
|
||||
"name": "António Simões",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
@@ -738,7 +738,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rildo",
|
||||
"name": "Rildo da Costa Menezes",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -759,22 +759,22 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Davidov",
|
||||
"name": "Ivan Davidov",
|
||||
"minute": 43,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Mészöly",
|
||||
"name": "Kálmán Mészöly",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "Bene",
|
||||
"name": "Ferenc Bene",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Asparuhov",
|
||||
"name": "Georgi Asparuhov",
|
||||
"minute": 15
|
||||
}
|
||||
],
|
||||
@@ -795,15 +795,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Malofeyev",
|
||||
"name": "Eduard Malofeyev",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Malofeyev",
|
||||
"name": "Eduard Malofeyev",
|
||||
"minute": 88
|
||||
},
|
||||
{
|
||||
"name": "Banishevskiy",
|
||||
"name": "Anatoliy Banishevskiy",
|
||||
"minute": 33
|
||||
}
|
||||
],
|
||||
@@ -824,11 +824,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Mazzola",
|
||||
"name": "Sandro Mazzola",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Barison",
|
||||
"name": "Paolo Barison",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -849,7 +849,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Marcos",
|
||||
"name": "Rubén Marcos",
|
||||
"minute": 26,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -877,7 +877,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Chislenko",
|
||||
"name": "Igor Chislenko",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -919,17 +919,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Porkuyan",
|
||||
"name": "Valeriy Porkujan",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Porkuyan",
|
||||
"name": "Valeriy Porkujan",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Marcos",
|
||||
"name": "Rubén Marcos",
|
||||
"minute": 32
|
||||
}
|
||||
],
|
||||
@@ -2,7 +2,7 @@
|
||||
"host": "England",
|
||||
"teams_count": 16,
|
||||
"winner": "England",
|
||||
"runner_up": "West Germany",
|
||||
"runner_up": "Germany",
|
||||
"third_place": "Portugal",
|
||||
"fourth_place": "Soviet Union"
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
"teams": [
|
||||
"Peru",
|
||||
"Bulgaria",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Morocco"
|
||||
]
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Espárrago",
|
||||
"name": "Víctor Espárrago",
|
||||
"minute": 117
|
||||
}
|
||||
],
|
||||
@@ -38,26 +38,26 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Guzmán",
|
||||
"name": "Javier Guzmán",
|
||||
"minute": 25,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Riva",
|
||||
"name": "Gigi Riva",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Riva",
|
||||
"name": "Gigi Riva",
|
||||
"minute": 76
|
||||
},
|
||||
{
|
||||
"name": "Rivera",
|
||||
"name": "Gianni Rivera",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "González",
|
||||
"name": "José Luis González Dávila",
|
||||
"minute": 13
|
||||
}
|
||||
],
|
||||
@@ -95,11 +95,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Gallardo",
|
||||
"name": "Alberto Gallardo",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
@@ -109,7 +109,7 @@
|
||||
"round": "Quarter-finals",
|
||||
"date": "1970-06-14",
|
||||
"time": "12:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "England",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -123,25 +123,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Beckenbauer",
|
||||
"name": "Franz Beckenbauer",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 82
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 108
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Mullery",
|
||||
"name": "Alan Mullery",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Peters",
|
||||
"name": "Martin Peters",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
@@ -175,7 +175,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Cubilla",
|
||||
"name": "Luis Cubilla",
|
||||
"minute": 19
|
||||
}
|
||||
],
|
||||
@@ -186,7 +186,7 @@
|
||||
"date": "1970-06-17",
|
||||
"time": "16:00",
|
||||
"team1": "Italy",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -199,34 +199,34 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Boninsegna",
|
||||
"name": "Roberto Boninsegna",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Burgnich",
|
||||
"name": "Tarcisio Burgnich",
|
||||
"minute": 98
|
||||
},
|
||||
{
|
||||
"name": "Riva",
|
||||
"name": "Gigi Riva",
|
||||
"minute": 104
|
||||
},
|
||||
{
|
||||
"name": "Rivera",
|
||||
"name": "Gianni Rivera",
|
||||
"minute": 111
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schnellinger",
|
||||
"name": "Karl-Heinz Schnellinger",
|
||||
"minute": 90,
|
||||
"offset": 2
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 94
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 110
|
||||
}
|
||||
],
|
||||
@@ -236,7 +236,7 @@
|
||||
"round": "Third-place match",
|
||||
"date": "1970-06-20",
|
||||
"time": "16:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Uruguay",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -246,7 +246,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Overath",
|
||||
"name": "Wolfgang Overath",
|
||||
"minute": 26
|
||||
}
|
||||
],
|
||||
@@ -278,13 +278,13 @@
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "Carlos Alberto",
|
||||
"name": "Carlos Alberto Torres",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Boninsegna",
|
||||
"name": "Roberto Boninsegna",
|
||||
"minute": 37
|
||||
}
|
||||
],
|
||||
@@ -320,15 +320,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Van Moer",
|
||||
"name": "Wilfried Van Moer",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Van Moer",
|
||||
"name": "Wilfried Van Moer",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Lambert",
|
||||
"name": "Raoul Lambert",
|
||||
"minute": 79,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -350,25 +350,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Byshovets",
|
||||
"name": "Anatoliy Byshovets",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Byshovets",
|
||||
"name": "Anatoliy Byshovets",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Asatiani",
|
||||
"name": "Kakhi Asatiani",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Khmelnytskyi",
|
||||
"name": "Vitaliy Khmelnytskyi",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lambert",
|
||||
"name": "Raoul Lambert",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
@@ -389,19 +389,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Valdivia",
|
||||
"name": "Javier Valdivia",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "Valdivia",
|
||||
"name": "Javier Valdivia",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Fragoso",
|
||||
"name": "Javier Fragoso",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Basaguren",
|
||||
"name": "Juan Ignacio Basaguren",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -422,11 +422,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Byshovets",
|
||||
"name": "Anatoliy Byshovets",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Byshovets",
|
||||
"name": "Anatoliy Byshovets",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -447,7 +447,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Peña",
|
||||
"name": "Gustavo Peña",
|
||||
"minute": 14,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -469,11 +469,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Maneiro",
|
||||
"name": "Ildo Maneiro",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Mujica",
|
||||
"name": "Juan Mujica",
|
||||
"minute": 50
|
||||
}
|
||||
],
|
||||
@@ -494,7 +494,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Domenghini",
|
||||
"name": "Angelo Domenghini",
|
||||
"minute": 10
|
||||
}
|
||||
],
|
||||
@@ -530,13 +530,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Turesson",
|
||||
"name": "Tom Turesson",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Spiegler",
|
||||
"name": "Mordechai Spiegler",
|
||||
"minute": 56
|
||||
}
|
||||
],
|
||||
@@ -557,7 +557,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Grahn",
|
||||
"name": "Ove Grahn",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
@@ -593,7 +593,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hurst",
|
||||
"name": "Geoff Hurst",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -632,7 +632,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Petráš",
|
||||
"name": "Ladislav Petráš",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -653,18 +653,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Neagu",
|
||||
"name": "Alexandru Neagu",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Dumitrache",
|
||||
"name": "Florea Dumitrache",
|
||||
"minute": 75,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Petráš",
|
||||
"name": "Ladislav Petráš",
|
||||
"minute": 5
|
||||
}
|
||||
],
|
||||
@@ -720,11 +720,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dumitrache",
|
||||
"name": "Florea Dumitrache",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Dembrovschi",
|
||||
"name": "Emerich Dembrovschi",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -745,7 +745,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Clarke",
|
||||
"name": "Allan Clarke",
|
||||
"minute": 50,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -767,25 +767,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Gallardo",
|
||||
"name": "Alberto Gallardo",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Chumpitaz",
|
||||
"name": "Héctor Chumpitaz",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Dermendzhiev",
|
||||
"name": "Dinko Dermendzhiev",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "Bonev",
|
||||
"name": "Hristo Bonev",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
@@ -796,7 +796,7 @@
|
||||
"group": "Group 4",
|
||||
"date": "1970-06-03",
|
||||
"time": "16:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Morocco",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -806,17 +806,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jarir",
|
||||
"name": "Houmane Jarir",
|
||||
"minute": 21
|
||||
}
|
||||
],
|
||||
@@ -837,15 +837,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Challe",
|
||||
"name": "Roberto Challe",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -856,7 +856,7 @@
|
||||
"group": "Group 4",
|
||||
"date": "1970-06-07",
|
||||
"time": "12:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Bulgaria",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -866,34 +866,34 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Libuda",
|
||||
"name": "Reinhard Libuda",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 52,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 88
|
||||
},
|
||||
{
|
||||
"name": "Seeler",
|
||||
"name": "Uwe Seeler",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nikodimov",
|
||||
"name": "Asparuh Nikodimov",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Kolev",
|
||||
"name": "Todor Kolev",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -904,7 +904,7 @@
|
||||
"group": "Group 4",
|
||||
"date": "1970-06-10",
|
||||
"time": "16:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Peru",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -914,21 +914,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 39
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
@@ -949,13 +949,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Zhechev",
|
||||
"name": "Dobromir Zhechev",
|
||||
"minute": 40
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ghazouani",
|
||||
"name": "Maouhoub Ghazouani",
|
||||
"minute": 61
|
||||
}
|
||||
],
|
||||
@@ -3,6 +3,6 @@
|
||||
"teams_count": 16,
|
||||
"winner": "Brazil",
|
||||
"runner_up": "Italy",
|
||||
"third_place": "West Germany",
|
||||
"third_place": "Germany",
|
||||
"fourth_place": "Uruguay"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"name": "Group 1",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Chile",
|
||||
"East Germany",
|
||||
"Australia"
|
||||
@@ -49,7 +49,7 @@
|
||||
"name": "Group B",
|
||||
"teams": [
|
||||
"Yugoslavia",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Sweden",
|
||||
"Poland"
|
||||
]
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -25,7 +25,7 @@
|
||||
"date": "1974-07-07",
|
||||
"time": "16:00",
|
||||
"team1": "Netherlands",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -34,19 +34,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Neeskens",
|
||||
"name": "Johan Neeskens",
|
||||
"minute": 2,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Breitner",
|
||||
"name": "Paul Breitner",
|
||||
"minute": 25,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -57,7 +57,7 @@
|
||||
"group": "Group 1",
|
||||
"date": "1974-06-14",
|
||||
"time": "16:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Chile",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Breitner",
|
||||
"name": "Paul Breitner",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -88,12 +88,12 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Curran",
|
||||
"name": "Colin Curran",
|
||||
"minute": 58,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Streich",
|
||||
"name": "Joachim Streich",
|
||||
"minute": 72
|
||||
}
|
||||
],
|
||||
@@ -105,7 +105,7 @@
|
||||
"date": "1974-06-18",
|
||||
"time": "16:00",
|
||||
"team1": "Australia",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -114,15 +114,15 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Overath",
|
||||
"name": "Wolfgang Overath",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Cullmann",
|
||||
"name": "Bernhard Cullmann",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
@@ -143,13 +143,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ahumada",
|
||||
"name": "Sergio Ahumada",
|
||||
"minute": 69
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hoffmann",
|
||||
"name": "Martin Hoffmann",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
@@ -176,7 +176,7 @@
|
||||
"date": "1974-06-22",
|
||||
"time": "19:30",
|
||||
"team1": "East Germany",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -185,7 +185,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sparwasser",
|
||||
"name": "Jürgen Sparwasser",
|
||||
"minute": 77
|
||||
}
|
||||
],
|
||||
@@ -221,11 +221,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lorimer",
|
||||
"name": "Peter Lorimer",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Jordan",
|
||||
"name": "Joe Jordan",
|
||||
"minute": 34
|
||||
}
|
||||
],
|
||||
@@ -246,39 +246,39 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bajević",
|
||||
"name": "Dušan Bajević",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Bajević",
|
||||
"name": "Dušan Bajević",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Bajević",
|
||||
"name": "Dušan Bajević",
|
||||
"minute": 81
|
||||
},
|
||||
{
|
||||
"name": "Džajić",
|
||||
"name": "Dragan Džajić",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Šurjak",
|
||||
"name": "Ivica Šurjak",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Katalinski",
|
||||
"name": "Josip Katalinski",
|
||||
"minute": 22
|
||||
},
|
||||
{
|
||||
"name": "Bogićević",
|
||||
"name": "Vladislav Bogićević",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Oblak",
|
||||
"name": "Branko Oblak",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "Petković",
|
||||
"name": "Ilija Petković",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -314,13 +314,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Jordan",
|
||||
"name": "Joe Jordan",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Karasi",
|
||||
"name": "Stanislav Karasi",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -349,7 +349,7 @@
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Valdomiro",
|
||||
"name": "Valdomiro Vaz Franco",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -370,11 +370,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
@@ -410,13 +410,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bonev",
|
||||
"name": "Hristo Bonev",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Pavoni",
|
||||
"name": "Ricardo Pavoni",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
@@ -452,28 +452,28 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Krol",
|
||||
"name": "Ruud Krol",
|
||||
"minute": 78,
|
||||
"owngoal": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Neeskens",
|
||||
"name": "Johan Neeskens",
|
||||
"minute": 5,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Neeskens",
|
||||
"name": "Johan Neeskens",
|
||||
"minute": 45,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "De Jong",
|
||||
"name": "Theo de Jong",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -494,15 +494,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Edström",
|
||||
"name": "Ralf Edström",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Edström",
|
||||
"name": "Ralf Edström",
|
||||
"minute": 77
|
||||
},
|
||||
{
|
||||
"name": "Sandberg",
|
||||
"name": "Roland Sandberg",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -523,21 +523,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rivera",
|
||||
"name": "Gianni Rivera",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Benetti",
|
||||
"name": "Romeo Benetti",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Anastasi",
|
||||
"name": "Pietro Anastasi",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sanon",
|
||||
"name": "Emmanuel Sanon",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
@@ -558,25 +558,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 62
|
||||
},
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 8
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Heredia",
|
||||
"name": "Ramón Heredia",
|
||||
"minute": 60
|
||||
},
|
||||
{
|
||||
"name": "Babington",
|
||||
"name": "Carlos Babington",
|
||||
"minute": 66
|
||||
}
|
||||
],
|
||||
@@ -597,13 +597,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Houseman",
|
||||
"name": "René Houseman",
|
||||
"minute": 20
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Perfumo",
|
||||
"name": "Roberto Perfumo",
|
||||
"minute": 35,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -625,31 +625,31 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 87
|
||||
},
|
||||
{
|
||||
"name": "Deyna",
|
||||
"name": "Kazimierz Deyna",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Gorgoń",
|
||||
"name": "Jerzy Gorgoń",
|
||||
"minute": 31
|
||||
}
|
||||
],
|
||||
@@ -670,25 +670,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Yazalde",
|
||||
"name": "Héctor Yazalde",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Yazalde",
|
||||
"name": "Héctor Yazalde",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Houseman",
|
||||
"name": "René Houseman",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Ayala",
|
||||
"name": "Rubén Ayala",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sanon",
|
||||
"name": "Emmanuel Sanon",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
@@ -709,17 +709,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Deyna",
|
||||
"name": "Kazimierz Deyna",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Capello",
|
||||
"name": "Fabio Capello",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -740,19 +740,19 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cruyff",
|
||||
"name": "Johan Cruyff",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Cruyff",
|
||||
"name": "Johan Cruyff",
|
||||
"minute": 90
|
||||
},
|
||||
{
|
||||
"name": "Krol",
|
||||
"name": "Ruud Krol",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -794,7 +794,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brindisi",
|
||||
"name": "Miguel Ángel Brindisi",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -825,11 +825,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Neeskens",
|
||||
"name": "Johan Neeskens",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 59
|
||||
}
|
||||
],
|
||||
@@ -850,13 +850,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Houseman",
|
||||
"name": "René Houseman",
|
||||
"minute": 20
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Streich",
|
||||
"name": "Joachim Streich",
|
||||
"minute": 14
|
||||
}
|
||||
],
|
||||
@@ -877,11 +877,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Neeskens",
|
||||
"name": "Johan Neeskens",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Cruyff",
|
||||
"name": "Johan Cruyff",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -893,7 +893,7 @@
|
||||
"date": "1974-06-26",
|
||||
"time": "16:00",
|
||||
"team1": "Yugoslavia",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -902,11 +902,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Breitner",
|
||||
"name": "Paul Breitner",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -927,7 +927,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -948,18 +948,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Deyna",
|
||||
"name": "Kazimierz Deyna",
|
||||
"minute": 24,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Karasi",
|
||||
"name": "Stanislav Karasi",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -970,7 +970,7 @@
|
||||
"group": "Group B",
|
||||
"date": "1974-06-30",
|
||||
"time": "19:30",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Sweden",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -980,30 +980,30 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Overath",
|
||||
"name": "Wolfgang Overath",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Bonhof",
|
||||
"name": "Rainer Bonhof",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Grabowski",
|
||||
"name": "Jürgen Grabowski",
|
||||
"minute": 76
|
||||
},
|
||||
{
|
||||
"name": "Hoeneß",
|
||||
"name": "Uli Hoeneß",
|
||||
"minute": 89,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Edström",
|
||||
"name": "Ralf Edström",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Sandberg",
|
||||
"name": "Roland Sandberg",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
@@ -1015,7 +1015,7 @@
|
||||
"date": "1974-07-03",
|
||||
"time": "16:35",
|
||||
"team1": "Poland",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -1024,7 +1024,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Müller",
|
||||
"name": "Gerd Müller",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -1045,17 +1045,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Edström",
|
||||
"name": "Ralf Edström",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Torstensson",
|
||||
"name": "Conny Torstensson",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Šurjak",
|
||||
"name": "Ivica Šurjak",
|
||||
"minute": 27
|
||||
}
|
||||
],
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"host": "West Germany",
|
||||
"teams_count": 16,
|
||||
"winner": "West Germany",
|
||||
"winner": "Germany",
|
||||
"runner_up": "Netherlands",
|
||||
"third_place": "Poland",
|
||||
"fourth_place": "Brazil"
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"name": "Group 2",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Poland",
|
||||
"Tunisia",
|
||||
"Mexico"
|
||||
@@ -42,7 +42,7 @@
|
||||
"Austria",
|
||||
"Netherlands",
|
||||
"Italy",
|
||||
"West Germany"
|
||||
"Germany"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -24,7 +24,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Causio",
|
||||
"name": "Franco Causio",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -48,21 +48,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 105
|
||||
},
|
||||
{
|
||||
"name": "Bertoni",
|
||||
"name": "Daniel Bertoni",
|
||||
"minute": 115
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Nanninga",
|
||||
"name": "Dick Nanninga",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -83,17 +83,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Zaccarelli",
|
||||
"name": "Renato Zaccarelli",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lacombe",
|
||||
"name": "Bernard Lacombe",
|
||||
"minute": 1
|
||||
}
|
||||
],
|
||||
@@ -114,17 +114,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Luque",
|
||||
"name": "Leopoldo Luque",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Bertoni",
|
||||
"name": "Daniel Bertoni",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Csapó",
|
||||
"name": "Károly Csapó",
|
||||
"minute": 9
|
||||
}
|
||||
],
|
||||
@@ -145,21 +145,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Bettega",
|
||||
"name": "Roberto Bettega",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Benetti",
|
||||
"name": "Romeo Benetti",
|
||||
"minute": 61
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "A. Tóth",
|
||||
"name": "András Tóth",
|
||||
"minute": 81,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -181,18 +181,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Passarella",
|
||||
"name": "Daniel Passarella",
|
||||
"minute": 45,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Luque",
|
||||
"name": "Leopoldo Luque",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platini",
|
||||
"name": "Michel Platini",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
@@ -213,21 +213,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lopez",
|
||||
"name": "Christian Lopez",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Berdoll",
|
||||
"name": "Marc Berdoll",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Rocheteau",
|
||||
"name": "Dominique Rocheteau",
|
||||
"minute": 42
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zombori",
|
||||
"name": "Sándor Zombori",
|
||||
"minute": 41
|
||||
}
|
||||
],
|
||||
@@ -248,7 +248,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bettega",
|
||||
"name": "Roberto Bettega",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -259,7 +259,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1978-06-01",
|
||||
"time": "15:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Poland",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -284,21 +284,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kaabi",
|
||||
"name": "Ali Kaabi",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Ghommidh",
|
||||
"name": "Néjib Ghommidh",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
"name": "Dhouieb",
|
||||
"name": "Mokhtar Dhouieb",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Vázquez Ayala",
|
||||
"name": "Arturo Vázquez Ayala",
|
||||
"minute": 45,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -310,7 +310,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1978-06-06",
|
||||
"time": "16:45",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Mexico",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -320,27 +320,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "D. Müller",
|
||||
"name": "Dieter Müller",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "H. Müller",
|
||||
"name": "Hansi Müller",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 38
|
||||
},
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
"name": "Flohe",
|
||||
"name": "Heinz Flohe",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Flohe",
|
||||
"name": "Heinz Flohe",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -361,7 +361,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 43
|
||||
}
|
||||
],
|
||||
@@ -372,7 +372,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1978-06-10",
|
||||
"time": "16:45",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Tunisia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -397,21 +397,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 84
|
||||
},
|
||||
{
|
||||
"name": "Deyna",
|
||||
"name": "Kazimierz Deyna",
|
||||
"minute": 56
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rangel",
|
||||
"name": "Víctor Rangel",
|
||||
"minute": 52
|
||||
}
|
||||
],
|
||||
@@ -432,11 +432,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schachner",
|
||||
"name": "Walter Schachner",
|
||||
"minute": 10
|
||||
},
|
||||
{
|
||||
"name": "Krankl",
|
||||
"name": "Hans Krankl",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -469,7 +469,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sjöberg",
|
||||
"name": "Thomas Sjöberg",
|
||||
"minute": 37
|
||||
}
|
||||
],
|
||||
@@ -490,7 +490,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Krankl",
|
||||
"name": "Hans Krankl",
|
||||
"minute": 42,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -527,7 +527,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Asensi",
|
||||
"name": "Juan Manuel Asensi",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -548,7 +548,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dinamite",
|
||||
"name": "Roberto Dinamite",
|
||||
"minute": 40
|
||||
}
|
||||
],
|
||||
@@ -569,21 +569,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cueto",
|
||||
"name": "César Cueto",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 77
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jordan",
|
||||
"name": "Joe Jordan",
|
||||
"minute": 14
|
||||
}
|
||||
],
|
||||
@@ -604,16 +604,16 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 40,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 62
|
||||
},
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 78,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -635,14 +635,14 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Eskandarian",
|
||||
"name": "Andranik Eskandarian",
|
||||
"minute": 43,
|
||||
"owngoal": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Danaeifard",
|
||||
"name": "Iraj Danaeifard",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
@@ -678,27 +678,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Velásquez",
|
||||
"name": "José Velásquez",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 36,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 39,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Cubillas",
|
||||
"name": "Teófilo Cubillas",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rowshan",
|
||||
"name": "Hassan Rowshan",
|
||||
"minute": 41
|
||||
}
|
||||
],
|
||||
@@ -719,27 +719,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dalglish",
|
||||
"name": "Kenny Dalglish",
|
||||
"minute": 45
|
||||
},
|
||||
{
|
||||
"name": "A. Gemmill",
|
||||
"name": "Archie Gemmill",
|
||||
"minute": 46,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "A. Gemmill",
|
||||
"name": "Archie Gemmill",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 34,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
@@ -760,30 +760,30 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Obermayer",
|
||||
"name": "Erich Obermayer",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brandts",
|
||||
"name": "Ernie Brandts",
|
||||
"minute": 6
|
||||
},
|
||||
{
|
||||
"name": "Rensenbrink",
|
||||
"name": "Rob Rensenbrink",
|
||||
"minute": 35,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 36
|
||||
},
|
||||
{
|
||||
"name": "Rep",
|
||||
"name": "Johnny Rep",
|
||||
"minute": 53
|
||||
},
|
||||
{
|
||||
"name": "W. van de Kerkhof",
|
||||
"name": "Willy van de Kerkhof",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -795,7 +795,7 @@
|
||||
"date": "1978-06-14",
|
||||
"time": "13:45",
|
||||
"team1": "Italy",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -810,7 +810,7 @@
|
||||
"date": "1978-06-18",
|
||||
"time": "16:45",
|
||||
"team1": "Netherlands",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
2,
|
||||
@@ -819,21 +819,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Haan",
|
||||
"name": "Arie Haan",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "R. van de Kerkhof",
|
||||
"name": "René van de Kerkhof",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Abramczik",
|
||||
"name": "Rüdiger Abramczik",
|
||||
"minute": 3
|
||||
},
|
||||
{
|
||||
"name": "D. Müller",
|
||||
"name": "Dieter Müller",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
@@ -854,7 +854,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 13
|
||||
}
|
||||
],
|
||||
@@ -866,7 +866,7 @@
|
||||
"date": "1978-06-21",
|
||||
"time": "13:45",
|
||||
"team1": "Austria",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
3,
|
||||
@@ -875,26 +875,26 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vogts",
|
||||
"name": "Berti Vogts",
|
||||
"minute": 59,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Krankl",
|
||||
"name": "Hans Krankl",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Krankl",
|
||||
"name": "Hans Krankl",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Hölzenbein",
|
||||
"name": "Bernd Hölzenbein",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -915,18 +915,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brandts",
|
||||
"name": "Ernie Brandts",
|
||||
"minute": 19,
|
||||
"owngoal": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brandts",
|
||||
"name": "Ernie Brandts",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Haan",
|
||||
"name": "Arie Haan",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -977,11 +977,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
@@ -1002,7 +1002,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
@@ -1042,17 +1042,17 @@
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "Dinamite",
|
||||
"name": "Roberto Dinamite",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Dinamite",
|
||||
"name": "Roberto Dinamite",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 45
|
||||
}
|
||||
],
|
||||
@@ -1073,27 +1073,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 21
|
||||
},
|
||||
{
|
||||
"name": "Kempes",
|
||||
"name": "Mario Kempes",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Tarantini",
|
||||
"name": "Alberto Tarantini",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Luque",
|
||||
"name": "Leopoldo Luque",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Luque",
|
||||
"name": "Leopoldo Luque",
|
||||
"minute": 72
|
||||
},
|
||||
{
|
||||
"name": "Houseman",
|
||||
"name": "René Houseman",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"name": "Group 2",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Algeria",
|
||||
"Chile",
|
||||
"Austria"
|
||||
@@ -65,7 +65,7 @@
|
||||
{
|
||||
"name": "Group B",
|
||||
"teams": [
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"England",
|
||||
"Spain"
|
||||
]
|
||||
@@ -14,11 +14,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 22
|
||||
},
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -28,7 +28,7 @@
|
||||
"round": "Semi-finals",
|
||||
"date": "1982-07-08",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "France",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -46,30 +46,30 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Littbarski",
|
||||
"name": "Pierre Littbarski",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 102
|
||||
},
|
||||
{
|
||||
"name": "Fischer",
|
||||
"name": "Klaus Fischer",
|
||||
"minute": 108
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platini",
|
||||
"name": "Michel Platini",
|
||||
"minute": 26,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Trésor",
|
||||
"name": "Marius Trésor",
|
||||
"minute": 92
|
||||
},
|
||||
{
|
||||
"name": "Giresse",
|
||||
"name": "Alain Giresse",
|
||||
"minute": 98
|
||||
}
|
||||
],
|
||||
@@ -89,25 +89,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Szarmach",
|
||||
"name": "Andrzej Szarmach",
|
||||
"minute": 40
|
||||
},
|
||||
{
|
||||
"name": "Majewski",
|
||||
"name": "Stefan Majewski",
|
||||
"minute": 44
|
||||
},
|
||||
{
|
||||
"name": "Kupcewicz",
|
||||
"name": "Janusz Kupcewicz",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Girard",
|
||||
"name": "René Girard",
|
||||
"minute": 13
|
||||
},
|
||||
{
|
||||
"name": "Couriol",
|
||||
"name": "Alain Couriol",
|
||||
"minute": 72
|
||||
}
|
||||
],
|
||||
@@ -118,7 +118,7 @@
|
||||
"date": "1982-07-11",
|
||||
"time": "20:00",
|
||||
"team1": "Italy",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
3,
|
||||
@@ -127,21 +127,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Tardelli",
|
||||
"name": "Marco Tardelli",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "Altobelli",
|
||||
"name": "Alessandro Altobelli",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Breitner",
|
||||
"name": "Paul Breitner",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -192,13 +192,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Conti",
|
||||
"name": "Bruno Conti",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Díaz",
|
||||
"name": "Rubén Toribio Díaz",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -234,29 +234,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Smolarek",
|
||||
"name": "Włodzimierz Smolarek",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Lato",
|
||||
"name": "Grzegorz Lato",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 61
|
||||
},
|
||||
{
|
||||
"name": "Buncol",
|
||||
"name": "Andrzej Buncol",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
"name": "Ciołek",
|
||||
"name": "Włodzimierz Ciołek",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "La Rosa",
|
||||
"name": "Guillermo La Rosa",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -277,13 +277,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Graziani",
|
||||
"name": "Francesco Graziani",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "M'Bida",
|
||||
"name": "Grégoire M'Bida",
|
||||
"minute": 61
|
||||
}
|
||||
],
|
||||
@@ -294,7 +294,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1982-06-16",
|
||||
"time": "17:15",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Algeria",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -304,17 +304,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Madjer",
|
||||
"name": "Rabah Madjer",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Belloumi",
|
||||
"name": "Lakhdar Belloumi",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -335,7 +335,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schachner",
|
||||
"name": "Walter Schachner",
|
||||
"minute": 22
|
||||
}
|
||||
],
|
||||
@@ -346,7 +346,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1982-06-20",
|
||||
"time": "17:15",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Chile",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -356,25 +356,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Reinders",
|
||||
"name": "Uwe Reinders",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Moscoso",
|
||||
"name": "Gustavo Moscoso",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
@@ -395,11 +395,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schachner",
|
||||
"name": "Walter Schachner",
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Krankl",
|
||||
"name": "Hans Krankl",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -420,26 +420,26 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Assad",
|
||||
"name": "Salah Assad",
|
||||
"minute": 7
|
||||
},
|
||||
{
|
||||
"name": "Assad",
|
||||
"name": "Salah Assad",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Bensaoula",
|
||||
"name": "Tedj Bensaoula",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Neira",
|
||||
"name": "Miguel Ángel Neira",
|
||||
"minute": 59,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Letelier",
|
||||
"name": "Juan Carlos Letelier",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -450,7 +450,7 @@
|
||||
"group": "Group 2",
|
||||
"date": "1982-06-25",
|
||||
"time": "17:15",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Austria",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -460,7 +460,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Hrubesch",
|
||||
"name": "Horst Hrubesch",
|
||||
"minute": 10
|
||||
}
|
||||
],
|
||||
@@ -481,7 +481,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Vandenbergh",
|
||||
"name": "Erwin Vandenbergh",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -502,49 +502,49 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Nyilasi",
|
||||
"name": "Tibor Nyilasi",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Nyilasi",
|
||||
"name": "Tibor Nyilasi",
|
||||
"minute": 83
|
||||
},
|
||||
{
|
||||
"name": "Pölöskei",
|
||||
"name": "Gábor Pölöskei",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Fazekas",
|
||||
"name": "László Fazekas",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Fazekas",
|
||||
"name": "László Fazekas",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Tóth",
|
||||
"name": "József Tóth",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "L. Kiss",
|
||||
"name": "László Kiss",
|
||||
"minute": 69
|
||||
},
|
||||
{
|
||||
"name": "L. Kiss",
|
||||
"name": "László Kiss",
|
||||
"minute": 72
|
||||
},
|
||||
{
|
||||
"name": "L. Kiss",
|
||||
"name": "László Kiss",
|
||||
"minute": 76
|
||||
},
|
||||
{
|
||||
"name": "Szentes",
|
||||
"name": "Lázár Szentes",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ramírez",
|
||||
"name": "Luis Ramírez Zapata",
|
||||
"minute": 64
|
||||
}
|
||||
],
|
||||
@@ -565,25 +565,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Bertoni",
|
||||
"name": "Daniel Bertoni",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Ardiles",
|
||||
"name": "Osvaldo Ardiles",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Pölöskei",
|
||||
"name": "Gábor Pölöskei",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
@@ -604,7 +604,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Coeck",
|
||||
"name": "Ludo Coeck",
|
||||
"minute": 19
|
||||
}
|
||||
],
|
||||
@@ -625,13 +625,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Czerniatynski",
|
||||
"name": "Alexandre Czerniatynski",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Varga",
|
||||
"name": "József Varga",
|
||||
"minute": 27
|
||||
}
|
||||
],
|
||||
@@ -652,12 +652,12 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Passarella",
|
||||
"name": "Daniel Passarella",
|
||||
"minute": 22,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Bertoni",
|
||||
"name": "Daniel Bertoni",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
@@ -678,21 +678,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Robson",
|
||||
"name": "Bryan Robson",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Robson",
|
||||
"name": "Bryan Robson",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Mariner",
|
||||
"name": "Paul Mariner",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Soler",
|
||||
"name": "Gérard Soler",
|
||||
"minute": 24
|
||||
}
|
||||
],
|
||||
@@ -713,14 +713,14 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Panenka",
|
||||
"name": "Antonín Panenka",
|
||||
"minute": 21,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Al-Dakhil",
|
||||
"name": "Faisal Al-Dakhil",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -741,11 +741,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Francis",
|
||||
"name": "Trevor Francis",
|
||||
"minute": 62
|
||||
},
|
||||
{
|
||||
"name": "Barmoš",
|
||||
"name": "Jozef Barmoš",
|
||||
"minute": 66,
|
||||
"owngoal": true
|
||||
}
|
||||
@@ -767,25 +767,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Genghini",
|
||||
"name": "Bernard Genghini",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Platini",
|
||||
"name": "Michel Platini",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Six",
|
||||
"name": "Didier Six",
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Bossis",
|
||||
"name": "Maxime Bossis",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Abdull. Al-Buloushi",
|
||||
"name": "Abdullah Al-Buloushi",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -806,13 +806,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Six",
|
||||
"name": "Didier Six",
|
||||
"minute": 66
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Panenka",
|
||||
"name": "Antonín Panenka",
|
||||
"minute": 84,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -834,7 +834,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Francis",
|
||||
"name": "Trevor Francis",
|
||||
"minute": 27
|
||||
}
|
||||
],
|
||||
@@ -855,14 +855,14 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "López Ufarte",
|
||||
"name": "Roberto López Ufarte",
|
||||
"minute": 65,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zelaya",
|
||||
"name": "Héctor Zelaya",
|
||||
"minute": 8
|
||||
}
|
||||
],
|
||||
@@ -903,13 +903,13 @@
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Saura",
|
||||
"name": "Enrique Saura",
|
||||
"minute": 66
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Gudelj",
|
||||
"name": "Ivan Gudelj",
|
||||
"minute": 10
|
||||
}
|
||||
],
|
||||
@@ -930,13 +930,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Laing",
|
||||
"name": "Eduardo Laing",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Armstrong",
|
||||
"name": "Gerry Armstrong",
|
||||
"minute": 10
|
||||
}
|
||||
],
|
||||
@@ -957,7 +957,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Petrović",
|
||||
"name": "Vladimir Petrović",
|
||||
"minute": 88,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -979,7 +979,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Armstrong",
|
||||
"name": "Gerry Armstrong",
|
||||
"minute": 47
|
||||
}
|
||||
],
|
||||
@@ -1004,13 +1004,13 @@
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Éder",
|
||||
"name": "Éder Aleixo de Assis",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bal",
|
||||
"name": "Andriy Bal",
|
||||
"minute": 34
|
||||
}
|
||||
],
|
||||
@@ -1031,33 +1031,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Dalglish",
|
||||
"name": "Kenny Dalglish",
|
||||
"minute": 18
|
||||
},
|
||||
{
|
||||
"name": "Wark",
|
||||
"name": "John Wark",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Wark",
|
||||
"name": "John Wark",
|
||||
"minute": 32
|
||||
},
|
||||
{
|
||||
"name": "Robertson",
|
||||
"name": "John Robertson",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
"name": "Archibald",
|
||||
"name": "Steve Archibald",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sumner",
|
||||
"name": "Steve Sumner",
|
||||
"minute": 54
|
||||
},
|
||||
{
|
||||
"name": "Wooddin",
|
||||
"name": "Steve Wooddin",
|
||||
"minute": 64
|
||||
}
|
||||
],
|
||||
@@ -1086,17 +1086,17 @@
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Éder",
|
||||
"name": "Éder Aleixo de Assis",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Falcão",
|
||||
"name": "Paulo Roberto Falcão",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Narey",
|
||||
"name": "David Narey",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -1117,15 +1117,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Gavrilov",
|
||||
"name": "Yuri Gavrilov",
|
||||
"minute": 24
|
||||
},
|
||||
{
|
||||
"name": "Blokhin",
|
||||
"name": "Oleh Blokhin",
|
||||
"minute": 48
|
||||
},
|
||||
{
|
||||
"name": "Baltacha",
|
||||
"name": "Sergei Pavlovich Baltacha",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -1146,21 +1146,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Chivadze",
|
||||
"name": "Aleksandre Chivadze",
|
||||
"minute": 59
|
||||
},
|
||||
{
|
||||
"name": "Shengelia",
|
||||
"name": "Ramaz Shengelia",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jordan",
|
||||
"name": "Joe Jordan",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Souness",
|
||||
"name": "Graeme Souness",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
@@ -1189,11 +1189,11 @@
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Falcão",
|
||||
"name": "Paulo Roberto Falcão",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Serginho",
|
||||
"name": "Serginho Chulapa",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
@@ -1214,15 +1214,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Boniek",
|
||||
"name": "Zbigniew Boniek",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
@@ -1243,7 +1243,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Oganesian",
|
||||
"name": "Khoren Oganesian",
|
||||
"minute": 48
|
||||
}
|
||||
],
|
||||
@@ -1269,7 +1269,7 @@
|
||||
"group": "Group B",
|
||||
"date": "1982-06-29",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "England",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1284,7 +1284,7 @@
|
||||
"group": "Group B",
|
||||
"date": "1982-07-02",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Spain",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1294,17 +1294,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Littbarski",
|
||||
"name": "Pierre Littbarski",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Fischer",
|
||||
"name": "Klaus Fischer",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Zamora",
|
||||
"name": "Jesús María Zamora",
|
||||
"minute": 82
|
||||
}
|
||||
],
|
||||
@@ -1340,17 +1340,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Tardelli",
|
||||
"name": "Marco Tardelli",
|
||||
"minute": 57
|
||||
},
|
||||
{
|
||||
"name": "Cabrini",
|
||||
"name": "Antonio Cabrini",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Passarella",
|
||||
"name": "Daniel Passarella",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -1371,7 +1371,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Díaz",
|
||||
"name": "Ramón Díaz",
|
||||
"minute": 89
|
||||
}
|
||||
],
|
||||
@@ -1381,11 +1381,11 @@
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Serginho",
|
||||
"name": "Serginho Chulapa",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Júnior",
|
||||
"name": "Leovegildo Lins da Gama Júnior",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -1406,15 +1406,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Rossi",
|
||||
"name": "Paolo Rossi",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -1424,7 +1424,7 @@
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Falcão",
|
||||
"name": "Paulo Roberto Falcão",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -1445,7 +1445,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Genghini",
|
||||
"name": "Bernard Genghini",
|
||||
"minute": 39
|
||||
}
|
||||
],
|
||||
@@ -1466,21 +1466,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Pezzey",
|
||||
"name": "Bruno Pezzey",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Hintermaier",
|
||||
"name": "Reinhold Hintermaier",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Hamilton",
|
||||
"name": "Billy Hamilton",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Hamilton",
|
||||
"name": "Billy Hamilton",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -1501,25 +1501,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Giresse",
|
||||
"name": "Alain Giresse",
|
||||
"minute": 33
|
||||
},
|
||||
{
|
||||
"name": "Giresse",
|
||||
"name": "Alain Giresse",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Rocheteau",
|
||||
"name": "Dominique Rocheteau",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Rocheteau",
|
||||
"name": "Dominique Rocheteau",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Armstrong",
|
||||
"name": "Gerry Armstrong",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -2,7 +2,7 @@
|
||||
"host": "Spain",
|
||||
"teams_count": 24,
|
||||
"winner": "Italy",
|
||||
"runner_up": "West Germany",
|
||||
"runner_up": "Germany",
|
||||
"third_place": "Poland",
|
||||
"fourth_place": "France"
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
"name": "Group E",
|
||||
"teams": [
|
||||
"Uruguay",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Scotland",
|
||||
"Denmark"
|
||||
]
|
||||
@@ -14,11 +14,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Negrete",
|
||||
"name": "Manuel Negrete Arias",
|
||||
"minute": 34
|
||||
},
|
||||
{
|
||||
"name": "Servín",
|
||||
"name": "Raúl Servín",
|
||||
"minute": 61
|
||||
}
|
||||
],
|
||||
@@ -42,34 +42,34 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Belanov",
|
||||
"name": "Igor Belanov",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Belanov",
|
||||
"name": "Igor Belanov",
|
||||
"minute": 70
|
||||
},
|
||||
{
|
||||
"name": "Belanov",
|
||||
"name": "Igor Belanov",
|
||||
"minute": 111,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Scifo",
|
||||
"name": "Enzo Scifo",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Ceulemans",
|
||||
"name": "Jan Ceulemans",
|
||||
"minute": 77
|
||||
},
|
||||
{
|
||||
"name": "Demol",
|
||||
"name": "Stéphane Demol",
|
||||
"minute": 102
|
||||
},
|
||||
{
|
||||
"name": "Claesen",
|
||||
"name": "Nico Claesen",
|
||||
"minute": 110
|
||||
}
|
||||
],
|
||||
@@ -98,7 +98,7 @@
|
||||
"minute": 55
|
||||
},
|
||||
{
|
||||
"name": "Edinho",
|
||||
"name": "Edino Nazareth Filho",
|
||||
"minute": 79
|
||||
},
|
||||
{
|
||||
@@ -123,7 +123,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Pasculli",
|
||||
"name": "Pedro Pasculli",
|
||||
"minute": 42
|
||||
}
|
||||
],
|
||||
@@ -143,11 +143,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platini",
|
||||
"name": "Michel Platini",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Stopyra",
|
||||
"name": "Yannick Stopyra",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -158,7 +158,7 @@
|
||||
"date": "1986-06-17",
|
||||
"time": "16:00",
|
||||
"team1": "Morocco",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -167,7 +167,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Matthäus",
|
||||
"name": "Lothar Matthäus",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -187,15 +187,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 31
|
||||
},
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
"name": "Beardsley",
|
||||
"name": "Peter Beardsley",
|
||||
"minute": 56
|
||||
}
|
||||
],
|
||||
@@ -215,31 +215,31 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "J. Olsen",
|
||||
"name": "Jesper Olsen",
|
||||
"minute": 33,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Butragueño",
|
||||
"name": "Emilio Butragueño",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Butragueño",
|
||||
"name": "Emilio Butragueño",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Butragueño",
|
||||
"name": "Emilio Butragueño",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Butragueño",
|
||||
"name": "Emilio Butragueño",
|
||||
"minute": 88,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Goikoetxea",
|
||||
"name": "Andoni Goikoetxea Olaskoaga",
|
||||
"minute": 68,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -274,7 +274,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platini",
|
||||
"name": "Michel Platini",
|
||||
"minute": 40
|
||||
}
|
||||
],
|
||||
@@ -284,7 +284,7 @@
|
||||
"round": "Quarter-finals",
|
||||
"date": "1986-06-21",
|
||||
"time": "16:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Mexico",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -316,17 +316,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -354,13 +354,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Señor",
|
||||
"name": "Juan Antonio Señor",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ceulemans",
|
||||
"name": "Jan Ceulemans",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -371,7 +371,7 @@
|
||||
"date": "1986-06-25",
|
||||
"time": "12:00",
|
||||
"team1": "France",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -380,11 +380,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brehme",
|
||||
"name": "Andreas Brehme",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 90
|
||||
}
|
||||
],
|
||||
@@ -404,11 +404,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
@@ -432,29 +432,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ceulemans",
|
||||
"name": "Jan Ceulemans",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Claesen",
|
||||
"name": "Nico Claesen",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ferreri",
|
||||
"name": "Jean-Marc Ferreri",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Papin",
|
||||
"name": "Jean-Pierre Papin",
|
||||
"minute": 43
|
||||
},
|
||||
{
|
||||
"name": "Genghini",
|
||||
"name": "Bernard Genghini",
|
||||
"minute": 104
|
||||
},
|
||||
{
|
||||
"name": "Amoros",
|
||||
"name": "Manuel Amoros",
|
||||
"minute": 111,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -466,7 +466,7 @@
|
||||
"date": "1986-06-29",
|
||||
"time": "12:00",
|
||||
"team1": "Argentina",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
3,
|
||||
@@ -475,25 +475,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brown",
|
||||
"name": "José Luis Brown",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Valdano",
|
||||
"name": "Jorge Valdano",
|
||||
"minute": 56
|
||||
},
|
||||
{
|
||||
"name": "Burruchaga",
|
||||
"name": "Jorge Burruchaga",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rummenigge",
|
||||
"name": "Karl-Heinz Rummenigge",
|
||||
"minute": 74
|
||||
},
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -514,13 +514,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sirakov",
|
||||
"name": "Nasko Sirakov",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Altobelli",
|
||||
"name": "Alessandro Altobelli",
|
||||
"minute": 44
|
||||
}
|
||||
],
|
||||
@@ -541,15 +541,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Valdano",
|
||||
"name": "Jorge Valdano",
|
||||
"minute": 6
|
||||
},
|
||||
{
|
||||
"name": "Valdano",
|
||||
"name": "Jorge Valdano",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Ruggeri",
|
||||
"name": "Oscar Ruggeri",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -576,14 +576,14 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Altobelli",
|
||||
"name": "Alessandro Altobelli",
|
||||
"minute": 6,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Maradona",
|
||||
"name": "Diego Maradona",
|
||||
"minute": 34
|
||||
}
|
||||
],
|
||||
@@ -610,7 +610,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Getov",
|
||||
"name": "Plamen Getov",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -641,11 +641,11 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Altobelli",
|
||||
"name": "Alessandro Altobelli",
|
||||
"minute": 17
|
||||
},
|
||||
{
|
||||
"name": "Altobelli",
|
||||
"name": "Alessandro Altobelli",
|
||||
"minute": 73
|
||||
},
|
||||
{
|
||||
@@ -671,11 +671,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Valdano",
|
||||
"name": "Jorge Valdano",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Burruchaga",
|
||||
"name": "Jorge Burruchaga",
|
||||
"minute": 77
|
||||
}
|
||||
],
|
||||
@@ -696,17 +696,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vandenbergh",
|
||||
"name": "Erwin Vandenbergh",
|
||||
"minute": 45
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Quirarte",
|
||||
"name": "Fernando Quirarte",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Sánchez",
|
||||
"name": "Hugo Sánchez",
|
||||
"minute": 39
|
||||
}
|
||||
],
|
||||
@@ -727,7 +727,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Romero",
|
||||
"name": "Julio César Romero",
|
||||
"minute": 35
|
||||
}
|
||||
],
|
||||
@@ -748,13 +748,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Flores",
|
||||
"name": "Luis Flores",
|
||||
"minute": 3
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Romero",
|
||||
"name": "Julio César Romero",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -775,17 +775,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Radhi",
|
||||
"name": "Ahmed Radhi",
|
||||
"minute": 59
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Scifo",
|
||||
"name": "Enzo Scifo",
|
||||
"minute": 16
|
||||
},
|
||||
{
|
||||
"name": "Claesen",
|
||||
"name": "Nico Claesen",
|
||||
"minute": 21,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -807,21 +807,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cabañas",
|
||||
"name": "Roberto Cabañas",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Cabañas",
|
||||
"name": "Roberto Cabañas",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Vercauteren",
|
||||
"name": "Franky Vercauteren",
|
||||
"minute": 30
|
||||
},
|
||||
{
|
||||
"name": "Veyt",
|
||||
"name": "Daniel Veyt",
|
||||
"minute": 59
|
||||
}
|
||||
],
|
||||
@@ -842,7 +842,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Quirarte",
|
||||
"name": "Fernando Quirarte",
|
||||
"minute": 54
|
||||
}
|
||||
],
|
||||
@@ -863,7 +863,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Papin",
|
||||
"name": "Jean-Pierre Papin",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -884,29 +884,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Yakovenko",
|
||||
"name": "Pavlo Yakovenko",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Aleinikov",
|
||||
"name": "Sergei Aleinikov",
|
||||
"minute": 4
|
||||
},
|
||||
{
|
||||
"name": "Belanov",
|
||||
"name": "Igor Belanov",
|
||||
"minute": 24,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Yaremchuk",
|
||||
"name": "Ivan Yaremchuk",
|
||||
"minute": 66
|
||||
},
|
||||
{
|
||||
"name": "Dajka",
|
||||
"name": "László Dajka",
|
||||
"minute": 73,
|
||||
"owngoal": true
|
||||
},
|
||||
{
|
||||
"name": "Rodionov",
|
||||
"name": "Sergey Rodionov",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -927,13 +927,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Fernández",
|
||||
"name": "Luis Fernández",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rats",
|
||||
"name": "Vasyl Rats",
|
||||
"minute": 53
|
||||
}
|
||||
],
|
||||
@@ -954,11 +954,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Esterházy",
|
||||
"name": "Márton Esterházy",
|
||||
"minute": 2
|
||||
},
|
||||
{
|
||||
"name": "Détári",
|
||||
"name": "Lajos Détári",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -979,15 +979,15 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Stopyra",
|
||||
"name": "Yannick Stopyra",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Tigana",
|
||||
"name": "Jean Tigana",
|
||||
"minute": 62
|
||||
},
|
||||
{
|
||||
"name": "Rocheteau",
|
||||
"name": "Dominique Rocheteau",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -1008,11 +1008,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Blokhin",
|
||||
"name": "Oleg Blokhin",
|
||||
"minute": 58
|
||||
},
|
||||
{
|
||||
"name": "Zavarov",
|
||||
"name": "Oleksandr Zavarov",
|
||||
"minute": 74
|
||||
}
|
||||
],
|
||||
@@ -1054,13 +1054,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Zidane",
|
||||
"name": "Djamel Zidane",
|
||||
"minute": 59
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Whiteside",
|
||||
"name": "Norman Whiteside",
|
||||
"minute": 6
|
||||
}
|
||||
],
|
||||
@@ -1102,17 +1102,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Clarke",
|
||||
"name": "Colin Clarke",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Butragueño",
|
||||
"name": "Emilio Butragueño",
|
||||
"minute": 1
|
||||
},
|
||||
{
|
||||
"name": "Salinas",
|
||||
"name": "Julio Salinas",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -1162,11 +1162,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Calderé",
|
||||
"name": "Ramón Calderé",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Calderé",
|
||||
"name": "Ramón Calderé",
|
||||
"minute": 68
|
||||
},
|
||||
{
|
||||
@@ -1182,7 +1182,7 @@
|
||||
"date": "1986-06-04",
|
||||
"time": "12:00",
|
||||
"team1": "Uruguay",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
1,
|
||||
@@ -1191,13 +1191,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Alzamendi",
|
||||
"name": "Antonio Alzamendi",
|
||||
"minute": 4
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Allofs",
|
||||
"name": "Klaus Allofs",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
@@ -1218,7 +1218,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Elkjær",
|
||||
"name": "Preben Elkjær",
|
||||
"minute": 57
|
||||
}
|
||||
],
|
||||
@@ -1229,7 +1229,7 @@
|
||||
"group": "Group E",
|
||||
"date": "1986-06-08",
|
||||
"time": "12:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Scotland",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1239,17 +1239,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 23
|
||||
},
|
||||
{
|
||||
"name": "Allofs",
|
||||
"name": "Klaus Allofs",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Strachan",
|
||||
"name": "Gordon Strachan",
|
||||
"minute": 18
|
||||
}
|
||||
],
|
||||
@@ -1270,33 +1270,33 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Elkjær",
|
||||
"name": "Preben Elkjær",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Elkjær",
|
||||
"name": "Preben Elkjær",
|
||||
"minute": 67
|
||||
},
|
||||
{
|
||||
"name": "Elkjær",
|
||||
"name": "Preben Elkjær",
|
||||
"minute": 80
|
||||
},
|
||||
{
|
||||
"name": "Lerby",
|
||||
"name": "Søren Lerby",
|
||||
"minute": 41
|
||||
},
|
||||
{
|
||||
"name": "Laudrup",
|
||||
"name": "Michael Laudrup",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "J. Olsen",
|
||||
"name": "Jesper Olsen",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Francescoli",
|
||||
"name": "Enzo Francescoli",
|
||||
"minute": 45,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -1309,7 +1309,7 @@
|
||||
"date": "1986-06-13",
|
||||
"time": "12:00",
|
||||
"team1": "Denmark",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
2,
|
||||
@@ -1318,12 +1318,12 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "J. Olsen",
|
||||
"name": "Jesper Olsen",
|
||||
"minute": 43,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Eriksen",
|
||||
"name": "John Eriksen",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -1410,7 +1410,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Smolarek",
|
||||
"name": "Włodzimierz Smolarek",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -1431,15 +1431,15 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 8
|
||||
},
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 14
|
||||
},
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 36
|
||||
}
|
||||
],
|
||||
@@ -1460,21 +1460,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Diamantino",
|
||||
"name": "Diamantino Miranda",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Khairi",
|
||||
"name": "Abderrazak Khairi",
|
||||
"minute": 19
|
||||
},
|
||||
{
|
||||
"name": "Khairi",
|
||||
"name": "Abderrazak Khairi",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "A. Merry",
|
||||
"name": "Abdelkrim Merry",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
@@ -2,7 +2,7 @@
|
||||
"host": "Mexico",
|
||||
"teams_count": 24,
|
||||
"winner": "Argentina",
|
||||
"runner_up": "West Germany",
|
||||
"runner_up": "Germany",
|
||||
"third_place": "France",
|
||||
"fourth_place": "Belgium"
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
"teams": [
|
||||
"United Arab Emirates",
|
||||
"Colombia",
|
||||
"West Germany",
|
||||
"Germany",
|
||||
"Yugoslavia"
|
||||
]
|
||||
},
|
||||
@@ -18,17 +18,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Milla",
|
||||
"name": "Roger Milla",
|
||||
"minute": 106
|
||||
},
|
||||
{
|
||||
"name": "Milla",
|
||||
"name": "Roger Milla",
|
||||
"minute": 108
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Redín",
|
||||
"name": "Bernardo Redín",
|
||||
"minute": 115
|
||||
}
|
||||
],
|
||||
@@ -48,25 +48,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Skuhravý",
|
||||
"name": "Tomáš Skuhravý",
|
||||
"minute": 12
|
||||
},
|
||||
{
|
||||
"name": "Skuhravý",
|
||||
"name": "Tomáš Skuhravý",
|
||||
"minute": 63
|
||||
},
|
||||
{
|
||||
"name": "Skuhravý",
|
||||
"name": "Tomáš Skuhravý",
|
||||
"minute": 82
|
||||
},
|
||||
{
|
||||
"name": "Kubík",
|
||||
"name": "Luboš Kubík",
|
||||
"minute": 76
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "González",
|
||||
"name": "Rónald González Brenes",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Caniggia",
|
||||
"name": "Claudio Caniggia",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -96,7 +96,7 @@
|
||||
"round": "Round of 16",
|
||||
"date": "1990-06-24",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Netherlands",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -106,17 +106,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Klinsmann",
|
||||
"name": "Jürgen Klinsmann",
|
||||
"minute": 51
|
||||
},
|
||||
{
|
||||
"name": "Brehme",
|
||||
"name": "Andreas Brehme",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "R. Koeman",
|
||||
"name": "Ronald Koeman",
|
||||
"minute": 89,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -159,11 +159,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 65
|
||||
},
|
||||
{
|
||||
"name": "Serena",
|
||||
"name": "Aldo Serena",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -187,17 +187,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Salinas",
|
||||
"name": "Julio Salinas",
|
||||
"minute": 84
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Stojković",
|
||||
"name": "Dragan Stojković",
|
||||
"minute": 78
|
||||
},
|
||||
{
|
||||
"name": "Stojković",
|
||||
"name": "Dragan Stojković",
|
||||
"minute": 93
|
||||
}
|
||||
],
|
||||
@@ -221,7 +221,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Platt",
|
||||
"name": "David Platt",
|
||||
"minute": 119
|
||||
}
|
||||
],
|
||||
@@ -263,7 +263,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -274,7 +274,7 @@
|
||||
"date": "1990-07-01",
|
||||
"time": "17:00",
|
||||
"team1": "Czechoslovakia",
|
||||
"team2": "West Germany",
|
||||
"team2": "Germany",
|
||||
"score": {
|
||||
"ft": [
|
||||
0,
|
||||
@@ -283,7 +283,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Matthäus",
|
||||
"name": "Lothar Matthäus",
|
||||
"minute": 25,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -308,27 +308,27 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kundé",
|
||||
"name": "Emmanuel Kundé",
|
||||
"minute": 61,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Ekéké",
|
||||
"name": "Eugène Ekéké",
|
||||
"minute": 65
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platt",
|
||||
"name": "David Platt",
|
||||
"minute": 25
|
||||
},
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 83,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 105,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -357,13 +357,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Caniggia",
|
||||
"name": "Claudio Caniggia",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 17
|
||||
}
|
||||
],
|
||||
@@ -373,7 +373,7 @@
|
||||
"round": "Semi-finals",
|
||||
"date": "1990-07-04",
|
||||
"time": "20:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "England",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -391,13 +391,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brehme",
|
||||
"name": "Andreas Brehme",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 80
|
||||
}
|
||||
],
|
||||
@@ -417,18 +417,18 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Baggio",
|
||||
"name": "Roberto Baggio",
|
||||
"minute": 71
|
||||
},
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 86,
|
||||
"penalty": true
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Platt",
|
||||
"name": "David Platt",
|
||||
"minute": 81
|
||||
}
|
||||
],
|
||||
@@ -438,7 +438,7 @@
|
||||
"round": "Final",
|
||||
"date": "1990-07-08",
|
||||
"time": "20:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Argentina",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -448,7 +448,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Brehme",
|
||||
"name": "Andreas Brehme",
|
||||
"minute": 85,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -470,7 +470,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
@@ -491,30 +491,30 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Caligiuri",
|
||||
"name": "Paul Caligiuri",
|
||||
"minute": 60
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Skuhravý",
|
||||
"name": "Tomáš Skuhravý",
|
||||
"minute": 26
|
||||
},
|
||||
{
|
||||
"name": "Skuhravý",
|
||||
"name": "Tomáš Skuhravý",
|
||||
"minute": 78
|
||||
},
|
||||
{
|
||||
"name": "Bílek",
|
||||
"name": "Michal Bílek",
|
||||
"minute": 40,
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Hašek",
|
||||
"name": "Ivan Hašek",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Luhový",
|
||||
"name": "Milan Luhový",
|
||||
"minute": 90,
|
||||
"offset": 3
|
||||
}
|
||||
@@ -536,7 +536,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Giannini",
|
||||
"name": "Giuseppe Giannini",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -557,7 +557,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bílek",
|
||||
"name": "Michal Bílek",
|
||||
"minute": 31,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -579,11 +579,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Schillaci",
|
||||
"name": "Salvatore Schillaci",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Baggio",
|
||||
"name": "Roberto Baggio",
|
||||
"minute": 78
|
||||
}
|
||||
],
|
||||
@@ -604,17 +604,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ogris",
|
||||
"name": "Andreas Ogris",
|
||||
"minute": 49
|
||||
},
|
||||
{
|
||||
"name": "Rodax",
|
||||
"name": "Gerhard Rodax",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Murray",
|
||||
"name": "Bruce Murray",
|
||||
"minute": 83
|
||||
}
|
||||
],
|
||||
@@ -635,7 +635,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Omam-Biyik",
|
||||
"name": "François Omam-Biyik",
|
||||
"minute": 67
|
||||
}
|
||||
],
|
||||
@@ -656,11 +656,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Lăcătuș",
|
||||
"name": "Marius Lăcătuș",
|
||||
"minute": 41
|
||||
},
|
||||
{
|
||||
"name": "Lăcătuș",
|
||||
"name": "Marius Lăcătuș",
|
||||
"minute": 55,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -682,11 +682,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Troglio",
|
||||
"name": "Pedro Troglio",
|
||||
"minute": 27
|
||||
},
|
||||
{
|
||||
"name": "Burruchaga",
|
||||
"name": "Jorge Burruchaga",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -707,17 +707,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Milla",
|
||||
"name": "Roger Milla",
|
||||
"minute": 76
|
||||
},
|
||||
{
|
||||
"name": "Milla",
|
||||
"name": "Roger Milla",
|
||||
"minute": 86
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Balint",
|
||||
"name": "Gavril Balint",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
@@ -738,13 +738,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Monzón",
|
||||
"name": "Pedro Monzón",
|
||||
"minute": 62
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Balint",
|
||||
"name": "Gavril Balint",
|
||||
"minute": 68
|
||||
}
|
||||
],
|
||||
@@ -765,19 +765,19 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Protasov",
|
||||
"name": "Oleh Protasov",
|
||||
"minute": 20
|
||||
},
|
||||
{
|
||||
"name": "Zygmantovich",
|
||||
"name": "Andrei Zygmantovich",
|
||||
"minute": 29
|
||||
},
|
||||
{
|
||||
"name": "Zavarov",
|
||||
"name": "Oleksandr Zavarov",
|
||||
"minute": 52
|
||||
},
|
||||
{
|
||||
"name": "Dobrovolski",
|
||||
"name": "Igor Dobrovolski",
|
||||
"minute": 63
|
||||
}
|
||||
],
|
||||
@@ -808,7 +808,7 @@
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Brolin",
|
||||
"name": "Tomas Brolin",
|
||||
"minute": 79
|
||||
}
|
||||
],
|
||||
@@ -829,7 +829,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Cayasso",
|
||||
"name": "Juan Cayasso",
|
||||
"minute": 49
|
||||
}
|
||||
],
|
||||
@@ -871,17 +871,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Strömberg",
|
||||
"name": "Glenn Strömberg",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "McCall",
|
||||
"name": "Stuart McCall",
|
||||
"minute": 11
|
||||
},
|
||||
{
|
||||
"name": "Johnston",
|
||||
"name": "Mo Johnston",
|
||||
"minute": 81,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -924,17 +924,17 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Ekström",
|
||||
"name": "Johnny Ekström",
|
||||
"minute": 32
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Flores",
|
||||
"name": "Róger Flores",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Medford",
|
||||
"name": "Hernán Medford",
|
||||
"minute": 87
|
||||
}
|
||||
],
|
||||
@@ -955,11 +955,11 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Redín",
|
||||
"name": "Bernardo Redín",
|
||||
"minute": 50
|
||||
},
|
||||
{
|
||||
"name": "Valderrama",
|
||||
"name": "Carlos Valderrama",
|
||||
"minute": 85
|
||||
}
|
||||
],
|
||||
@@ -970,7 +970,7 @@
|
||||
"group": "Group D",
|
||||
"date": "1990-06-10",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Yugoslavia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -980,25 +980,25 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Matthäus",
|
||||
"name": "Lothar Matthäus",
|
||||
"minute": 28
|
||||
},
|
||||
{
|
||||
"name": "Matthäus",
|
||||
"name": "Lothar Matthäus",
|
||||
"minute": 64
|
||||
},
|
||||
{
|
||||
"name": "Klinsmann",
|
||||
"name": "Jürgen Klinsmann",
|
||||
"minute": 39
|
||||
},
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 70
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Jozić",
|
||||
"name": "Davor Jozić",
|
||||
"minute": 55
|
||||
}
|
||||
],
|
||||
@@ -1019,7 +1019,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Jozić",
|
||||
"name": "Davor Jozić",
|
||||
"minute": 75
|
||||
}
|
||||
],
|
||||
@@ -1030,7 +1030,7 @@
|
||||
"group": "Group D",
|
||||
"date": "1990-06-15",
|
||||
"time": "21:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "United Arab Emirates",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1040,29 +1040,29 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 35
|
||||
},
|
||||
{
|
||||
"name": "Völler",
|
||||
"name": "Rudi Völler",
|
||||
"minute": 75
|
||||
},
|
||||
{
|
||||
"name": "Klinsmann",
|
||||
"name": "Jürgen Klinsmann",
|
||||
"minute": 37
|
||||
},
|
||||
{
|
||||
"name": "Matthäus",
|
||||
"name": "Lothar Matthäus",
|
||||
"minute": 47
|
||||
},
|
||||
{
|
||||
"name": "Bein",
|
||||
"name": "Uwe Bein",
|
||||
"minute": 58
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Ismaïl",
|
||||
"name": "Khalid Ismaïl",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
@@ -1073,7 +1073,7 @@
|
||||
"group": "Group D",
|
||||
"date": "1990-06-19",
|
||||
"time": "17:00",
|
||||
"team1": "West Germany",
|
||||
"team1": "Germany",
|
||||
"team2": "Colombia",
|
||||
"score": {
|
||||
"ft": [
|
||||
@@ -1083,13 +1083,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Littbarski",
|
||||
"name": "Pierre Littbarski",
|
||||
"minute": 88
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Rincón",
|
||||
"name": "Freddy Rincón",
|
||||
"minute": 90,
|
||||
"offset": 3
|
||||
}
|
||||
@@ -1111,26 +1111,26 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Sušić",
|
||||
"name": "Safet Sušić",
|
||||
"minute": 5
|
||||
},
|
||||
{
|
||||
"name": "Pančev",
|
||||
"name": "Darko Pančev",
|
||||
"minute": 9
|
||||
},
|
||||
{
|
||||
"name": "Pančev",
|
||||
"name": "Darko Pančev",
|
||||
"minute": 46
|
||||
},
|
||||
{
|
||||
"name": "Prosinečki",
|
||||
"name": "Robert Prosinečki",
|
||||
"minute": 90,
|
||||
"offset": 3
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Thani",
|
||||
"name": "Ali Thani Jumaa",
|
||||
"minute": 22
|
||||
}
|
||||
],
|
||||
@@ -1151,11 +1151,11 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Degryse",
|
||||
"name": "Marc Degryse",
|
||||
"minute": 53
|
||||
},
|
||||
{
|
||||
"name": "De Wolf",
|
||||
"name": "Michel De Wolf",
|
||||
"minute": 64
|
||||
}
|
||||
],
|
||||
@@ -1191,21 +1191,21 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Clijsters",
|
||||
"name": "Lei Clijsters",
|
||||
"minute": 15
|
||||
},
|
||||
{
|
||||
"name": "Scifo",
|
||||
"name": "Enzo Scifo",
|
||||
"minute": 22
|
||||
},
|
||||
{
|
||||
"name": "Ceulemans",
|
||||
"name": "Jan Ceulemans",
|
||||
"minute": 46
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Bengoechea",
|
||||
"name": "Pablo Bengoechea",
|
||||
"minute": 72
|
||||
}
|
||||
],
|
||||
@@ -1261,7 +1261,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Vervoort",
|
||||
"name": "Patrick Vervoort",
|
||||
"minute": 29
|
||||
}
|
||||
],
|
||||
@@ -1272,7 +1272,7 @@
|
||||
"penalty": true
|
||||
},
|
||||
{
|
||||
"name": "Górriz",
|
||||
"name": "Alberto Górriz",
|
||||
"minute": 38
|
||||
}
|
||||
],
|
||||
@@ -1293,7 +1293,7 @@
|
||||
},
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Fonseca",
|
||||
"name": "Daniel Fonseca",
|
||||
"minute": 90,
|
||||
"offset": 1
|
||||
}
|
||||
@@ -1315,13 +1315,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Lineker",
|
||||
"name": "Gary Lineker",
|
||||
"minute": 9
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Sheedy",
|
||||
"name": "Kevin Sheedy",
|
||||
"minute": 73
|
||||
}
|
||||
],
|
||||
@@ -1342,13 +1342,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Kieft",
|
||||
"name": "Wim Kieft",
|
||||
"minute": 58
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Abdelghani",
|
||||
"name": "Magdi Abdelghani",
|
||||
"minute": 83,
|
||||
"penalty": true
|
||||
}
|
||||
@@ -1400,7 +1400,7 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Wright",
|
||||
"name": "Mark Wright",
|
||||
"minute": 58
|
||||
}
|
||||
],
|
||||
@@ -1421,13 +1421,13 @@
|
||||
},
|
||||
"goals1": [
|
||||
{
|
||||
"name": "Quinn",
|
||||
"name": "Niall Quinn",
|
||||
"minute": 71
|
||||
}
|
||||
],
|
||||
"goals2": [
|
||||
{
|
||||
"name": "Gullit",
|
||||
"name": "Ruud Gullit",
|
||||
"minute": 11
|
||||
}
|
||||
],
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"host": "Italy",
|
||||
"teams_count": 24,
|
||||
"winner": "West Germany",
|
||||
"winner": "Germany",
|
||||
"runner_up": "Argentina",
|
||||
"third_place": "Italy",
|
||||
"fourth_place": "England"
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user