diff --git a/app/components/Flag.tsx b/app/components/Flag.tsx
index 9d92f0b..d365a9d 100644
--- a/app/components/Flag.tsx
+++ b/app/components/Flag.tsx
@@ -1,15 +1,17 @@
"use client";
+import { useState } from "react";
import { Team } from "@/lib/types";
// Zeigt die Flagge/das Wappen eines Teams. Fällt auf ein neutrales Rund
-// zurück, wenn keine crest-URL vorliegt. SVG-Crests (football-data) skalieren
-// sauber; das Rendern als rundes Bild gibt den Flaggen-Look aus dem Screenshot.
+// zurück, wenn keine crest-URL vorliegt oder das Bild nicht geladen werden kann.
export default function Flag({
team, size = 22,
}: { team?: Team; size?: number }) {
+ const [imgFailed, setImgFailed] = useState(false);
const style = { width: size, height: size } as const;
- if (team?.crest) {
+
+ if (team?.crest && !imgFailed) {
return (
setImgFailed(true)}
/>
);
}
diff --git a/lib/feeds.ts b/lib/feeds.ts
index d1a65c9..74cc72b 100644
--- a/lib/feeds.ts
+++ b/lib/feeds.ts
@@ -129,7 +129,7 @@ export async function fetchMatchesAndTeams(): Promise<{ matches: Match[]; teams:
if (!teamMap.has(id)) {
teamMap.set(id, {
id, name: side.name, code: side.tla ?? "", group,
- crest: side.crest ?? null,
+ crest: `/crests/${id}.svg`,
localisedName: localisedTeamName(side.tla ?? "", side.name ?? ""),
});
}
diff --git a/package-lock.json b/package-lock.json
index 0ec24e5..48c7758 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@types/node": "22.10.7",
"@types/react": "19.0.7",
"@types/react-dom": "19.0.3",
+ "tsx": "^4.22.4",
"typescript": "5.7.3"
}
},
@@ -29,6 +30,448 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
+ "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
+ "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
+ "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
+ "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
+ "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
+ "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
+ "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
+ "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
+ "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
+ "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
+ "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
+ "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
+ "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
+ "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
+ "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
+ "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
+ "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
+ "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
+ "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
+ "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
@@ -668,6 +1111,63 @@
"node": ">=8"
}
},
+ "node_modules/esbuild": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
+ "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.1",
+ "@esbuild/android-arm": "0.28.1",
+ "@esbuild/android-arm64": "0.28.1",
+ "@esbuild/android-x64": "0.28.1",
+ "@esbuild/darwin-arm64": "0.28.1",
+ "@esbuild/darwin-x64": "0.28.1",
+ "@esbuild/freebsd-arm64": "0.28.1",
+ "@esbuild/freebsd-x64": "0.28.1",
+ "@esbuild/linux-arm": "0.28.1",
+ "@esbuild/linux-arm64": "0.28.1",
+ "@esbuild/linux-ia32": "0.28.1",
+ "@esbuild/linux-loong64": "0.28.1",
+ "@esbuild/linux-mips64el": "0.28.1",
+ "@esbuild/linux-ppc64": "0.28.1",
+ "@esbuild/linux-riscv64": "0.28.1",
+ "@esbuild/linux-s390x": "0.28.1",
+ "@esbuild/linux-x64": "0.28.1",
+ "@esbuild/netbsd-arm64": "0.28.1",
+ "@esbuild/netbsd-x64": "0.28.1",
+ "@esbuild/openbsd-arm64": "0.28.1",
+ "@esbuild/openbsd-x64": "0.28.1",
+ "@esbuild/openharmony-arm64": "0.28.1",
+ "@esbuild/sunos-x64": "0.28.1",
+ "@esbuild/win32-arm64": "0.28.1",
+ "@esbuild/win32-ia32": "0.28.1",
+ "@esbuild/win32-x64": "0.28.1"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
@@ -918,6 +1418,25 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/tsx": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz",
+ "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.28.0"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
diff --git a/package.json b/package.json
index 7ef31fe..e403b17 100644
--- a/package.json
+++ b/package.json
@@ -14,9 +14,10 @@
"react-dom": "19.0.0"
},
"devDependencies": {
- "typescript": "5.7.3",
"@types/node": "22.10.7",
"@types/react": "19.0.7",
- "@types/react-dom": "19.0.3"
+ "@types/react-dom": "19.0.3",
+ "tsx": "^4.22.4",
+ "typescript": "5.7.3"
}
}
diff --git a/public/crests/1060.svg b/public/crests/1060.svg
new file mode 100644
index 0000000..45845f0
--- /dev/null
+++ b/public/crests/1060.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/1836.svg b/public/crests/1836.svg
new file mode 100644
index 0000000..d6ddb3f
--- /dev/null
+++ b/public/crests/1836.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/1930.svg b/public/crests/1930.svg
new file mode 100644
index 0000000..1f61248
--- /dev/null
+++ b/public/crests/1930.svg
@@ -0,0 +1,24 @@
+
diff --git a/public/crests/1934.svg b/public/crests/1934.svg
new file mode 100644
index 0000000..862681e
--- /dev/null
+++ b/public/crests/1934.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/1935.svg b/public/crests/1935.svg
new file mode 100644
index 0000000..7563a18
--- /dev/null
+++ b/public/crests/1935.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/758.svg b/public/crests/758.svg
new file mode 100644
index 0000000..a01a172
--- /dev/null
+++ b/public/crests/758.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/759.svg b/public/crests/759.svg
new file mode 100644
index 0000000..a42f059
--- /dev/null
+++ b/public/crests/759.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/crests/760.svg b/public/crests/760.svg
new file mode 100644
index 0000000..760fe0d
--- /dev/null
+++ b/public/crests/760.svg
@@ -0,0 +1,581 @@
+
diff --git a/public/crests/761.svg b/public/crests/761.svg
new file mode 100644
index 0000000..7e41611
--- /dev/null
+++ b/public/crests/761.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/762.svg b/public/crests/762.svg
new file mode 100644
index 0000000..af454c2
Binary files /dev/null and b/public/crests/762.svg differ
diff --git a/public/crests/763.svg b/public/crests/763.svg
new file mode 100644
index 0000000..6017337
--- /dev/null
+++ b/public/crests/763.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/crests/764.svg b/public/crests/764.svg
new file mode 100644
index 0000000..a07bcf7
--- /dev/null
+++ b/public/crests/764.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/765.svg b/public/crests/765.svg
new file mode 100644
index 0000000..c3e79d1
--- /dev/null
+++ b/public/crests/765.svg
@@ -0,0 +1,66 @@
+
diff --git a/public/crests/766.svg b/public/crests/766.svg
new file mode 100644
index 0000000..6299e73
--- /dev/null
+++ b/public/crests/766.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/crests/769.svg b/public/crests/769.svg
new file mode 100644
index 0000000..018c462
--- /dev/null
+++ b/public/crests/769.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/770.svg b/public/crests/770.svg
new file mode 100644
index 0000000..52e2702
--- /dev/null
+++ b/public/crests/770.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/crests/771.svg b/public/crests/771.svg
new file mode 100644
index 0000000..9201215
--- /dev/null
+++ b/public/crests/771.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/772.svg b/public/crests/772.svg
new file mode 100644
index 0000000..cf5f3a6
Binary files /dev/null and b/public/crests/772.svg differ
diff --git a/public/crests/773.svg b/public/crests/773.svg
new file mode 100644
index 0000000..c43631e
--- /dev/null
+++ b/public/crests/773.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/774.svg b/public/crests/774.svg
new file mode 100644
index 0000000..9fd94ac
--- /dev/null
+++ b/public/crests/774.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/778.svg b/public/crests/778.svg
new file mode 100644
index 0000000..e1165a7
--- /dev/null
+++ b/public/crests/778.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/779.svg b/public/crests/779.svg
new file mode 100644
index 0000000..bab7eb4
--- /dev/null
+++ b/public/crests/779.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/783.svg b/public/crests/783.svg
new file mode 100644
index 0000000..db87a7f
--- /dev/null
+++ b/public/crests/783.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/788.svg b/public/crests/788.svg
new file mode 100644
index 0000000..5ea9eea
--- /dev/null
+++ b/public/crests/788.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/791.svg b/public/crests/791.svg
new file mode 100644
index 0000000..b673e6e
--- /dev/null
+++ b/public/crests/791.svg
@@ -0,0 +1,519 @@
+
diff --git a/public/crests/792.svg b/public/crests/792.svg
new file mode 100644
index 0000000..9223d14
--- /dev/null
+++ b/public/crests/792.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/798.svg b/public/crests/798.svg
new file mode 100644
index 0000000..db03aba
--- /dev/null
+++ b/public/crests/798.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/799.svg b/public/crests/799.svg
new file mode 100644
index 0000000..39b2287
--- /dev/null
+++ b/public/crests/799.svg
@@ -0,0 +1,240 @@
+
diff --git a/public/crests/801.svg b/public/crests/801.svg
new file mode 100644
index 0000000..d9a6ce8
--- /dev/null
+++ b/public/crests/801.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/802.svg b/public/crests/802.svg
new file mode 100644
index 0000000..a86d3d4
--- /dev/null
+++ b/public/crests/802.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/crests/803.svg b/public/crests/803.svg
new file mode 100644
index 0000000..7f55856
--- /dev/null
+++ b/public/crests/803.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/crests/8030.svg b/public/crests/8030.svg
new file mode 100644
index 0000000..b750f07
--- /dev/null
+++ b/public/crests/8030.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/804.svg b/public/crests/804.svg
new file mode 100644
index 0000000..7e34312
--- /dev/null
+++ b/public/crests/804.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/8049.svg b/public/crests/8049.svg
new file mode 100644
index 0000000..d0284e2
Binary files /dev/null and b/public/crests/8049.svg differ
diff --git a/public/crests/805.svg b/public/crests/805.svg
new file mode 100644
index 0000000..7caa698
--- /dev/null
+++ b/public/crests/805.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/8062.svg b/public/crests/8062.svg
new file mode 100644
index 0000000..f806fcb
--- /dev/null
+++ b/public/crests/8062.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/8070.svg b/public/crests/8070.svg
new file mode 100644
index 0000000..b22b8fb
Binary files /dev/null and b/public/crests/8070.svg differ
diff --git a/public/crests/815.svg b/public/crests/815.svg
new file mode 100644
index 0000000..9faffa1
--- /dev/null
+++ b/public/crests/815.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/816.svg b/public/crests/816.svg
new file mode 100644
index 0000000..a0a161d
--- /dev/null
+++ b/public/crests/816.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/crests/818.svg b/public/crests/818.svg
new file mode 100644
index 0000000..6cb2061
--- /dev/null
+++ b/public/crests/818.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/825.svg b/public/crests/825.svg
new file mode 100644
index 0000000..e53e54a
--- /dev/null
+++ b/public/crests/825.svg
@@ -0,0 +1,78 @@
+
diff --git a/public/crests/828.svg b/public/crests/828.svg
new file mode 100644
index 0000000..f03177d
--- /dev/null
+++ b/public/crests/828.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/836.svg b/public/crests/836.svg
new file mode 100644
index 0000000..8fb20cf
--- /dev/null
+++ b/public/crests/836.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/840.svg b/public/crests/840.svg
new file mode 100644
index 0000000..59b51b5
--- /dev/null
+++ b/public/crests/840.svg
@@ -0,0 +1,31 @@
+
diff --git a/public/crests/8601.svg b/public/crests/8601.svg
new file mode 100644
index 0000000..baed368
--- /dev/null
+++ b/public/crests/8601.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/crests/8872.svg b/public/crests/8872.svg
new file mode 100644
index 0000000..4765e85
--- /dev/null
+++ b/public/crests/8872.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/crests/8873.svg b/public/crests/8873.svg
new file mode 100644
index 0000000..3c68d59
--- /dev/null
+++ b/public/crests/8873.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/crests/9460.svg b/public/crests/9460.svg
new file mode 100644
index 0000000..f2c9853
--- /dev/null
+++ b/public/crests/9460.svg
@@ -0,0 +1,16 @@
+
diff --git a/scripts/fetch-crests.ts b/scripts/fetch-crests.ts
new file mode 100644
index 0000000..e17fed2
--- /dev/null
+++ b/scripts/fetch-crests.ts
@@ -0,0 +1,83 @@
+/**
+ * Einmal-Skript: Lädt alle Team-Crests von football-data.org herunter
+ * und speichert sie unter public/crests/{teamId}.svg.
+ *
+ * Ausführung: npx tsx --env-file=.env scripts/fetch-crests.ts
+ */
+import * as fs from "node:fs";
+import * as path from "node:path";
+
+const CREST_BASE = "https://crests.football-data.org";
+const OUT_DIR = path.resolve(import.meta.dirname, "..", "public", "crests");
+const FD_BASE = "https://api.football-data.org/v4";
+const FD_COMP = "WC";
+
+function fdHeaders(): Record {
+ const token = process.env.FOOTBALL_DATA_TOKEN;
+ if (!token) {
+ console.error("[fehler] FOOTBALL_DATA_TOKEN nicht gesetzt. Bitte .env prüfen.");
+ process.exit(1);
+ }
+ return { "X-Auth-Token": token };
+}
+
+interface FdTeam {
+ id: number;
+ name: string;
+ tla?: string | null;
+ crest?: string | null;
+}
+
+async function main() {
+ console.log("[fetch-crests] Rufe Team-Daten von football-data.org ab…");
+
+ const res = await fetch(`${FD_BASE}/competitions/${FD_COMP}/teams`, {
+ headers: fdHeaders(),
+ });
+ if (!res.ok) {
+ console.error(`[fehler] football-data API: ${res.status} ${res.statusText}`);
+ process.exit(1);
+ }
+
+ const data = (await res.json()) as { teams: FdTeam[] };
+ const teams = data.teams ?? [];
+ console.log(`[fetch-crests] ${teams.length} Teams gefunden.`);
+
+ fs.mkdirSync(OUT_DIR, { recursive: true });
+
+ let ok = 0;
+ let failed = 0;
+ const failures: string[] = [];
+
+ for (const t of teams) {
+ const id = String(t.id);
+ const url = t.crest ?? `${CREST_BASE}/${id}.svg`;
+ const outPath = path.join(OUT_DIR, `${id}.svg`);
+
+ try {
+ const imgRes = await fetch(url);
+ if (!imgRes.ok) {
+ failed++;
+ failures.push(`${t.name} (id=${id}): HTTP ${imgRes.status}`);
+ continue;
+ }
+ const buf = Buffer.from(await imgRes.arrayBuffer());
+ fs.writeFileSync(outPath, buf);
+ ok++;
+ } catch (err) {
+ failed++;
+ failures.push(`${t.name} (id=${id}): ${err instanceof Error ? err.message : String(err)}`);
+ }
+ }
+
+ console.log(`\n[fetch-crests] Fertig: ${ok} geladen, ${failed} fehlgeschlagen.`);
+ if (failures.length > 0) {
+ console.log("[fetch-crests] Fehlgeschlagene:");
+ for (const f of failures) console.log(` - ${f}`);
+ }
+}
+
+main().catch((err) => {
+ console.error("[fehler]", err);
+ process.exit(1);
+});