Compare commits
21 Commits
65e3c0651c
...
98b11f7b9b
| Author | SHA1 | Date | |
|---|---|---|---|
| 98b11f7b9b | |||
| aaf919af0a | |||
| 8c2754cebc | |||
| ba5dac81fd | |||
| 5f73f0f952 | |||
| 4a1fcc6447 | |||
| 04b69611a1 | |||
| 25a55ec94e | |||
| 2b90f977d5 | |||
| 8c8be5273b | |||
| 37f4234c87 | |||
| 29d992affe | |||
| 24d557958a | |||
| 524ccc13d2 | |||
| 8142c72c93 | |||
| 8ca1e3d511 | |||
| 6093553ce5 | |||
| bd7e962f83 | |||
| 9e39547936 | |||
| e58b94022a | |||
| c211aa21bb |
39
flake.nix
39
flake.nix
@ -74,35 +74,6 @@
|
|||||||
timple
|
timple
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
f1python = pkgs.python312.withPackages (p:
|
|
||||||
with p; [
|
|
||||||
# Basic
|
|
||||||
rich
|
|
||||||
|
|
||||||
# Web
|
|
||||||
flask
|
|
||||||
flask-sqlalchemy
|
|
||||||
flask-caching
|
|
||||||
sqlalchemy
|
|
||||||
|
|
||||||
# Test
|
|
||||||
pytest
|
|
||||||
|
|
||||||
# TODO: For some reason, listing those under fastf1.dependencies doesn't work???
|
|
||||||
matplotlib
|
|
||||||
numpy
|
|
||||||
pandas
|
|
||||||
python-dateutil
|
|
||||||
requests
|
|
||||||
requests-cache
|
|
||||||
scipy
|
|
||||||
rapidfuzz
|
|
||||||
websockets
|
|
||||||
timple
|
|
||||||
|
|
||||||
fastf1
|
|
||||||
]);
|
|
||||||
in {
|
in {
|
||||||
devShell = pkgs.devshell.mkShell {
|
devShell = pkgs.devshell.mkShell {
|
||||||
name = "Formula11";
|
name = "Formula11";
|
||||||
@ -110,16 +81,6 @@
|
|||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
nodejs_23
|
nodejs_23
|
||||||
pocketbase
|
pocketbase
|
||||||
|
|
||||||
# nodePackages.autoprefixer
|
|
||||||
# nodePackages.postcss
|
|
||||||
# nodePackages.postcss-cli
|
|
||||||
# nodePackages.sass
|
|
||||||
# nodePackages.svelte-check
|
|
||||||
# nodePackages.tailwindcss
|
|
||||||
|
|
||||||
# f1python
|
|
||||||
# sqlitebrowser
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Use $1 for positional args
|
# Use $1 for positional args
|
||||||
|
|||||||
317
package-lock.json
generated
317
package-lock.json
generated
@ -15,13 +15,11 @@
|
|||||||
"@fsouza/prettierd": "^0.25.4",
|
"@fsouza/prettierd": "^0.25.4",
|
||||||
"@skeletonlabs/skeleton": "^2.10.4",
|
"@skeletonlabs/skeleton": "^2.10.4",
|
||||||
"@skeletonlabs/tw-plugin": "^0.4.0",
|
"@skeletonlabs/tw-plugin": "^0.4.0",
|
||||||
"@sveltejs/adapter-auto": "^3.3.1",
|
|
||||||
"@sveltejs/adapter-node": "^5.2.12",
|
"@sveltejs/adapter-node": "^5.2.12",
|
||||||
"@sveltejs/kit": "^2.16.1",
|
"@sveltejs/kit": "^2.16.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/forms": "^0.5.10",
|
"@tailwindcss/forms": "^0.5.10",
|
||||||
"@types/node": "^22.10.10",
|
"@types/node": "^22.10.10",
|
||||||
"@types/uuid": "^10.0.0",
|
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"pocketbase": "^0.25.1",
|
"pocketbase": "^0.25.1",
|
||||||
@ -33,7 +31,6 @@
|
|||||||
"svelte-check": "^4.1.4",
|
"svelte-check": "^4.1.4",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"uuid": "^11.0.5",
|
|
||||||
"vite": "^6.0.11"
|
"vite": "^6.0.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -87,14 +84,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.26.7",
|
"version": "7.26.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
|
||||||
"integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==",
|
"integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.26.7"
|
"@babel/types": "^7.26.9"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@ -104,9 +101,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.26.7",
|
"version": "7.26.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
|
||||||
"integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==",
|
"integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -1184,9 +1181,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
|
||||||
"integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
|
"integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -1198,9 +1195,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
|
"integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1212,9 +1209,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
|
"integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1226,9 +1223,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
|
"integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -1240,9 +1237,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
|
"integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1254,9 +1251,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
|
"integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -1268,9 +1265,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
|
"integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -1282,9 +1279,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
|
"integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -1296,9 +1293,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
|
"integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1310,9 +1307,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
|
"integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1324,9 +1321,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
|
"integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@ -1338,9 +1335,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
|
"integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@ -1352,9 +1349,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
|
"integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@ -1366,9 +1363,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
|
"integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@ -1380,9 +1377,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
|
"integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -1394,9 +1391,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
|
"integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -1408,9 +1405,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
|
"integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -1422,9 +1419,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
|
"integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -1436,9 +1433,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
|
"integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -1472,19 +1469,6 @@
|
|||||||
"tailwindcss": ">=3.0.0"
|
"tailwindcss": ">=3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/adapter-auto": {
|
|
||||||
"version": "3.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.3.1.tgz",
|
|
||||||
"integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"import-meta-resolve": "^4.1.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@sveltejs/kit": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sveltejs/adapter-node": {
|
"node_modules/@sveltejs/adapter-node": {
|
||||||
"version": "5.2.12",
|
"version": "5.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.12.tgz",
|
||||||
@ -1502,9 +1486,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/kit": {
|
"node_modules/@sveltejs/kit": {
|
||||||
"version": "2.16.1",
|
"version": "2.17.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.17.2.tgz",
|
||||||
"integrity": "sha512-2pF5sgGJx9brYZ/9nNDYnh5KX0JguPF14dnvvtf/MqrvlWrDj/e7Rk3LBJPecFLLK1GRs6ZniD24gFPqZm/NFw==",
|
"integrity": "sha512-Vypk02baf7qd3SOB1uUwUC/3Oka+srPo2J0a8YN3EfJypRshDkNx9HzNKjSmhOnGWwT+SSO06+N0mAb8iVTmTQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1607,9 +1591,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.13.0",
|
"version": "22.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
|
||||||
"integrity": "sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA==",
|
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1623,17 +1607,10 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/uuid": {
|
|
||||||
"version": "10.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
|
||||||
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.21.0",
|
"version": "8.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.0.tgz",
|
||||||
"integrity": "sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==",
|
"integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -1646,21 +1623,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.21.0",
|
"version": "8.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz",
|
||||||
"integrity": "sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==",
|
"integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.21.0",
|
"@typescript-eslint/types": "8.24.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.21.0",
|
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"minimatch": "^9.0.4",
|
"minimatch": "^9.0.4",
|
||||||
"semver": "^7.6.0",
|
"semver": "^7.6.0",
|
||||||
"ts-api-utils": "^2.0.0"
|
"ts-api-utils": "^2.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@ -1674,14 +1651,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.21.0",
|
"version": "8.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz",
|
||||||
"integrity": "sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==",
|
"integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.21.0",
|
"@typescript-eslint/types": "8.24.0",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -1927,9 +1904,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001695",
|
"version": "1.0.30001700",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
|
||||||
"integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
|
"integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2156,9 +2133,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.88",
|
"version": "1.5.101",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz",
|
||||||
"integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==",
|
"integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@ -2242,9 +2219,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/esrap": {
|
"node_modules/esrap": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.5.tgz",
|
||||||
"integrity": "sha512-Xddc1RsoFJ4z9nR7W7BFaEPIp4UXoeQ0+077UdWLxbafMQFyU79sQJMk7kxNgRwQ9/aVgaKacCHC2pUACGwmYw==",
|
"integrity": "sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2276,9 +2253,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.18.0",
|
"version": "1.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
|
||||||
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
|
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -2886,9 +2863,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.1",
|
"version": "8.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz",
|
||||||
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
|
"integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -3036,9 +3013,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.4.2",
|
"version": "3.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
|
||||||
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
"integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -3173,9 +3150,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
|
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -3219,9 +3196,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.32.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
|
||||||
"integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
|
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3235,25 +3212,25 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.32.0",
|
"@rollup/rollup-android-arm-eabi": "4.34.8",
|
||||||
"@rollup/rollup-android-arm64": "4.32.0",
|
"@rollup/rollup-android-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-arm64": "4.32.0",
|
"@rollup/rollup-darwin-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-x64": "4.32.0",
|
"@rollup/rollup-darwin-x64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.32.0",
|
"@rollup/rollup-freebsd-arm64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-x64": "4.32.0",
|
"@rollup/rollup-freebsd-x64": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.32.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.32.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.32.0",
|
"@rollup/rollup-linux-arm64-musl": "4.34.8",
|
||||||
"@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
|
"@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.32.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.32.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.32.0",
|
"@rollup/rollup-linux-x64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.32.0",
|
"@rollup/rollup-linux-x64-musl": "4.34.8",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.32.0",
|
"@rollup/rollup-win32-arm64-msvc": "4.34.8",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.32.0",
|
"@rollup/rollup-win32-ia32-msvc": "4.34.8",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.32.0",
|
"@rollup/rollup-win32-x64-msvc": "4.34.8",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3295,9 +3272,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.3",
|
"version": "7.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@ -3579,9 +3556,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte": {
|
"node_modules/svelte": {
|
||||||
"version": "5.19.6",
|
"version": "5.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.6.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.20.1.tgz",
|
||||||
"integrity": "sha512-6ydekB3qyqUal+UhfMjmVOjRGtxysR8vuiMhi2nwuBtPJWnctVlsGspjVFB05qmR+TXI1emuqtZt81c0XiFleA==",
|
"integrity": "sha512-aCARru2WTdzJl55Ws8SK27+kvQwd8tijl4kY7NoDUXUHtTHhxMa8Lf6QNZKmU7cuPu3jjFloDO1j5HgYJNIIWg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3807,9 +3784,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ts-api-utils": {
|
"node_modules/ts-api-utils": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
|
||||||
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
|
"integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -3893,30 +3870,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
|
||||||
"version": "11.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz",
|
|
||||||
"integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
"https://github.com/sponsors/broofa",
|
|
||||||
"https://github.com/sponsors/ctavan"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/esm/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.0.11",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
|
||||||
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.24.2",
|
"esbuild": "^0.24.2",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.5.1",
|
||||||
"rollup": "^4.23.0"
|
"rollup": "^4.30.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
|
|||||||
@ -14,13 +14,11 @@
|
|||||||
"@fsouza/prettierd": "^0.25.4",
|
"@fsouza/prettierd": "^0.25.4",
|
||||||
"@skeletonlabs/skeleton": "^2.10.4",
|
"@skeletonlabs/skeleton": "^2.10.4",
|
||||||
"@skeletonlabs/tw-plugin": "^0.4.0",
|
"@skeletonlabs/tw-plugin": "^0.4.0",
|
||||||
"@sveltejs/adapter-auto": "^3.3.1",
|
|
||||||
"@sveltejs/adapter-node": "^5.2.12",
|
"@sveltejs/adapter-node": "^5.2.12",
|
||||||
"@sveltejs/kit": "^2.16.1",
|
"@sveltejs/kit": "^2.16.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/forms": "^0.5.10",
|
"@tailwindcss/forms": "^0.5.10",
|
||||||
"@types/node": "^22.10.10",
|
"@types/node": "^22.10.10",
|
||||||
"@types/uuid": "^10.0.0",
|
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"pocketbase": "^0.25.1",
|
"pocketbase": "^0.25.1",
|
||||||
@ -32,7 +30,6 @@
|
|||||||
"svelte-check": "^4.1.4",
|
"svelte-check": "^4.1.4",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"uuid": "^11.0.5",
|
|
||||||
"vite": "^6.0.11"
|
"vite": "^6.0.11"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -9,17 +9,19 @@
|
|||||||
type ToastStore,
|
type ToastStore,
|
||||||
} from "@skeletonlabs/skeleton";
|
} from "@skeletonlabs/skeleton";
|
||||||
import { Button, Input, Card, Dropdown } from "$lib/components";
|
import { Button, Input, Card, Dropdown } from "$lib/components";
|
||||||
import type { Driver, SkeletonData } from "$lib/schema";
|
import type { Driver } from "$lib/schema";
|
||||||
import { DRIVER_HEADSHOT_HEIGHT, DRIVER_HEADSHOT_WIDTH } from "$lib/config";
|
import { DRIVER_HEADSHOT_HEIGHT, DRIVER_HEADSHOT_WIDTH } from "$lib/config";
|
||||||
import { team_dropdown_options } from "$lib/dropdown";
|
import { team_dropdown_options } from "$lib/dropdown";
|
||||||
import { get_driver_headshot_template } from "$lib/database";
|
import { get_driver_headshot_template } from "$lib/database";
|
||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
import type { PageData } from "../../../routes/data/season/drivers/$types";
|
||||||
|
|
||||||
interface DriverCardProps {
|
interface DriverCardProps {
|
||||||
/** Data passed from the page context */
|
/** Data passed from the page context */
|
||||||
data: SkeletonData;
|
data: PageData;
|
||||||
|
|
||||||
/** The [Driver] object used to prefill values. */
|
/** The [Driver] object used to prefill values. */
|
||||||
driver?: Driver;
|
driver?: Driver;
|
||||||
@ -51,7 +53,6 @@
|
|||||||
let active_value: boolean = $state(driver?.active ?? true);
|
let active_value: boolean = $state(driver?.active ?? true);
|
||||||
|
|
||||||
// Database actions
|
// Database actions
|
||||||
// TODO: Headshot compression
|
|
||||||
const update_driver = (create?: boolean): (() => Promise<void>) => {
|
const update_driver = (create?: boolean): (() => Promise<void>) => {
|
||||||
const handler = async (): Promise<void> => {
|
const handler = async (): Promise<void> => {
|
||||||
if (!firstname_input_value || firstname_input_value === "") {
|
if (!firstname_input_value || firstname_input_value === "") {
|
||||||
@ -71,21 +72,47 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Headshot handling
|
||||||
|
let headshot_avif: Blob | undefined = undefined;
|
||||||
|
const headshot_file: File | undefined =
|
||||||
|
headshot_file_value && headshot_file_value.length === 1
|
||||||
|
? headshot_file_value[0]
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (headshot_file) {
|
||||||
|
const headshot_formdata: FormData = new FormData();
|
||||||
|
headshot_formdata.append("image", headshot_file);
|
||||||
|
headshot_formdata.append("width", DRIVER_HEADSHOT_WIDTH.toString());
|
||||||
|
headshot_formdata.append("height", DRIVER_HEADSHOT_HEIGHT.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/compress", {
|
||||||
|
method: "POST",
|
||||||
|
body: headshot_formdata,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
error(500, "Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
headshot_avif = await response.blob();
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const driver_data = {
|
const driver_data = {
|
||||||
firstname: firstname_input_value,
|
firstname: firstname_input_value,
|
||||||
lastname: lastname_input_value,
|
lastname: lastname_input_value,
|
||||||
code: code_input_value,
|
code: code_input_value,
|
||||||
team: team_select_value,
|
team: team_select_value,
|
||||||
active: active_value,
|
active: active_value,
|
||||||
headshot:
|
headshot: headshot_avif,
|
||||||
headshot_file_value && headshot_file_value.length === 1
|
|
||||||
? headshot_file_value[0]
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!headshot_file_value || headshot_file_value.length !== 1) {
|
if (!headshot_avif) {
|
||||||
toastStore.trigger(get_error_toast("Please upload a single driver headshot!"));
|
toastStore.trigger(get_error_toast("Please upload a single driver headshot!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,19 @@
|
|||||||
type ToastStore,
|
type ToastStore,
|
||||||
} from "@skeletonlabs/skeleton";
|
} from "@skeletonlabs/skeleton";
|
||||||
import { Button, Card, Input } from "$lib/components";
|
import { Button, Card, Input } from "$lib/components";
|
||||||
import type { Race, SkeletonData } from "$lib/schema";
|
import type { Race } from "$lib/schema";
|
||||||
import { RACE_PICTOGRAM_HEIGHT, RACE_PICTOGRAM_WIDTH } from "$lib/config";
|
import { RACE_PICTOGRAM_HEIGHT, RACE_PICTOGRAM_WIDTH } from "$lib/config";
|
||||||
import { get_race_pictogram_template } from "$lib/database";
|
import { get_race_pictogram_template } from "$lib/database";
|
||||||
import { format_date } from "$lib/date";
|
import { format_date } from "$lib/date";
|
||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
import type { PageData } from "../../../routes/data/season/races/$types";
|
||||||
|
|
||||||
interface RaceCardProps {
|
interface RaceCardProps {
|
||||||
/** Data passed from the page context */
|
/** Data passed from the page context */
|
||||||
data: SkeletonData;
|
data: PageData;
|
||||||
|
|
||||||
/** The [Race] object used to prefill values. */
|
/** The [Race] object used to prefill values. */
|
||||||
race?: Race;
|
race?: Race;
|
||||||
@ -68,7 +70,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Database actions
|
// Database actions
|
||||||
// TODO: Pictogram compression
|
|
||||||
const update_race = (create?: boolean): (() => Promise<void>) => {
|
const update_race = (create?: boolean): (() => Promise<void>) => {
|
||||||
const handler = async (): Promise<void> => {
|
const handler = async (): Promise<void> => {
|
||||||
if (!name_value || name_value === "") {
|
if (!name_value || name_value === "") {
|
||||||
@ -92,6 +93,33 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pictogram handling
|
||||||
|
let pictogram_avif: Blob | undefined = undefined;
|
||||||
|
const pictogram_file: File | undefined =
|
||||||
|
pictogram_value && pictogram_value.length === 1 ? pictogram_value[0] : undefined;
|
||||||
|
|
||||||
|
if (pictogram_file) {
|
||||||
|
const pictogram_formdata: FormData = new FormData();
|
||||||
|
pictogram_formdata.append("image", pictogram_file);
|
||||||
|
pictogram_formdata.append("width", RACE_PICTOGRAM_WIDTH.toString());
|
||||||
|
pictogram_formdata.append("height", RACE_PICTOGRAM_HEIGHT.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/compress", {
|
||||||
|
method: "POST",
|
||||||
|
body: pictogram_formdata,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
error(500, "Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pictogram_avif = await response.blob();
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const race_data = {
|
const race_data = {
|
||||||
name: name_value,
|
name: name_value,
|
||||||
step: step_value,
|
step: step_value,
|
||||||
@ -106,12 +134,12 @@
|
|||||||
: undefined,
|
: undefined,
|
||||||
qualidate: new Date(qualidate_value).toISOString(),
|
qualidate: new Date(qualidate_value).toISOString(),
|
||||||
racedate: new Date(racedate_value).toISOString(),
|
racedate: new Date(racedate_value).toISOString(),
|
||||||
pictogram: pictogram_value && pictogram_value.length === 1 ? pictogram_value[0] : undefined,
|
pictogram: pictogram_avif,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!pictogram_value || pictogram_value.length !== 1) {
|
if (!pictogram_avif) {
|
||||||
toastStore.trigger(get_error_toast("Please upload a single pictogram!"));
|
toastStore.trigger(get_error_toast("Please upload a single pictogram!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -139,7 +167,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pb.collection("raceresults").delete(race.id);
|
await pb.collection("races").delete(race.id);
|
||||||
invalidateAll();
|
invalidateAll();
|
||||||
modalStore.close();
|
modalStore.close();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,14 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Card, Button, Dropdown } from "$lib/components";
|
import { Card, Button, Dropdown } from "$lib/components";
|
||||||
import type {
|
import type { Driver, RacePick, Substitution } from "$lib/schema";
|
||||||
CurrentPickedUser,
|
|
||||||
Driver,
|
|
||||||
Race,
|
|
||||||
RacePick,
|
|
||||||
RaceResult,
|
|
||||||
SkeletonData,
|
|
||||||
Substitution,
|
|
||||||
} from "$lib/schema";
|
|
||||||
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
||||||
import {
|
import {
|
||||||
getModalStore,
|
getModalStore,
|
||||||
@ -21,15 +13,11 @@
|
|||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
|
import type { PageData } from "../../../routes/racepicks/$types";
|
||||||
|
|
||||||
interface RacePickCardProps {
|
interface RacePickCardProps {
|
||||||
/** Data passed from the page context */
|
/** Data passed from the page context */
|
||||||
data: SkeletonData & {
|
data: PageData;
|
||||||
currentrace: Race;
|
|
||||||
racepicks: Promise<RacePick[]>;
|
|
||||||
currentpickedusers: Promise<CurrentPickedUser[]>;
|
|
||||||
raceresults: Promise<RaceResult[]>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** The [RacePick] object used to prefill values. */
|
/** The [RacePick] object used to prefill values. */
|
||||||
racepick?: RacePick;
|
racepick?: RacePick;
|
||||||
@ -59,7 +47,7 @@
|
|||||||
|
|
||||||
// Reactive state
|
// Reactive state
|
||||||
let required: boolean = $derived(!racepick);
|
let required: boolean = $derived(!racepick);
|
||||||
let disabled: boolean = $derived(!data.admin);
|
let disabled: boolean = false; // TODO: Datelock
|
||||||
let pxx_select_value: string = $state(racepick?.pxx ?? "");
|
let pxx_select_value: string = $state(racepick?.pxx ?? "");
|
||||||
let dnf_select_value: string = $state(racepick?.dnf ?? "");
|
let dnf_select_value: string = $state(racepick?.dnf ?? "");
|
||||||
|
|
||||||
|
|||||||
@ -9,16 +9,17 @@
|
|||||||
type ToastStore,
|
type ToastStore,
|
||||||
} from "@skeletonlabs/skeleton";
|
} from "@skeletonlabs/skeleton";
|
||||||
import { Button, Card, Dropdown } from "$lib/components";
|
import { Button, Card, Dropdown } from "$lib/components";
|
||||||
import type { Driver, Race, RaceResult, SkeletonData } from "$lib/schema";
|
import type { Driver, Race, RaceResult } from "$lib/schema";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value } from "$lib/database";
|
||||||
import { race_dropdown_options } from "$lib/dropdown";
|
import { race_dropdown_options } from "$lib/dropdown";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
|
import type { PageData } from "../../../routes/data/raceresults/$types";
|
||||||
|
|
||||||
interface RaceResultCardProps {
|
interface RaceResultCardProps {
|
||||||
/** Data passed from the page context */
|
/** Data passed from the page context */
|
||||||
data: SkeletonData & { results: RaceResult[] };
|
data: PageData;
|
||||||
|
|
||||||
/** The [RaceResult] object used to prefill values. */
|
/** The [RaceResult] object used to prefill values. */
|
||||||
result?: RaceResult;
|
result?: RaceResult;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Card, Button, Dropdown } from "$lib/components";
|
import { Card, Button, Dropdown } from "$lib/components";
|
||||||
import type { Driver, SkeletonData, Substitution } from "$lib/schema";
|
import type { Driver, Substitution } from "$lib/schema";
|
||||||
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
||||||
import {
|
import {
|
||||||
getModalStore,
|
getModalStore,
|
||||||
@ -13,10 +13,11 @@
|
|||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
|
import type { PageData } from "../../../routes/data/season/substitutions/$types";
|
||||||
|
|
||||||
interface SubstitutionCardProps {
|
interface SubstitutionCardProps {
|
||||||
/** Data passed from the page context */
|
/** Data passed from the page context */
|
||||||
data: SkeletonData;
|
data: PageData;
|
||||||
|
|
||||||
/** The [Substitution] object used to prefill values. */
|
/** The [Substitution] object used to prefill values. */
|
||||||
substitution?: Substitution;
|
substitution?: Substitution;
|
||||||
|
|||||||
@ -8,16 +8,23 @@
|
|||||||
type ToastStore,
|
type ToastStore,
|
||||||
} from "@skeletonlabs/skeleton";
|
} from "@skeletonlabs/skeleton";
|
||||||
import { Card, Button, Input, LazyImage } from "$lib/components";
|
import { Card, Button, Input, LazyImage } from "$lib/components";
|
||||||
import type { SkeletonData, Team } from "$lib/schema";
|
import type { Team } from "$lib/schema";
|
||||||
import { TEAM_BANNER_HEIGHT, TEAM_BANNER_WIDTH } from "$lib/config";
|
import {
|
||||||
|
TEAM_BANNER_HEIGHT,
|
||||||
|
TEAM_BANNER_WIDTH,
|
||||||
|
TEAM_LOGO_HEIGHT,
|
||||||
|
TEAM_LOGO_WIDTH,
|
||||||
|
} from "$lib/config";
|
||||||
import { get_team_banner_template, get_team_logo_template } from "$lib/database";
|
import { get_team_banner_template, get_team_logo_template } from "$lib/database";
|
||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidateAll } from "$app/navigation";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
import type { PageData } from "../../../routes/data/season/teams/$types";
|
||||||
|
|
||||||
interface TeamCardProps {
|
interface TeamCardProps {
|
||||||
/** Data from the page context */
|
/** Data from the page context */
|
||||||
data: SkeletonData;
|
data: PageData;
|
||||||
|
|
||||||
/** The [Team] object used to prefill values. */
|
/** The [Team] object used to prefill values. */
|
||||||
team?: Team;
|
team?: Team;
|
||||||
@ -47,7 +54,6 @@
|
|||||||
let logo_value: FileList | undefined = $state();
|
let logo_value: FileList | undefined = $state();
|
||||||
|
|
||||||
// Database actions
|
// Database actions
|
||||||
// TODO: Banner + logo compression
|
|
||||||
const update_team = (create?: boolean): (() => Promise<void>) => {
|
const update_team = (create?: boolean): (() => Promise<void>) => {
|
||||||
const handler = async (): Promise<void> => {
|
const handler = async (): Promise<void> => {
|
||||||
if (!name_value || name_value === "") {
|
if (!name_value || name_value === "") {
|
||||||
@ -59,20 +65,83 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const team_data = {
|
// Banner handling
|
||||||
|
let banner_avif: Blob | undefined = undefined;
|
||||||
|
const banner_file: File | undefined =
|
||||||
|
banner_value && banner_value.length === 1 ? banner_value[0] : undefined;
|
||||||
|
|
||||||
|
if (banner_file) {
|
||||||
|
const banner_formdata: FormData = new FormData();
|
||||||
|
banner_formdata.append("image", banner_file);
|
||||||
|
banner_formdata.append("width", TEAM_BANNER_WIDTH.toString());
|
||||||
|
banner_formdata.append("height", TEAM_BANNER_HEIGHT.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/compress", {
|
||||||
|
method: "POST",
|
||||||
|
body: banner_formdata,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
error(500, "Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
banner_avif = await response.blob();
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logo handling
|
||||||
|
let logo_avif: Blob | undefined = undefined;
|
||||||
|
const logo_file: File | undefined =
|
||||||
|
logo_value && logo_value.length === 1 ? logo_value[0] : undefined;
|
||||||
|
|
||||||
|
if (logo_file) {
|
||||||
|
const logo_formdata: FormData = new FormData();
|
||||||
|
logo_formdata.append("image", logo_file);
|
||||||
|
logo_formdata.append("width", TEAM_LOGO_WIDTH.toString());
|
||||||
|
logo_formdata.append("height", TEAM_LOGO_HEIGHT.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/compress", {
|
||||||
|
method: "POST",
|
||||||
|
body: logo_formdata,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
error(500, "Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
logo_avif = await response.blob();
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let team_data = {
|
||||||
name: name_value,
|
name: name_value,
|
||||||
color: color_value,
|
color: color_value,
|
||||||
banner: banner_value && banner_value.length === 1 ? banner_value[0] : undefined,
|
banner: banner_avif,
|
||||||
logo: logo_value && logo_value.length === 1 ? logo_value[0] : undefined,
|
logo: logo_avif,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// HACK: Having only a single file for the update request
|
||||||
|
// doesn't work with pocketbase for some reason
|
||||||
|
if (team_data.banner === undefined) {
|
||||||
|
delete team_data.banner;
|
||||||
|
}
|
||||||
|
if (team_data.logo === undefined) {
|
||||||
|
delete team_data.logo;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!banner_value || banner_value.length !== 1) {
|
if (!banner_avif) {
|
||||||
toastStore.trigger(get_error_toast("Please upload a single team banner!"));
|
toastStore.trigger(get_error_toast("Please upload a single team banner!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!logo_value || logo_value.length !== 1) {
|
if (!logo_avif) {
|
||||||
toastStore.trigger(get_error_toast("Please upload a single team logo!"));
|
toastStore.trigger(get_error_toast("Please upload a single team logo!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
172
src/lib/fetch.ts
Normal file
172
src/lib/fetch.ts
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import { pb } from "./pocketbase";
|
||||||
|
import type {
|
||||||
|
CurrentPickedUser,
|
||||||
|
Driver,
|
||||||
|
Graphic,
|
||||||
|
Race,
|
||||||
|
RacePick,
|
||||||
|
RaceResult,
|
||||||
|
Substitution,
|
||||||
|
Team,
|
||||||
|
User,
|
||||||
|
} from "./schema";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Graphics] from the database with file URLs
|
||||||
|
*/
|
||||||
|
export const fetch_graphics = async (fetch: (_: any) => Promise<Response>): Promise<Graphic[]> => {
|
||||||
|
const graphics: Graphic[] = await pb.collection("graphics").getFullList({ fetch: fetch });
|
||||||
|
|
||||||
|
graphics.map((graphic: Graphic) => {
|
||||||
|
graphic.file_url = pb.files.getURL(graphic, graphic.file);
|
||||||
|
});
|
||||||
|
|
||||||
|
return graphics;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Teams] (sorted ascending by name) from the database with file URLs for banners/logos
|
||||||
|
*/
|
||||||
|
export const fetch_teams = async (fetch: (_: any) => Promise<Response>): Promise<Team[]> => {
|
||||||
|
const teams: Team[] = await pb.collection("teams").getFullList({
|
||||||
|
sort: "+name",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
teams.map((team: Team) => {
|
||||||
|
team.banner_url = pb.files.getURL(team, team.banner);
|
||||||
|
team.logo_url = pb.files.getURL(team, team.logo);
|
||||||
|
});
|
||||||
|
|
||||||
|
return teams;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Drivers] (sorted ascending by code) from the database with file URLs for headshots
|
||||||
|
*/
|
||||||
|
export const fetch_drivers = async (fetch: (_: any) => Promise<Response>): Promise<Driver[]> => {
|
||||||
|
const drivers: Driver[] = await pb.collection("drivers").getFullList({
|
||||||
|
sort: "+code",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
drivers.map((driver: Driver) => {
|
||||||
|
driver.headshot_url = pb.files.getURL(driver, driver.headshot);
|
||||||
|
});
|
||||||
|
|
||||||
|
return drivers;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Races] (sorted ascending by step) from the database with file URLs for pictograms
|
||||||
|
*/
|
||||||
|
export const fetch_races = async (fetch: (_: any) => Promise<Response>): Promise<Race[]> => {
|
||||||
|
const races: Race[] = await pb.collection("races").getFullList({
|
||||||
|
sort: "+step",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
races.map((race: Race) => {
|
||||||
|
race.pictogram_url = pb.files.getURL(race, race.pictogram);
|
||||||
|
});
|
||||||
|
|
||||||
|
return races;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Substitutions] (sorted ascending by race step) from the database
|
||||||
|
*/
|
||||||
|
export const fetch_substitutions = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<Substitution[]> => {
|
||||||
|
const substitutions: Substitution[] = await pb.collection("substitutions").getFullList({
|
||||||
|
expand: "race",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort by race step (ascending)
|
||||||
|
substitutions.sort((a: Substitution, b: Substitution) => a.expand.race.step - b.expand.race.step);
|
||||||
|
|
||||||
|
return substitutions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [RaceResults] (sorted descending by race step - newest first) from the database
|
||||||
|
*/
|
||||||
|
export const fetch_raceresults = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<RaceResult[]> => {
|
||||||
|
const raceresults: RaceResult[] = await pb
|
||||||
|
.collection("raceresultsdesc")
|
||||||
|
.getFullList({ fetch: fetch });
|
||||||
|
|
||||||
|
return raceresults;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Users] (sorted ascending by username) with file URLs for avatars
|
||||||
|
*/
|
||||||
|
export const fetch_users = async (fetch: (_: any) => Promise<Response>): Promise<User[]> => {
|
||||||
|
const users: User[] = await pb
|
||||||
|
.collection("users")
|
||||||
|
.getFullList({ fetch: fetch, sort: "+username" });
|
||||||
|
|
||||||
|
users.map((user: User) => {
|
||||||
|
if (user.avatar) {
|
||||||
|
user.avatar_url = pb.files.getURL(user, user.avatar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return users;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the first [Race] without result from the database with file URL for the pictogram
|
||||||
|
*/
|
||||||
|
export const fetch_currentrace = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<Race | null> => {
|
||||||
|
const currentrace: Race[] = await pb.collection("currentrace").getFullList({ fetch: fetch });
|
||||||
|
|
||||||
|
// The currentrace collection either has a single or no entries
|
||||||
|
if (currentrace.length == 0) return null;
|
||||||
|
|
||||||
|
currentrace[0].pictogram_url = pb.files.getURL(currentrace[0], currentrace[0].pictogram);
|
||||||
|
|
||||||
|
return currentrace[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [RacePicks] from the database
|
||||||
|
*/
|
||||||
|
export const fetch_racepicks = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<RacePick[]> => {
|
||||||
|
// Don't expand race/pxx/dnf since we already fetched those
|
||||||
|
const racepicks: RacePick[] = await pb
|
||||||
|
.collection("racepicks")
|
||||||
|
.getFullList({ fetch: fetch, expand: "user" });
|
||||||
|
|
||||||
|
return racepicks;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [Users] (with the extra field "picked" that is truthy
|
||||||
|
* if the user already picked for the current race)
|
||||||
|
* for the current race with file URLs for the avatars
|
||||||
|
*/
|
||||||
|
export const fetch_currentpickedusers = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<CurrentPickedUser[]> => {
|
||||||
|
const currentpickedusers: CurrentPickedUser[] = await pb
|
||||||
|
.collection("currentpickedusers")
|
||||||
|
.getFullList({ fetch: fetch });
|
||||||
|
|
||||||
|
currentpickedusers.map((currentpickeduser: CurrentPickedUser) => {
|
||||||
|
if (currentpickeduser.avatar) {
|
||||||
|
currentpickeduser.avatar_url = pb.files.getURL(currentpickeduser, currentpickeduser.avatar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return currentpickedusers;
|
||||||
|
};
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import Pocketbase, { type AuthRecord } from "pocketbase";
|
import Pocketbase, { type AuthRecord, type RecordModel, type RecordSubscription } from "pocketbase";
|
||||||
import type { Graphic, User } from "$lib/schema";
|
import type { Graphic, User } from "$lib/schema";
|
||||||
import { env } from "$env/dynamic/public";
|
import { env } from "$env/dynamic/public";
|
||||||
|
import { invalidate } from "$app/navigation";
|
||||||
|
|
||||||
export let pb = new Pocketbase(env.PUBLIC_PBURL || "http://192.168.86.50:8090");
|
export let pb = new Pocketbase(env.PUBLIC_PBURL || "http://192.168.86.50:8090");
|
||||||
export let pbUser: User | undefined = undefined;
|
export let pbUser: User | undefined = undefined;
|
||||||
@ -8,6 +9,7 @@ export let pbUser: User | undefined = undefined;
|
|||||||
const update_user = async (record: AuthRecord): Promise<void> => {
|
const update_user = async (record: AuthRecord): Promise<void> => {
|
||||||
if (!record) {
|
if (!record) {
|
||||||
pbUser = undefined;
|
pbUser = undefined;
|
||||||
|
console.log("Returning with pbUser = undefined");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,8 +34,25 @@ const update_user = async (record: AuthRecord): Promise<void> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update the pbUser object when authStore changes (e.g. after logging in)
|
// Update the pbUser object when authStore changes (e.g. after logging in)
|
||||||
pb.authStore.onChange(() => {
|
pb.authStore.onChange(async () => {
|
||||||
update_user(pb.authStore.record);
|
await update_user(pb.authStore.record);
|
||||||
// console.log("Updating pbUser...")
|
|
||||||
// console.dir(pbUser, { depth: null });
|
// TODO: If the user has not chosen an avatar,
|
||||||
|
// the page keeps displaying the "Login" button (wtf)
|
||||||
|
console.log("Updating pbUser...");
|
||||||
|
console.dir(pbUser, { depth: null });
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
export const subscribe = (collections: string[]) => {
|
||||||
|
collections.forEach((collection: string) => {
|
||||||
|
pb.collection(collection).subscribe("*", (event: RecordSubscription<RecordModel>) => {
|
||||||
|
invalidate(`data:${collection}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unsubscribe = (collections: string[]) => {
|
||||||
|
collections.forEach((collection: string) => {
|
||||||
|
pb.collection(collection).unsubscribe("*");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -3,20 +3,6 @@
|
|||||||
|
|
||||||
// Application Data
|
// Application Data
|
||||||
|
|
||||||
/**
|
|
||||||
* The data returned from the root layout's [load]-function.
|
|
||||||
*/
|
|
||||||
export interface SkeletonData {
|
|
||||||
user: User;
|
|
||||||
admin: boolean;
|
|
||||||
|
|
||||||
graphics: Promise<Graphic[]>;
|
|
||||||
teams: Promise<Team[]>;
|
|
||||||
drivers: Promise<Driver[]>;
|
|
||||||
races: Promise<Race[]>;
|
|
||||||
substitutions: Promise<Substitution[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Graphic {
|
export interface Graphic {
|
||||||
name: string;
|
name: string;
|
||||||
file: string;
|
file: string;
|
||||||
@ -27,7 +13,7 @@ export interface User {
|
|||||||
id: string;
|
id: string;
|
||||||
username: string;
|
username: string;
|
||||||
firstname: string;
|
firstname: string;
|
||||||
avatar: string;
|
avatar?: string;
|
||||||
avatar_url?: string;
|
avatar_url?: string;
|
||||||
admin: boolean;
|
admin: boolean;
|
||||||
}
|
}
|
||||||
@ -53,9 +39,6 @@ export interface Driver {
|
|||||||
headshot_url?: string;
|
headshot_url?: string;
|
||||||
team: string;
|
team: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
expand: {
|
|
||||||
team: Team;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Race {
|
export interface Race {
|
||||||
|
|||||||
@ -7,17 +7,21 @@ import sharp from "sharp";
|
|||||||
*/
|
*/
|
||||||
export const image_to_avif = async (
|
export const image_to_avif = async (
|
||||||
data: ArrayBuffer,
|
data: ArrayBuffer,
|
||||||
width: number | undefined = undefined,
|
width?: number,
|
||||||
height: number | undefined = undefined,
|
height?: number,
|
||||||
quality: number = 50,
|
quality: number = 50,
|
||||||
effort: number = 4,
|
effort: number = 4,
|
||||||
): Promise<Blob> => {
|
): Promise<Blob> => {
|
||||||
|
console.log(
|
||||||
|
`Compressing ${data.byteLength} Bytes to ${width ?? -1}x${height ?? -1} avif with quality ${quality} and effort ${effort}...`,
|
||||||
|
);
|
||||||
|
|
||||||
const compressed: Buffer = await sharp(data)
|
const compressed: Buffer = await sharp(data)
|
||||||
.resize(width, height)
|
.resize(width, height)
|
||||||
.avif({ quality: quality, effort: effort })
|
.avif({ quality: quality, effort: effort })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
console.log(`image_to_avif: ${data.byteLength} Bytes -> ${compressed.length} Bytes`);
|
console.log(`Compressed ${data.byteLength} Bytes to ${compressed.length} Bytes`);
|
||||||
|
|
||||||
return new Blob([compressed]);
|
return new Blob([compressed]);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "../app.css";
|
import "../app.css";
|
||||||
import type { Snippet } from "svelte";
|
import { onDestroy, onMount, type Snippet } from "svelte";
|
||||||
import type { LayoutData } from "./$types";
|
import type { LayoutData } from "./$types";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
import {
|
import {
|
||||||
@ -19,7 +19,6 @@
|
|||||||
RaceResultCard,
|
RaceResultCard,
|
||||||
} from "$lib/components";
|
} from "$lib/components";
|
||||||
import { get_avatar_preview_event_handler } from "$lib/image";
|
import { get_avatar_preview_event_handler } from "$lib/image";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
storePopup,
|
storePopup,
|
||||||
@ -39,9 +38,11 @@
|
|||||||
getToastStore,
|
getToastStore,
|
||||||
} from "@skeletonlabs/skeleton";
|
} from "@skeletonlabs/skeleton";
|
||||||
import { computePosition, autoUpdate, offset, shift, flip, arrow } from "@floating-ui/dom";
|
import { computePosition, autoUpdate, offset, shift, flip, arrow } from "@floating-ui/dom";
|
||||||
import { invalidateAll } from "$app/navigation";
|
import { invalidate } from "$app/navigation";
|
||||||
import { get_error_toast } from "$lib/toast";
|
import { get_error_toast } from "$lib/toast";
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb, subscribe, unsubscribe } from "$lib/pocketbase";
|
||||||
|
import { AVATAR_HEIGHT, AVATAR_WIDTH } from "$lib/config";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
|
||||||
let { data, children }: { data: LayoutData; children: Snippet } = $props();
|
let { data, children }: { data: LayoutData; children: Snippet } = $props();
|
||||||
|
|
||||||
@ -133,28 +134,26 @@
|
|||||||
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
// Reactive state
|
// Reactive state
|
||||||
let username_value: string = $state("");
|
let username_value: string = $state(data.user?.username ?? "");
|
||||||
let firstname_value: string = $state("");
|
let firstname_value: string = $state(data.user?.firstname ?? "");
|
||||||
let password_value: string = $state("");
|
let password_value: string = $state("");
|
||||||
let avatar_value: FileList | undefined = $state();
|
let avatar_value: FileList | undefined = $state();
|
||||||
|
|
||||||
// Database actions
|
// Database actions
|
||||||
// TODO: Avatar compression
|
|
||||||
const login = async (): Promise<void> => {
|
const login = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await pb.collection("users").authWithPassword(username_value, password_value);
|
await pb.collection("users").authWithPassword(username_value, password_value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toastStore.trigger(get_error_toast("" + error));
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
}
|
}
|
||||||
await invalidateAll();
|
await invalidate("data:user");
|
||||||
drawerStore.close();
|
drawerStore.close();
|
||||||
password_value = "";
|
password_value = "";
|
||||||
firstname_value = data.user?.firstname ?? "";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
pb.authStore.clear();
|
pb.authStore.clear();
|
||||||
await invalidateAll();
|
await invalidate("data:user");
|
||||||
drawerStore.close();
|
drawerStore.close();
|
||||||
username_value = "";
|
username_value = "";
|
||||||
firstname_value = "";
|
firstname_value = "";
|
||||||
@ -171,23 +170,50 @@
|
|||||||
toastStore.trigger(get_error_toast("Please enter your first name!"));
|
toastStore.trigger(get_error_toast("Please enter your first name!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avatar handling
|
||||||
|
let avatar_avif: Blob | undefined = undefined;
|
||||||
|
const avatar_file: File | undefined =
|
||||||
|
avatar_value && avatar_value.length === 1 ? avatar_value[0] : undefined;
|
||||||
|
|
||||||
|
if (avatar_file) {
|
||||||
|
const avatar_formdata: FormData = new FormData();
|
||||||
|
avatar_formdata.append("image", avatar_file);
|
||||||
|
avatar_formdata.append("width", AVATAR_WIDTH.toString());
|
||||||
|
avatar_formdata.append("height", AVATAR_HEIGHT.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/compress", {
|
||||||
|
method: "POST",
|
||||||
|
body: avatar_formdata,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
error(500, "Compression failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
avatar_avif = await response.blob();
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (create) {
|
||||||
if (!password_value || password_value === "") {
|
if (!password_value || password_value === "") {
|
||||||
toastStore.trigger(get_error_toast("Please enter a password!"));
|
toastStore.trigger(get_error_toast("Please enter a password!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if (create) {
|
|
||||||
await pb.collection("users").create({
|
await pb.collection("users").create({
|
||||||
username: username_value,
|
username: username_value,
|
||||||
firstname: firstname_value,
|
firstname: firstname_value,
|
||||||
password: password_value,
|
password: password_value,
|
||||||
passwordConfirm: password_value,
|
passwordConfirm: password_value, // lol
|
||||||
admin: false,
|
admin: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
await login();
|
await login();
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
if (!data.user?.id || data.user.id === "") {
|
if (!data.user?.id || data.user.id === "") {
|
||||||
toastStore.trigger(get_error_toast("Invalid user id!"));
|
toastStore.trigger(get_error_toast("Invalid user id!"));
|
||||||
@ -197,12 +223,12 @@
|
|||||||
await pb.collection("users").update(data.user.id, {
|
await pb.collection("users").update(data.user.id, {
|
||||||
username: username_value,
|
username: username_value,
|
||||||
firstname: firstname_value,
|
firstname: firstname_value,
|
||||||
avatar: avatar_value && avatar_value.length === 1 ? avatar_value[0] : undefined,
|
avatar: avatar_avif,
|
||||||
});
|
});
|
||||||
|
|
||||||
invalidateAll();
|
|
||||||
drawerStore.close();
|
drawerStore.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invalidate("data:users");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toastStore.trigger(get_error_toast("" + error));
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
}
|
}
|
||||||
@ -210,6 +236,39 @@
|
|||||||
|
|
||||||
return handler;
|
return handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Real-time updates without reloading
|
||||||
|
onMount(() =>
|
||||||
|
subscribe([
|
||||||
|
"users",
|
||||||
|
"drivers",
|
||||||
|
"racepicks",
|
||||||
|
"raceresults",
|
||||||
|
"races",
|
||||||
|
"seasonpicks",
|
||||||
|
"substitutions",
|
||||||
|
"teams",
|
||||||
|
"currentpickedusers",
|
||||||
|
"currentrace",
|
||||||
|
"raceresultdesc",
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
onDestroy(() =>
|
||||||
|
unsubscribe([
|
||||||
|
"users",
|
||||||
|
"drivers",
|
||||||
|
"racepicks",
|
||||||
|
"raceresults",
|
||||||
|
"races",
|
||||||
|
"seasonpicks",
|
||||||
|
"substitutions",
|
||||||
|
"teams",
|
||||||
|
"currentpickedusers",
|
||||||
|
"currentrace",
|
||||||
|
"raceresultdesc",
|
||||||
|
]),
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
|
|||||||
@ -1,91 +1,24 @@
|
|||||||
import { pb, pbUser } from "$lib/pocketbase";
|
import { fetch_graphics } from "$lib/fetch";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
import type { LayoutLoad } from "./$types";
|
||||||
|
|
||||||
// This makes the page client-side rendered
|
// This makes the page client-side rendered
|
||||||
export const ssr = false;
|
export const ssr = false;
|
||||||
|
|
||||||
import type { Driver, Graphic, Race, Substitution, Team } from "$lib/schema";
|
|
||||||
import type { LayoutLoad } from "./$types";
|
|
||||||
|
|
||||||
// On each page load (every route), this function runs serverside.
|
// On each page load (every route), this function runs serverside.
|
||||||
// The "locals.user" object is only available on the server,
|
// The "locals.user" object is only available on the server,
|
||||||
// since it's populated inside hooks.server.ts per request.
|
// since it's populated inside hooks.server.ts per request.
|
||||||
// It will populate the "user" attribute of each page's "data" object,
|
// It will populate the "user" attribute of each page's "data" object,
|
||||||
// so each page has access to the current user (or knows if no one is signed in).
|
// so each page has access to the current user (or knows if no one is signed in).
|
||||||
export const load: LayoutLoad = () => {
|
export const load: LayoutLoad = async ({ fetch, depends }) => {
|
||||||
const fetch_graphics = async (): Promise<Graphic[]> => {
|
depends("data:graphics", "data:user");
|
||||||
const graphics: Graphic[] = await pb.collection("graphics").getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
graphics.map((graphic: Graphic) => {
|
|
||||||
graphic.file_url = pb.files.getURL(graphic, graphic.file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return graphics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_teams = async (): Promise<Team[]> => {
|
|
||||||
const teams: Team[] = await pb.collection("teams").getFullList({
|
|
||||||
sort: "+name",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
teams.map((team: Team) => {
|
|
||||||
team.banner_url = pb.files.getURL(team, team.banner);
|
|
||||||
team.logo_url = pb.files.getURL(team, team.logo);
|
|
||||||
});
|
|
||||||
|
|
||||||
return teams;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_drivers = async (): Promise<Driver[]> => {
|
|
||||||
const drivers: Driver[] = await pb.collection("drivers").getFullList({
|
|
||||||
sort: "+code",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
drivers.map((driver: Driver) => {
|
|
||||||
driver.headshot_url = pb.files.getURL(driver, driver.headshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
return drivers;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_races = async (): Promise<Race[]> => {
|
|
||||||
const races: Race[] = await pb.collection("races").getFullList({
|
|
||||||
sort: "+step",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
races.map((race: Race) => {
|
|
||||||
race.pictogram_url = pb.files.getURL(race, race.pictogram);
|
|
||||||
});
|
|
||||||
|
|
||||||
return races;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_substitutions = async (): Promise<Substitution[]> => {
|
|
||||||
const substitutions: Substitution[] = await pb.collection("substitutions").getFullList({
|
|
||||||
expand: "race",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort by race step (ascending)
|
|
||||||
substitutions.sort(
|
|
||||||
(a: Substitution, b: Substitution) => a.expand.race.step - b.expand.race.step,
|
|
||||||
);
|
|
||||||
|
|
||||||
return substitutions;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// User information
|
// User information (synchronous)
|
||||||
user: pbUser,
|
user: pbUser,
|
||||||
admin: pbUser?.admin ?? false,
|
admin: pbUser?.admin ?? false,
|
||||||
|
|
||||||
// Return static data asynchronously
|
// Return static data
|
||||||
graphics: fetch_graphics(),
|
graphics: await fetch_graphics(fetch),
|
||||||
teams: fetch_teams(),
|
|
||||||
drivers: fetch_drivers(),
|
|
||||||
races: fetch_races(),
|
|
||||||
substitutions: fetch_substitutions(),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
45
src/routes/api/compress/+server.ts
Normal file
45
src/routes/api/compress/+server.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { image_to_avif } from "$lib/server/image";
|
||||||
|
import { error } from "@sveltejs/kit";
|
||||||
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This route is available at /api/compress.
|
||||||
|
* It will return the image as a compressed [avif] [Blob].
|
||||||
|
* We need this because [sharp] is a server-side node library.
|
||||||
|
*/
|
||||||
|
export const POST: RequestHandler = async ({ request }) => {
|
||||||
|
console.log("Hit /api/compress...");
|
||||||
|
const data: FormData = await request.formData();
|
||||||
|
|
||||||
|
const image: File | undefined = data.has("image") ? (data.get("image") as File) : undefined;
|
||||||
|
const width: number | undefined = data.has("width")
|
||||||
|
? parseInt(data.get("width")?.toString() ?? "-1")
|
||||||
|
: undefined;
|
||||||
|
const height: number | undefined = data.has("height")
|
||||||
|
? parseInt(data.get("height")?.toString() ?? "-1")
|
||||||
|
: undefined;
|
||||||
|
const quality: number | undefined = data.has("quality")
|
||||||
|
? parseInt(data.get("quality")?.toString() ?? "-1")
|
||||||
|
: undefined;
|
||||||
|
const effort: number | undefined = data.has("effort")
|
||||||
|
? parseInt(data.get("effort")?.toString() ?? "-1")
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
error(500, "Can't compress image without image data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const compressedImage: Blob = await image_to_avif(
|
||||||
|
await image.arrayBuffer(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
quality,
|
||||||
|
effort,
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Response(compressedImage, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "image/avif",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -11,7 +11,11 @@
|
|||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
|
|
||||||
const result_handler = async (event: Event, id?: string) => {
|
const result_handler = async (event: Event, id?: string) => {
|
||||||
const result: RaceResult | undefined = get_by_value(data.results, "id", id ?? "Invalid");
|
const result: RaceResult | undefined = get_by_value(
|
||||||
|
await data.raceresults,
|
||||||
|
"id",
|
||||||
|
id ?? "Invalid",
|
||||||
|
);
|
||||||
|
|
||||||
if (id && !result) return;
|
if (id && !result) return;
|
||||||
|
|
||||||
@ -90,4 +94,6 @@
|
|||||||
<span class="font-bold">Create Race Result</span>
|
<span class="font-bold">Create Race Result</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Table data={data.results} columns={results_columns} handler={result_handler} />
|
{#await data.raceresults then results}
|
||||||
|
<Table data={results} columns={results_columns} handler={result_handler} />
|
||||||
|
{/await}
|
||||||
|
|||||||
@ -1,18 +1,12 @@
|
|||||||
import { pb } from "$lib/pocketbase";
|
import { fetch_drivers, fetch_raceresults, fetch_races } from "$lib/fetch";
|
||||||
import type { RaceResult } from "$lib/schema";
|
|
||||||
import type { PageLoad } from "../../$types";
|
import type { PageLoad } from "../../$types";
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch }) => {
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
// TODO: Duplicated code from racepicks/+page.server.ts
|
depends("data:drivers", "data:races", "data:raceresults");
|
||||||
const fetch_raceresults = async (): Promise<RaceResult[]> => {
|
|
||||||
const raceresults: RaceResult[] = await pb
|
|
||||||
.collection("raceresultsdesc")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
return raceresults;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
results: await fetch_raceresults(),
|
drivers: fetch_drivers(fetch),
|
||||||
|
races: fetch_races(fetch),
|
||||||
|
raceresults: fetch_raceresults(fetch),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
11
src/routes/data/season/drivers/+page.ts
Normal file
11
src/routes/data/season/drivers/+page.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { fetch_drivers, fetch_teams } from "$lib/fetch";
|
||||||
|
import type { PageLoad } from "../../../$types";
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
|
depends("data:teams", "data:drivers");
|
||||||
|
|
||||||
|
return {
|
||||||
|
teams: fetch_teams(fetch),
|
||||||
|
drivers: fetch_drivers(fetch),
|
||||||
|
};
|
||||||
|
};
|
||||||
10
src/routes/data/season/races/+page.ts
Normal file
10
src/routes/data/season/races/+page.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { fetch_races } from "$lib/fetch";
|
||||||
|
import type { PageLoad } from "../../../$types";
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
|
depends("data:races");
|
||||||
|
|
||||||
|
return {
|
||||||
|
races: fetch_races(fetch),
|
||||||
|
};
|
||||||
|
};
|
||||||
12
src/routes/data/season/substitutions/+page.ts
Normal file
12
src/routes/data/season/substitutions/+page.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { fetch_drivers, fetch_races, fetch_substitutions } from "$lib/fetch";
|
||||||
|
import type { PageLoad } from "../../../$types";
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
|
depends("data:races", "data:drivers", "data:substitutions");
|
||||||
|
|
||||||
|
return {
|
||||||
|
races: fetch_races(fetch),
|
||||||
|
drivers: fetch_drivers(fetch),
|
||||||
|
substitutions: fetch_substitutions(fetch),
|
||||||
|
};
|
||||||
|
};
|
||||||
10
src/routes/data/season/teams/+page.ts
Normal file
10
src/routes/data/season/teams/+page.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { fetch_teams } from "$lib/fetch";
|
||||||
|
import type { PageLoad } from "../../../$types";
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
|
depends("data:teams");
|
||||||
|
|
||||||
|
return {
|
||||||
|
teams: fetch_teams(fetch),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,21 +1,10 @@
|
|||||||
import { pb } from "$lib/pocketbase";
|
import { fetch_users } from "$lib/fetch";
|
||||||
import type { User } from "$lib/schema";
|
|
||||||
import type { PageLoad } from "../../$types";
|
import type { PageLoad } from "../../$types";
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch }) => {
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
const fetch_users = async (): Promise<User[]> => {
|
depends("data:users");
|
||||||
const users: User[] = await pb
|
|
||||||
.collection("users")
|
|
||||||
.getFullList({ fetch: fetch, sort: "+username" });
|
|
||||||
|
|
||||||
users.map((user: User) => {
|
|
||||||
user.avatar_url = pb.files.getURL(user, user.avatar);
|
|
||||||
});
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users: await fetch_users(),
|
users: await fetch_users(fetch),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -170,7 +170,7 @@
|
|||||||
<h1 class="text-nowrap font-bold">
|
<h1 class="text-nowrap font-bold">
|
||||||
Picked ({picked.length}/{currentpicked.length}):
|
Picked ({picked.length}/{currentpicked.length}):
|
||||||
</h1>
|
</h1>
|
||||||
<div class="mt-1 grid grid-cols-4 gap-x-2 gap-y-0.5">
|
<div class="mt-1 grid grid-cols-4 gap-x-0 gap-y-0.5">
|
||||||
{#each picked.slice(0, 16) as user}
|
{#each picked.slice(0, 16) as user}
|
||||||
<LazyImage
|
<LazyImage
|
||||||
src={user.avatar_url ?? get_driver_headshot_template(graphics)}
|
src={user.avatar_url ?? get_driver_headshot_template(graphics)}
|
||||||
@ -303,14 +303,15 @@
|
|||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hide-scrollbar flex w-full overflow-x-scroll pb-2">
|
<!-- TODO: Horizontal scrollbar missing in desktop chrome (fuck chrome)??? -->
|
||||||
|
<div class="flex w-full overflow-x-scroll pb-2">
|
||||||
<!-- Not ideal but currentpickedusers contains all users, so we do not need to fetch the users separately -->
|
<!-- Not ideal but currentpickedusers contains all users, so we do not need to fetch the users separately -->
|
||||||
{#await Promise.all( [data.currentpickedusers, data.racepicks, data.races, data.drivers, data.raceresults], ) then [currentpicked, racepicks, races, drivers, raceresults]}
|
{#await Promise.all( [data.currentpickedusers, data.racepicks, data.races, data.drivers, data.raceresults], ) then [currentpicked, racepicks, races, drivers, raceresults]}
|
||||||
{#each currentpicked as user}
|
{#each currentpicked as user}
|
||||||
{@const picks = racepicks.filter((pick: RacePick) => pick.user === user.id)}
|
{@const picks = racepicks.filter((pick: RacePick) => pick.user === user.id)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="card ml-1 mt-2 w-full min-w-12 overflow-hidden py-2 shadow lg:ml-2 {data.user &&
|
class="card ml-1 mt-2 w-full min-w-12 overflow-hidden py-2 shadow lg:ml-2 lg:min-w-40 {data.user &&
|
||||||
data.user.username === user.username
|
data.user.username === user.username
|
||||||
? 'bg-primary-300'
|
? 'bg-primary-300'
|
||||||
: ''}"
|
: ''}"
|
||||||
|
|||||||
@ -1,57 +1,32 @@
|
|||||||
import { pb } from "$lib/pocketbase";
|
import {
|
||||||
import type { CurrentPickedUser, Race, RacePick, RaceResult } from "$lib/schema";
|
fetch_currentpickedusers,
|
||||||
|
fetch_currentrace,
|
||||||
|
fetch_drivers,
|
||||||
|
fetch_racepicks,
|
||||||
|
fetch_raceresults,
|
||||||
|
fetch_races,
|
||||||
|
fetch_substitutions,
|
||||||
|
} from "$lib/fetch";
|
||||||
import type { PageLoad } from "../$types";
|
import type { PageLoad } from "../$types";
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch }) => {
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
const fetch_currentrace = async (): Promise<Race | null> => {
|
depends(
|
||||||
const currentrace: Race[] = await pb.collection("currentrace").getFullList({ fetch: fetch });
|
"data:racepicks",
|
||||||
|
"data:currentpickedusers",
|
||||||
// The currentrace collection either has a single or no entries
|
"data:raceresults",
|
||||||
if (currentrace.length == 0) return null;
|
"data:drivers",
|
||||||
|
"data:races",
|
||||||
currentrace[0].pictogram_url = pb.files.getURL(currentrace[0], currentrace[0].pictogram);
|
"data:currentrace",
|
||||||
|
);
|
||||||
return currentrace[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_racepicks = async (): Promise<RacePick[]> => {
|
|
||||||
// Don't expand race/pxx/dnf since we already fetched those
|
|
||||||
const racepicks: RacePick[] = await pb
|
|
||||||
.collection("racepicks")
|
|
||||||
.getFullList({ fetch: fetch, expand: "user" });
|
|
||||||
|
|
||||||
return racepicks;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_currentpickedusers = async (): Promise<CurrentPickedUser[]> => {
|
|
||||||
const currentpickedusers: CurrentPickedUser[] = await pb
|
|
||||||
.collection("currentpickedusers")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
currentpickedusers.map((currentpickeduser: CurrentPickedUser) => {
|
|
||||||
if (currentpickeduser.avatar) {
|
|
||||||
currentpickeduser.avatar_url = pb.files.getURL(currentpickeduser, currentpickeduser.avatar);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return currentpickedusers;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from data/raceresults/+page.server.ts
|
|
||||||
const fetch_raceresults = async (): Promise<RaceResult[]> => {
|
|
||||||
// Don't expand races/pxxs/dnfs since we already fetched those
|
|
||||||
const raceresults: RaceResult[] = await pb
|
|
||||||
.collection("raceresultsdesc")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
return raceresults;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
racepicks: fetch_racepicks(),
|
racepicks: fetch_racepicks(fetch),
|
||||||
currentpickedusers: fetch_currentpickedusers(),
|
currentpickedusers: fetch_currentpickedusers(fetch),
|
||||||
raceresults: fetch_raceresults(),
|
raceresults: fetch_raceresults(fetch),
|
||||||
|
drivers: fetch_drivers(fetch),
|
||||||
|
races: fetch_races(fetch),
|
||||||
|
substitutions: fetch_substitutions(fetch),
|
||||||
|
|
||||||
currentrace: await fetch_currentrace(),
|
currentrace: await fetch_currentrace(fetch),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user