Initial commit
This commit is contained in:
+34
@@ -0,0 +1,34 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# kickern.app
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.3.11. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||||
Submodule
+1
Submodule apps/backend added at 3dd31e693b
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install # or pnpm install or yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
|
||||||
|
|
||||||
|
## Available Scripts
|
||||||
|
|
||||||
|
In the project directory, you can run:
|
||||||
|
|
||||||
|
### `npm run dev`
|
||||||
|
|
||||||
|
Runs the app in the development mode.<br>
|
||||||
|
Open [http://localhost:5173](http://localhost:5173) to view it in the browser.
|
||||||
|
|
||||||
|
### `npm run build`
|
||||||
|
|
||||||
|
Builds the app for production to the `dist` folder.<br>
|
||||||
|
It correctly bundles Solid in production mode and optimizes the build for the best performance.
|
||||||
|
|
||||||
|
The build is minified and the filenames include the hashes.<br>
|
||||||
|
Your app is ready to be deployed!
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
Learn more about deploying your application with the [documentations](https://vite.dev/guide/static-deploy.html)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="bg-gray-900">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="theme-color" content="#00ff00" />
|
||||||
|
<title>fontend</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
"build": "tsc -b && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@serwist/vite": "^9.5.11",
|
||||||
|
"@serwist/window": "^9.5.11",
|
||||||
|
"@solidjs/router": "^0.16.1",
|
||||||
|
"@tailwindcss/vite": "^4.3.1",
|
||||||
|
"solid-js": "^1.9.12",
|
||||||
|
"tailwindcss": "^4.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.12.3",
|
||||||
|
"typescript": "~6.0.2",
|
||||||
|
"vite": "^8.0.12",
|
||||||
|
"vite-plugin-solid": "^2.11.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
||||||
|
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
||||||
|
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="discord-icon" viewBox="0 0 20 19">
|
||||||
|
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="github-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="social-icon" viewBox="0 0 20 20">
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
||||||
|
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="x-icon" viewBox="0 0 19 19">
|
||||||
|
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,81 @@
|
|||||||
|
import { Router, Route, useNavigate, useBeforeLeave } from "@solidjs/router";
|
||||||
|
import { OverviewPage } from "./pages/Overview";
|
||||||
|
import { MatchPage } from "./pages/MatchDetails";
|
||||||
|
import { type ParentProps, onMount, onCleanup, createSignal } from "solid-js";
|
||||||
|
|
||||||
|
function Layout(props: ParentProps) {
|
||||||
|
return (
|
||||||
|
<div class="bg-gray-900 text-white h-dvh flex flex-col font-sans overflow-hidden select-none">
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [path, setPath] = createSignal(window.location.pathname);
|
||||||
|
|
||||||
|
// Die zentrale Navigations-Funktion
|
||||||
|
const navigate = (to) => {
|
||||||
|
if (window.location.pathname === to) return;
|
||||||
|
|
||||||
|
// Hier steuerst du die Transition BEVOR die URL oder das Signal angefasst wird
|
||||||
|
if (document.startViewTransition) {
|
||||||
|
document.startViewTransition(() => {
|
||||||
|
window.history.pushState({}, "", to);
|
||||||
|
setPath(to);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.history.pushState({}, "", to);
|
||||||
|
setPath(to);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePopstate = () => {
|
||||||
|
if (document.startViewTransition) {
|
||||||
|
document.documentElement.classList.add("back-navigation");
|
||||||
|
// Der Browser hat die URL bei BACK schon geändert,
|
||||||
|
// wir triggern die Transition und updaten das Signal synchron
|
||||||
|
const transition = document.startViewTransition(() => {
|
||||||
|
setPath(window.location.pathname);
|
||||||
|
});
|
||||||
|
transition.finished.then(() => {
|
||||||
|
document.documentElement.classList.remove("back-navigation");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setPath(window.location.pathname);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLinks = (e) => {
|
||||||
|
const a = e.target.closest("a");
|
||||||
|
if (a) {
|
||||||
|
const href = a.getAttribute("href");
|
||||||
|
if (href.startsWith("/")) {
|
||||||
|
e.preventDefault();
|
||||||
|
navigate(href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Hier fixen wir das Back-Button-Problem ein für alle Mal sauber!
|
||||||
|
onMount(() => {
|
||||||
|
window.addEventListener("click", handleLinks);
|
||||||
|
window.addEventListener("popstate", handlePopstate);
|
||||||
|
});
|
||||||
|
onCleanup(() => {
|
||||||
|
window.removeEventListener("click", handleLinks);
|
||||||
|
window.removeEventListener("popstate", handlePopstate);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="bg-gray-900 text-white h-dvh flex flex-col font-sans overflow-hidden select-none">
|
||||||
|
<Show when={path() === "/"}>
|
||||||
|
<OverviewPage />
|
||||||
|
</Show>
|
||||||
|
<Show when={path().startsWith("/match/")}>
|
||||||
|
<MatchPage />
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,35 @@
|
|||||||
|
import { splitProps } from "solid-js";
|
||||||
|
|
||||||
|
export const DayTab = (props: {
|
||||||
|
day: {
|
||||||
|
dateString: string;
|
||||||
|
weekday: string;
|
||||||
|
dayNum: number;
|
||||||
|
isToday: boolean;
|
||||||
|
};
|
||||||
|
isActive: boolean;
|
||||||
|
onClick: () => void;
|
||||||
|
[key: string]: any;
|
||||||
|
}) => {
|
||||||
|
const [local, restHtmlProps] = splitProps(props, [
|
||||||
|
"day",
|
||||||
|
"isActive",
|
||||||
|
"onClick",
|
||||||
|
]);
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
{...restHtmlProps}
|
||||||
|
onClick={local.onClick}
|
||||||
|
class={`flex flex-col items-center justify-center min-w-13.75 p-2 rounded-xl transition-all duration-200 ${
|
||||||
|
local.isActive
|
||||||
|
? "bg-emerald-500 text-gray-900 font-bold scale-105 shadow-lg shadow-emerald-500/20"
|
||||||
|
: local.day.isToday
|
||||||
|
? "bg-gray-700 text-emerald-400 border border-emerald-500/30"
|
||||||
|
: "bg-gray-800 text-gray-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span class="text-xs uppercase tracking-wider">{local.day.weekday}</span>
|
||||||
|
<span class="text-lg mt-0.5">{local.day.dayNum}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export const EmptyDay = (props: {
|
||||||
|
day: { dayNum: number; weekday: string };
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div class="text-center py-12 text-gray-500 bg-gray-800/30 rounded-2xl border border-dashed border-gray-700">
|
||||||
|
<p class="text-lg font-medium">Spielfrei!</p>
|
||||||
|
<p class="text-sm mt-1">
|
||||||
|
Keine Matches am {props.day.dayNum}. {props.day.weekday}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { Show, type ParentProps } from "solid-js";
|
||||||
|
|
||||||
|
type HeaderProps = ParentProps<{
|
||||||
|
title: string;
|
||||||
|
onClickTitle?: () => void;
|
||||||
|
showBackButton?: boolean;
|
||||||
|
}>;
|
||||||
|
export const Header = (props: HeaderProps) => (
|
||||||
|
<header
|
||||||
|
class={`p-4 bg-gray-800 border-b border-gray-700 items-center sticky top-0 z-20 flex`}
|
||||||
|
>
|
||||||
|
<div class="flex items-center w-8 h-5">
|
||||||
|
<Show when={props.showBackButton}>
|
||||||
|
<button
|
||||||
|
onClick={() => window.history.back()}
|
||||||
|
class="flex items-center gap-1 text-sm text-emerald-400 hover:text-emerald-300 py-1 pr-3 z-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-5 w-5"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15 19l-7-7 7-7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Zurück</span>
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1
|
||||||
|
class="absolute inset-x-0 text-base font-boldtracking-wide text-center text-emerald-400 truncate"
|
||||||
|
onClick={props.onClickTitle}
|
||||||
|
>
|
||||||
|
{props.title}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="text-right flex justify-end">{props.children}</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { For } from "solid-js";
|
||||||
|
|
||||||
|
export function ListSkeleton() {
|
||||||
|
return (
|
||||||
|
// Ein Wrapper, der genau wie dein echter Spiele-Container formatiert ist
|
||||||
|
<div class=" space-y-3 animate-pulse">
|
||||||
|
<div
|
||||||
|
style={{ "--delay": "0ms" }}
|
||||||
|
class="h-3 bg-gray-800 rounded w-1/3 mb-4 animate-skeleton-loop"
|
||||||
|
></div>
|
||||||
|
{/* Wir rendern 4 gefälschte Spiele-Karten */}
|
||||||
|
<For each={[1, 2, 3, 4]}>
|
||||||
|
{(_, i) => (
|
||||||
|
<div
|
||||||
|
class="bg-gray-800/60 p-4 rounded-xl border border-gray-700/40 shadow-md flex items-center justify-between h-[58px] animate-skeleton-loop"
|
||||||
|
style={{ "--delay": `${i() * 150}ms` }}
|
||||||
|
>
|
||||||
|
{/* Team A (Rechtsbündig simuliert) */}
|
||||||
|
<div class="w-full flex justify-end pr-2 items-center gap-2">
|
||||||
|
<div class="h-4 bg-gray-700 rounded w-20"></div>
|
||||||
|
<div class="size-8 bg-gray-700 rounded-full" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mittlerer Zeit-/Ergebnisblock */}
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div class="w-16 h-7 bg-gray-950/60 rounded-lg border border-gray-700/50"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Team B (Linksbündig simuliert) */}
|
||||||
|
<div class="w-full flex justify-start pl-2 gap-2 items-center">
|
||||||
|
<div class="size-8 bg-gray-700 rounded-full" />
|
||||||
|
<div class="h-4 bg-gray-700 rounded w-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export const LogoFallback = () => (
|
||||||
|
<div
|
||||||
|
class={`size-8 flex-shrink-0 rounded-full flex items-center justify-center border transition-colors duration-200 ${"bg-gray-800 border-gray-700 text-gray-400"}`}
|
||||||
|
>
|
||||||
|
{/* Ein sauberes, sportliches Trikot-SVG */}
|
||||||
|
<svg
|
||||||
|
class="size-5"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
{/* Trikot-Körper */}
|
||||||
|
<path d="M20.38 6.54L16 4.5a2 2 0 0 0-1.6.1L12 6l-2.4-1.4a2 2 0 0 0-1.6-.1L3.62 6.54a1 1 0 0 0-.62.92v4a2 2 0 0 0 1.25 1.85l3.25 1.3V20a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-5.4l3.25-1.3A2 2 0 0 0 21 11.46v-4a1 1 0 0 0-.62-.92z" />
|
||||||
|
{/* V-Ausschnitt für den sportlichen Look */}
|
||||||
|
<path d="M10 4.7a2 2 0 0 0 4 0" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Show } from "solid-js";
|
||||||
|
import { MatchItem } from "./MatchItem";
|
||||||
|
interface FirstLeg {
|
||||||
|
homeScore: number;
|
||||||
|
awayScore: number;
|
||||||
|
date: string;
|
||||||
|
wasHome?: boolean; // Hilft zu wissen, wer damals Heimrecht hatte
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MatchInsights(props: {
|
||||||
|
homeTeamName: string;
|
||||||
|
awayTeamName: string;
|
||||||
|
firstLeg: FirstLeg | null | undefined;
|
||||||
|
homeAvgGoals?: number; // z.B. 6.2
|
||||||
|
awayAvgGoals?: number; // z.B. 4.8
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div class="bg-gray-800/50 rounded-2xl p-4 border border-gray-800 space-y-4">
|
||||||
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-400 text-center">
|
||||||
|
Hinspiel
|
||||||
|
</h3>
|
||||||
|
<Show when={props.firstLeg}>
|
||||||
|
<MatchItem game={props.firstLeg} />
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Show } from "solid-js";
|
||||||
|
import { LogoFallback } from "./LogoFallback";
|
||||||
|
import { ResultTile } from "./ResultTile";
|
||||||
|
|
||||||
|
export const MatchItem = (props: { game: any }) => {
|
||||||
|
return (
|
||||||
|
<div class="flex items-center justify-between gap-2 flex-1">
|
||||||
|
<div class="flex-1 flex flex-row items-center gap-2 justify-end min-w-0">
|
||||||
|
<div class="text-right pr-2 line-clamp-2 font-light text-xs">
|
||||||
|
{props.game.homeTeam.name}
|
||||||
|
</div>
|
||||||
|
<div class="min-w-8">
|
||||||
|
<Show when={props.game.homeTeam.logoUrl} fallback={<LogoFallback />}>
|
||||||
|
<img
|
||||||
|
src={props.game.homeTeam.logoUrl}
|
||||||
|
class="size-8 object-contain"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-16 min-w-16 flex flex-col items-center">
|
||||||
|
<Show
|
||||||
|
when={props.game.status !== "SCHEDULED"}
|
||||||
|
fallback={
|
||||||
|
<span class="text-xs font-bold text-center">
|
||||||
|
{new Date(props.game.scheduledAt).toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ResultTile
|
||||||
|
home={props.game.homeTeam.points}
|
||||||
|
away={props.game.awayTeam.points}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-row gap-2 items-center justify-start min-w-0">
|
||||||
|
<div class="min-w-8">
|
||||||
|
<Show when={props.game.awayTeam.logoUrl} fallback={<LogoFallback />}>
|
||||||
|
<img
|
||||||
|
src={props.game.awayTeam.logoUrl}
|
||||||
|
class="size-8 object-contain"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<div class="text-left pl-2 line-clamp-2 font-light text-xs">
|
||||||
|
{props.game.awayTeam.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const ResultTile = (props: { home?: number; away?: number }) => {
|
||||||
|
return (
|
||||||
|
<div class="flex flex-col items-center justify-center bg-gray-900/60 p-2 rounded-lg border border-gray-700">
|
||||||
|
<div class="flex items-center gap-1 font-mono text-xs font-bold">
|
||||||
|
<span
|
||||||
|
class={props.home > props.away ? "text-emerald-400" : "text-gray-300"}
|
||||||
|
>
|
||||||
|
{props.home ?? "-"}
|
||||||
|
</span>
|
||||||
|
<span class="text-gray-600">:</span>
|
||||||
|
<span
|
||||||
|
class={props.away > props.home ? "text-emerald-400" : "text-gray-300"}
|
||||||
|
>
|
||||||
|
{props.away ?? "-"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
export function SquadComparison(props: { homeTeam: any; awayTeam: any }) {
|
||||||
|
const homeMembers = () => props.homeRosters || [];
|
||||||
|
const awayMembers = () => props.awayRosters || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="bg-gray-800/50 rounded-2xl p-4 border border-gray-800 space-y-4 overflow-hidden">
|
||||||
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-400 text-center">
|
||||||
|
Kaderübersicht
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
{/* HEIM TEAM ROW */}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="text-[10px] uppercase font-bold text-emerald-400 px-1">
|
||||||
|
{props.homeTeam.name}
|
||||||
|
</div>
|
||||||
|
{/* Horizontale Scrollbar */}
|
||||||
|
<div class="flex gap-3 overflow-x-auto pb-2 scrollbar-none snap-x">
|
||||||
|
<For each={homeMembers()}>
|
||||||
|
{(player) => (
|
||||||
|
<div class="flex flex-col items-center justify-center text-center w-14 flex-shrink-0 snap-start">
|
||||||
|
<div class="size-10 rounded-full border border-emerald-500/20 p-0.5 bg-gray-900 mb-1">
|
||||||
|
<img
|
||||||
|
src={player.imageUrl || "/fallback-avatar.svg"}
|
||||||
|
class="size-full rounded-full object-cover"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="text-[10px] text-gray-300 font-medium truncate w-full">
|
||||||
|
{player.name}
|
||||||
|
{/* Nur Nachname spart Platz */}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* AUSWÄRTS TEAM ROW */}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="text-[10px] uppercase font-bold text-gray-400 px-1">
|
||||||
|
{props.awayTeam.name}
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 overflow-x-auto pb-2 scrollbar-none snap-x">
|
||||||
|
<For each={awayMembers()}>
|
||||||
|
{(player) => (
|
||||||
|
<div class="flex flex-col items-center justify-center text-center w-14 flex-shrink-0 snap-start">
|
||||||
|
<div class="size-10 rounded-full border border-gray-700 p-0.5 bg-gray-900 mb-1">
|
||||||
|
<img
|
||||||
|
src={player.imageUrl || "/fallback-avatar.svg"}
|
||||||
|
class="size-full rounded-full object-cover"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="text-[10px] text-gray-300 font-medium truncate w-full">
|
||||||
|
{player.name.split(" ")[1] || player.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
export function TableComparison(props: { homeTeam: any; awayTeam: any }) {
|
||||||
|
// Beispielhafte Mock-Daten – hier kommen später die echten Tabellenplatz-Daten rein
|
||||||
|
const homeStats = props.homeTeam;
|
||||||
|
|
||||||
|
// name: props.homeTeam.name,
|
||||||
|
// logo: props.homeTeam.logoUrl,
|
||||||
|
// games: 12,
|
||||||
|
// diff: "+14",
|
||||||
|
// points: 25,
|
||||||
|
// };
|
||||||
|
const awayStats = props.awayTeam;
|
||||||
|
// {
|
||||||
|
// pos: 8,
|
||||||
|
// name: props.awayTeam.name,
|
||||||
|
// logo: props.awayTeam.logoUrl,
|
||||||
|
// games: 12,
|
||||||
|
// diff: "-2",
|
||||||
|
// points: 17,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// Sortieren, damit das Team weiter oben auch in der UI oben steht
|
||||||
|
const sortedTeams = () =>
|
||||||
|
[homeStats, awayStats].sort((a, b) => a.pos - b.pos);
|
||||||
|
const diffInPlaces = () => Math.abs(homeStats.pos - awayStats.pos) - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="bg-gray-800/50 rounded-2xl p-4 border border-gray-800 space-y-3">
|
||||||
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-400 text-center">
|
||||||
|
Tabellen-Ausschnitt
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="w-full space-y-1">
|
||||||
|
{/* Header-Zeile */}
|
||||||
|
<div class="flex text-[10px] uppercase font-bold text-gray-500 px-2 pb-1 border-b border-gray-800">
|
||||||
|
<span class="w-8">Pl.</span>
|
||||||
|
<span class="flex-1">Verein</span>
|
||||||
|
<span class="w-8 text-center">Sp.</span>
|
||||||
|
<span class="w-10 text-center">Diff.</span>
|
||||||
|
<span class="w-10 text-right">Pkt.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Team 1 (Das Höherplatzierte) */}
|
||||||
|
<div
|
||||||
|
class={`flex items-center text-xs p-2 rounded-xl border ${
|
||||||
|
sortedTeams()[0].name === props.homeTeam.name
|
||||||
|
? "bg-emerald-950/20 border-emerald-500/20"
|
||||||
|
: "bg-gray-900/40 border-transparent"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span class="w-8 font-mono font-bold text-gray-400">
|
||||||
|
#{sortedTeams()[0].pos}
|
||||||
|
</span>
|
||||||
|
<span class="flex-1 font-medium truncate flex items-center gap-2">
|
||||||
|
<img
|
||||||
|
src={sortedTeams()[0].logo}
|
||||||
|
class="size-4 object-contain"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{sortedTeams()[0].name}
|
||||||
|
</span>
|
||||||
|
<span class="w-8 text-center text-gray-400 font-mono">
|
||||||
|
{sortedTeams()[0].games}
|
||||||
|
</span>
|
||||||
|
<span class="w-10 text-center text-gray-400 font-mono">
|
||||||
|
{sortedTeams()[0].diff}
|
||||||
|
</span>
|
||||||
|
<span class="w-10 text-right font-bold text-emerald-400 font-mono">
|
||||||
|
{sortedTeams()[0].points}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Platzhalter-Trenner, wenn Teams weiter auseinanderliegen */}
|
||||||
|
<Show when={diffInPlaces() > 0}>
|
||||||
|
<div class="flex items-center px-4 py-1 text-[10px] text-gray-600 font-medium">
|
||||||
|
<div class="w-1 h-3 border-l border-dashed border-gray-700 mr-3"></div>
|
||||||
|
<span>
|
||||||
|
... {diffInPlaces()} {diffInPlaces() === 1 ? "Platz" : "Plätze"}{" "}
|
||||||
|
dazwischen ...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
{/* Team 2 (Das Tieferplatzierte) */}
|
||||||
|
<div
|
||||||
|
class={`flex items-center text-xs p-2 rounded-xl border ${
|
||||||
|
sortedTeams()[1].name === props.homeTeam.name
|
||||||
|
? "bg-emerald-950/20 border-emerald-500/20"
|
||||||
|
: "bg-gray-900/40 border-transparent"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span class="w-8 font-mono font-bold text-gray-400">
|
||||||
|
#{sortedTeams()[1].pos}
|
||||||
|
</span>
|
||||||
|
<span class="flex-1 font-medium truncate flex items-center gap-2">
|
||||||
|
<img
|
||||||
|
src={sortedTeams()[1].logo}
|
||||||
|
class="size-4 object-contain"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{sortedTeams()[1].name}
|
||||||
|
</span>
|
||||||
|
<span class="w-8 text-center text-gray-400 font-mono">
|
||||||
|
{sortedTeams()[1].games}
|
||||||
|
</span>
|
||||||
|
<span class="w-10 text-center text-gray-400 font-mono">
|
||||||
|
{sortedTeams()[1].diff}
|
||||||
|
</span>
|
||||||
|
<span class="w-10 text-right font-bold text-emerald-400 font-mono">
|
||||||
|
{sortedTeams()[1].points}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
|
||||||
|
@keyframes move-stripes {
|
||||||
|
0% { background-position: 0 0; }
|
||||||
|
100% { background-position: 40px 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-striped-loading-dark {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
rgba(0, 0, 0, 0.08) 25%,
|
||||||
|
transparent 25%,
|
||||||
|
transparent 50%,
|
||||||
|
rgba(0, 0, 0, 0.08) 50%,
|
||||||
|
rgba(0, 0, 0, 0.08) 75%,
|
||||||
|
transparent 75%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
animation: move-stripes 1.2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes waterfall {
|
||||||
|
0% {
|
||||||
|
opacity: 0.3;
|
||||||
|
/* transform: translateY(12px); */
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
/* transform: translateY(0); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-waterfall {
|
||||||
|
opacity: 0; /* Startet unsichtbar, bis die Animation greift */
|
||||||
|
animation: waterfall 0.25s cubic-bezier(0.21, 1.02, 0.43, 1.01) forwards;
|
||||||
|
/* Nutzen die Inline-Variable, die wir in SolidJS setzen */
|
||||||
|
animation-delay: var(--delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton-wave {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 0.3;
|
||||||
|
transform: scale(0.99);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-skeleton-loop {
|
||||||
|
opacity: 0.3;
|
||||||
|
/* 1.6s für einen kompletten Wellendurchlauf */
|
||||||
|
animation: skeleton-wave 1.6s ease-in-out infinite;
|
||||||
|
animation-delay: var(--delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(root),
|
||||||
|
::view-transition-new(root) {
|
||||||
|
animation-duration: 400ms;
|
||||||
|
animation-timing-function: cubic-bezier(0.32, 0.94, 0.6, 1);
|
||||||
|
animation-fill-mode: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
1. FORWARD / PUSH ANIMATION (Standard)
|
||||||
|
========================================== */
|
||||||
|
|
||||||
|
/* Die alte Seite schiebt sich leicht nach links (-20%) und wird blasser */
|
||||||
|
@keyframes ios-exit-forward {
|
||||||
|
from { transform: translateX(0); opacity: 1; }
|
||||||
|
to { transform: translateX(-20%); opacity: 0.9; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die neue Seite kommt von ganz rechts (100%) mit leichtem Schatten */
|
||||||
|
@keyframes ios-enter-forward {
|
||||||
|
from {
|
||||||
|
transform: translateX(100%);
|
||||||
|
box-shadow: -10px 0 30px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
box-shadow: -10px 0 30px rgba(0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(root) {
|
||||||
|
animation-name: ios-exit-forward;
|
||||||
|
}
|
||||||
|
::view-transition-new(root) {
|
||||||
|
animation-name: ios-enter-forward;
|
||||||
|
z-index: 2; /* Wichtig: Neue Seite liegt OBEN */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
2. BACKWARD / POP ANIMATION (.back-navigation)
|
||||||
|
========================================== */
|
||||||
|
|
||||||
|
/* Die alte Seite (die jetzt schließt) schiebt sich nach rechts weg */
|
||||||
|
@keyframes ios-exit-backward {
|
||||||
|
from {
|
||||||
|
transform: translateX(0);
|
||||||
|
box-shadow: -10px 0 30px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(100%);
|
||||||
|
box-shadow: -10px 0 30px rgba(0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die neue Seite (die von links wiederkommt) startet bei -20% und kommt vor */
|
||||||
|
@keyframes ios-enter-backward {
|
||||||
|
from { transform: translateX(-20%); opacity: 0.9; }
|
||||||
|
to { transform: translateX(0); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-navigation::view-transition-old(root) {
|
||||||
|
animation-name: ios-exit-backward;
|
||||||
|
z-index: 2; /* Wichtig: Die schließende Seite liegt OBEN */
|
||||||
|
}
|
||||||
|
.back-navigation::view-transition-new(root) {
|
||||||
|
animation-name: ios-enter-backward;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* @refresh reload */
|
||||||
|
import { render } from 'solid-js/web'
|
||||||
|
import './index.css'
|
||||||
|
import App from './App.tsx'
|
||||||
|
|
||||||
|
const root = document.getElementById('root')
|
||||||
|
|
||||||
|
render(() => <App />, root!)
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
import { onMount } from "solid-js";
|
||||||
|
import { Header } from "../components/Header";
|
||||||
|
import { useParams } from "@solidjs/router";
|
||||||
|
import { matchStore, loadMatch } from "../stores/matchStore";
|
||||||
|
import { MatchItem } from "../components/MatchItem";
|
||||||
|
import { MatchInsights } from "../components/MatchInsights";
|
||||||
|
import { ResultTile } from "../components/ResultTile";
|
||||||
|
export function MatchPage() {
|
||||||
|
// const { id } = useParams();
|
||||||
|
const id = window.location.pathname.split("/").pop();
|
||||||
|
const match = () => matchStore.matches.find((m) => m.id === id);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
loadMatch(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="w-full h-full overflow-y-auto bg-gray-800">
|
||||||
|
<button
|
||||||
|
class="sticky top-5 left-2 z-22 p-2 cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
window.history.back();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-5 w-5"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15 19l-7-7 7-7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Back</span>
|
||||||
|
</button>
|
||||||
|
<div class="bg-gray-900">
|
||||||
|
{/* <Header title={""} showBackButton /> */}
|
||||||
|
{match() && match().status !== "SCHEDULED" && (
|
||||||
|
<MatchDetails match={match()} />
|
||||||
|
)}
|
||||||
|
{match() && match().status === "SCHEDULED" && (
|
||||||
|
<MatchDetailsFuture match={match()} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MatchDetails(props: { match: any }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="bg-gradient-to-b from-gray-800 to-gray-850 w-full py-5.5 px-10 border-b border-gray-800 text-center sticky top-0 backdrop-blur-md z-21">
|
||||||
|
<MatchItem game={props.match} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{props.match.slots?.map((s) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{s.type}
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div class="flex-1">
|
||||||
|
{s.home.players.map((p) => (
|
||||||
|
<div>{p ? `${p.firstName} ${p.lastName}` : "-"}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{s.sets.map((s) => (
|
||||||
|
<ResultTile home={s?.homeGoals} away={s?.awayGoals} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
{s.away.players.map((p) => (
|
||||||
|
<div>{p ? `${p.firstName} ${p.lastName}` : "-"}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
import { For, Show } from "solid-js";
|
||||||
|
import { LogoFallback as JerseyFallback } from "../components/LogoFallback.tsx";
|
||||||
|
import { TableComparison } from "../components/TableComparison.tsx";
|
||||||
|
import { SquadComparison } from "../components/SquadComparison.tsx";
|
||||||
|
|
||||||
|
export default function MatchDetailsFuture(props: { match: any }) {
|
||||||
|
// Beispiel-Struktur für props.match:
|
||||||
|
// { homeTeam: { name: "...", logoUrl: "..." }, awayTeam: { ... }, scheduledAt: "...", tournament: "Bundesliga", venue: "Allianz Arena" }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* 1. DER SHOWDOWN HEADER */}
|
||||||
|
<div class="bg-gradient-to-b from-gray-800 to-gray-850 p-6 border-b border-gray-800 text-center relative sticky top-0 backdrop-blur-md z-21">
|
||||||
|
<span class="text-xs font-bold uppercase tracking-widest text-emerald-400 block mb-4">
|
||||||
|
{props.match.event.name}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between gap-4 my-2">
|
||||||
|
{/* Home Team */}
|
||||||
|
<div class="flex-1 flex flex-col items-center gap-2 min-w-0">
|
||||||
|
<Show
|
||||||
|
when={props.match.homeTeam.logoUrl}
|
||||||
|
fallback={<JerseyFallback type="home" />}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={props.match.homeTeam.logoUrl}
|
||||||
|
class="size-14 object-contain"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<span class="text-sm font-semibold text-gray-200 text-center line-clamp-2 leading-tight">
|
||||||
|
{props.match.homeTeam.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mittlerer Zeitblock */}
|
||||||
|
<div class="flex flex-col items-center justify-center px-4 py-2 bg-gray-950/50 rounded-2xl border border-gray-800 min-w-[100px]">
|
||||||
|
<span class="text-xs font-semibold text-emerald-400 tracking-wider">
|
||||||
|
{new Date(props.match.scheduledAt).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "short",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<span class="text-xl font-mono font-bold text-white mt-0.5">
|
||||||
|
{new Date(props.match.scheduledAt).toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<span class="text-[10px] text-gray-500 uppercase tracking-widest font-bold mt-1">
|
||||||
|
VS
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Away Team */}
|
||||||
|
<div class="flex-1 flex flex-col items-center gap-2 min-w-0">
|
||||||
|
<Show
|
||||||
|
when={props.match.awayTeam.logoUrl}
|
||||||
|
fallback={<JerseyFallback type="away" />}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={props.match.awayTeam.logoUrl}
|
||||||
|
class="size-14 object-contain"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<span class="text-sm font-semibold text-gray-200 text-center line-clamp-2 leading-tight">
|
||||||
|
{props.match.awayTeam.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Location Info */}
|
||||||
|
<p class="text-xs text-gray-500 mt-4 flex items-center justify-center gap-1">
|
||||||
|
<svg
|
||||||
|
class="size-3.5"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{props.match.venue?.name || "Unbekannter Spielort"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* INHALT / ANALYSE SEKTIONEN */}
|
||||||
|
<div class="p-4 space-y-6">
|
||||||
|
{/* 2. PROGNOSE / VOTING BAR */}
|
||||||
|
<div class="bg-gray-800/50 rounded-2xl p-4 border border-gray-800">
|
||||||
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-400 mb-3 text-center">
|
||||||
|
Wer gewinnt das Match?
|
||||||
|
</h3>
|
||||||
|
{/* Der 3-geteilte Balken */}
|
||||||
|
<div class="h-3.5 w-full rounded-full overflow-hidden flex bg-gray-900 border border-gray-750">
|
||||||
|
<div
|
||||||
|
class="bg-emerald-500 h-full transition-all duration-500"
|
||||||
|
style={{
|
||||||
|
width: `${props.match.prediction?.homeWinChance ?? 0}%`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="bg-gray-700 h-full transition-all duration-500"
|
||||||
|
style={{ width: `${props.match.prediction?.drawChance ?? 0}%` }}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="bg-blue-500 h-full transition-all duration-500"
|
||||||
|
style={{
|
||||||
|
width: `${props.match.prediction?.awayWinChance ?? 0}%`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
{/* Legende / Prozentzahlen */}
|
||||||
|
<div class="flex justify-between items-center mt-2.5 text-xs font-semibold px-0.5">
|
||||||
|
<span class="text-emerald-400">
|
||||||
|
Heim ({props.match.prediction?.homeWinChance}%)
|
||||||
|
</span>
|
||||||
|
<span class="text-gray-400">
|
||||||
|
Remis ({props.match.prediction?.drawChance}%)
|
||||||
|
</span>
|
||||||
|
<span class="text-blue-400">
|
||||||
|
Auswärts ({props.match.prediction?.awayWinChance}%)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{props.match.standing && (
|
||||||
|
<TableComparison
|
||||||
|
homeTeam={props.match.standing.home}
|
||||||
|
awayTeam={props.match.standing.away}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 3. FORMKURVE (LAST 5 MATCHES) */}
|
||||||
|
<div class="bg-gray-800/50 rounded-2xl p-4 border border-gray-800 space-y-4">
|
||||||
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-400 text-center">
|
||||||
|
Aktuelle Formkurve
|
||||||
|
</h3>
|
||||||
|
<div class="flex items-center justify-between gap-2 px-2">
|
||||||
|
{/* Form Team A */}
|
||||||
|
<div class="flex gap-1">
|
||||||
|
{props.match.form?.home.map((f) => (
|
||||||
|
<FormBadge
|
||||||
|
result={
|
||||||
|
{
|
||||||
|
WIN: "S",
|
||||||
|
DRAW: "U",
|
||||||
|
LOST: "N",
|
||||||
|
}[f]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] uppercase tracking-widest font-bold text-gray-600">
|
||||||
|
Form
|
||||||
|
</span>
|
||||||
|
{/* Form Team B */}
|
||||||
|
<div class="flex gap-1">
|
||||||
|
{props.match.form?.away.map((f) => (
|
||||||
|
<FormBadge
|
||||||
|
result={
|
||||||
|
{
|
||||||
|
WIN: "S",
|
||||||
|
DRAW: "U",
|
||||||
|
LOST: "N",
|
||||||
|
}[f]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SquadComparison
|
||||||
|
homeRosters={props.match.homeRosters}
|
||||||
|
awayRosters={props.match.awayRosters}
|
||||||
|
homeTeam={props.match.homeTeam}
|
||||||
|
awayTeam={props.match.awayTeam}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MatchInsights firstLeg={props.match.firstLeg} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FormBadge(props: { result: "S" | "U" | "N" }) {
|
||||||
|
const styles = () => {
|
||||||
|
switch (props.result) {
|
||||||
|
case "S": // Sieg
|
||||||
|
return "bg-emerald-500/20 text-emerald-400 border-emerald-500/30";
|
||||||
|
case "U": // Unentschieden
|
||||||
|
return "bg-gray-700/40 text-gray-400 border-gray-600/30";
|
||||||
|
case "N": // Niederlage
|
||||||
|
return "bg-rose-500/20 text-rose-400 border-rose-500/30";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
class={`size-6 rounded-full flex items-center justify-center text-[11px] font-bold border ${styles()}`}
|
||||||
|
>
|
||||||
|
{props.result}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
import {
|
||||||
|
createMemo,
|
||||||
|
For,
|
||||||
|
Show,
|
||||||
|
createEffect,
|
||||||
|
createSignal,
|
||||||
|
onMount,
|
||||||
|
onCleanup,
|
||||||
|
} from "solid-js";
|
||||||
|
// import { useSearchParams } from "@solidjs/router";
|
||||||
|
import { Header } from "../components/Header";
|
||||||
|
import { DayTab } from "../components/DayTab";
|
||||||
|
import { ListSkeleton } from "../components/ListSkeleton";
|
||||||
|
import { MatchItem } from "../components/MatchItem";
|
||||||
|
import { loadMatches, matchStore, type Match } from "../stores/matchStore";
|
||||||
|
import { EmptyDay } from "../components/EmptyDay";
|
||||||
|
|
||||||
|
type MatchesByDay = Record<string, Match[]>;
|
||||||
|
type EventGroup = {
|
||||||
|
eventName: string;
|
||||||
|
matches: Match[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSearchParams = () => {
|
||||||
|
const [params, setParams] = createSignal(
|
||||||
|
Object.fromEntries(new URLSearchParams(window.location.search).entries()),
|
||||||
|
);
|
||||||
|
return [
|
||||||
|
params,
|
||||||
|
(value) => {
|
||||||
|
const current = new URL(window.location.href);
|
||||||
|
|
||||||
|
current.search = `?${new URLSearchParams(value).toString()}`;
|
||||||
|
setParams(value);
|
||||||
|
window.history.replaceState({}, "", current.toString());
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const _scrollposition = new Map<string, number>();
|
||||||
|
export function OverviewPage() {
|
||||||
|
const [offset, setOffset] = createSignal(0);
|
||||||
|
const shouldAnimateOnEnter = matchStore.matches.length === 0;
|
||||||
|
|
||||||
|
const daysList = createMemo(() => {
|
||||||
|
const list = [];
|
||||||
|
for (let i = -7; i <= 7; i++) {
|
||||||
|
const d = new Date();
|
||||||
|
d.setDate(d.getDate() + i);
|
||||||
|
list.push({
|
||||||
|
dateString: d.toLocaleDateString("en-ca"),
|
||||||
|
weekday: d.toLocaleDateString("de-DE", { weekday: "short" }),
|
||||||
|
dayNum: d.getDate(),
|
||||||
|
isToday: i === 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
const matchesByDay = createMemo(() => {
|
||||||
|
const grouped: MatchesByDay = {};
|
||||||
|
|
||||||
|
for (const match of matchStore.matches) {
|
||||||
|
const dateKey = new Date(match.scheduledAt).toLocaleDateString("en-ca");
|
||||||
|
if (!grouped[dateKey]) grouped[dateKey] = [];
|
||||||
|
grouped[dateKey].push(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
return grouped;
|
||||||
|
});
|
||||||
|
|
||||||
|
let scrollContainerRef!: HTMLDivElement;
|
||||||
|
let navContainerRef!: HTMLDivElement;
|
||||||
|
let topContainerRef!: HTMLDivElement;
|
||||||
|
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams<{ date: string }>();
|
||||||
|
|
||||||
|
const activeDate = () =>
|
||||||
|
daysList().some((d) => d.dateString === searchParams().date)
|
||||||
|
? searchParams().date!
|
||||||
|
: new Date().toLocaleDateString("en-ca");
|
||||||
|
let isScrolling: boolean | undefined;
|
||||||
|
const scrollToDate = (dateString: string) => {
|
||||||
|
isScrolling = false;
|
||||||
|
setSearchParams({ date: dateString });
|
||||||
|
};
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const behavior = isScrolling === undefined ? "instant" : "smooth";
|
||||||
|
const activeTabBtn = navContainerRef.querySelector(
|
||||||
|
`[data-nav='${activeDate()}']`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (activeTabBtn) {
|
||||||
|
activeTabBtn.scrollIntoView({
|
||||||
|
behavior,
|
||||||
|
block: "nearest",
|
||||||
|
inline: "center",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isScrolling) {
|
||||||
|
const targetEl = scrollContainerRef.querySelector(
|
||||||
|
`[data-date='${activeDate()}']`,
|
||||||
|
) as HTMLElement | null;
|
||||||
|
if (targetEl) {
|
||||||
|
targetEl.scrollIntoView({
|
||||||
|
behavior,
|
||||||
|
block: "nearest",
|
||||||
|
inline: "start",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
loadMatches();
|
||||||
|
if (!shouldAnimateOnEnter) {
|
||||||
|
_scrollposition.forEach((top, selector) => {
|
||||||
|
document.querySelector(selector).scrollTop = top;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const datelists = document.querySelectorAll("[data-date]");
|
||||||
|
datelists.forEach((list) => {
|
||||||
|
list.addEventListener("scrollend", (e) => {
|
||||||
|
_scrollposition.set(
|
||||||
|
`[data-date="${e.target.dataset.date}"]`,
|
||||||
|
e.target.scrollTop,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
if (!isScrolling) return;
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const date = entry.target.getAttribute("data-date");
|
||||||
|
if (date) {
|
||||||
|
setSearchParams({ date: date }, { replace: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ root: scrollContainerRef, threshold: 0.55 },
|
||||||
|
);
|
||||||
|
|
||||||
|
setOffset(topContainerRef.offsetHeight);
|
||||||
|
scrollContainerRef
|
||||||
|
.querySelectorAll("[data-date]")
|
||||||
|
.forEach((el) => observer.observe(el));
|
||||||
|
|
||||||
|
const handleScrollEnd = () => {
|
||||||
|
isScrolling = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
scrollContainerRef.addEventListener("scrollend", handleScrollEnd);
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
observer.disconnect();
|
||||||
|
scrollContainerRef.removeEventListener("scrollend", handleScrollEnd);
|
||||||
|
});
|
||||||
|
isScrolling = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const gamesByLeagueForDay = (dateString: string) => {
|
||||||
|
const dayMatches = matchesByDay()[dateString] || [];
|
||||||
|
return Object.values(
|
||||||
|
dayMatches.reduce<Record<string, EventGroup>>((acc, match) => {
|
||||||
|
const key = `${match.event.id}${match.event.matchday}`;
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = {
|
||||||
|
eventName: `${match.event.name} - ${match.event.matchday}`,
|
||||||
|
matches: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
acc[key].matches.push(match);
|
||||||
|
return acc;
|
||||||
|
}, {}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
ref={topContainerRef}
|
||||||
|
class="fixed w-full top-0 backdrop-blur-md z-21 bg-gradient-to-b from-gray-800 to-gray-850"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={navContainerRef}
|
||||||
|
class="p-3 overflow-x-auto flex gap-2 scrollbar-none border-b border-gray-700/50 flex-none p-6 border-b border-gray-800 text-center"
|
||||||
|
>
|
||||||
|
<For each={daysList()}>
|
||||||
|
{(day) => (
|
||||||
|
<DayTab
|
||||||
|
isActive={activeDate() === day.dateString}
|
||||||
|
day={day}
|
||||||
|
data-nav={day.dateString}
|
||||||
|
onClick={() => scrollToDate(day.dateString)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={`px-4 py-2 bg-gray-800/40 border-b border-gray-800 flex justify-between items-center flex-none transition-colors duration-300 ${
|
||||||
|
matchStore.isLoading
|
||||||
|
? "bg-emerald-600/30 border-emerald-500/40 bg-striped-loading-dark"
|
||||||
|
: "bg-gray-800/40 border-gray-800"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span class="text-xs font-semibold uppercase text-gray-400">
|
||||||
|
{new Date(activeDate()).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "numeric",
|
||||||
|
month: "long",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ref={scrollContainerRef}
|
||||||
|
class="flex-1 flex overflow-x-auto snap-x snap-mandatory scrollbar-none scroll-smooth bg-gray-900"
|
||||||
|
>
|
||||||
|
<For each={daysList()}>
|
||||||
|
{(day) => {
|
||||||
|
const gamesForDay = () => gamesByLeagueForDay(day.dateString);
|
||||||
|
const itemIndex = { current: 0 };
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-date={day.dateString}
|
||||||
|
class="w-full h-full shrink-0 snap-start snap-always p-4 overflow-y-auto space-y-3"
|
||||||
|
style={`padding-top: calc(1rem + ${offset()}px)`}
|
||||||
|
>
|
||||||
|
<Show
|
||||||
|
when={gamesForDay().length > 0}
|
||||||
|
fallback={
|
||||||
|
<Show
|
||||||
|
when={!matchStore.isLoading}
|
||||||
|
fallback={<ListSkeleton />}
|
||||||
|
>
|
||||||
|
<EmptyDay day={day} />
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{((itemIndex.current = 0), null)}
|
||||||
|
<div class="space-y-6">
|
||||||
|
<For each={gamesForDay()}>
|
||||||
|
{(event) => (
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
"--delay": `${itemIndex.current++ * 25}ms`,
|
||||||
|
}}
|
||||||
|
class={`bg-gray-900 flex items-center justify-between border-b border-gray-800 pb-1.5 px-1 ${shouldAnimateOnEnter ? "animate-waterfall" : ""}`}
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
{/* sapce for event icon */}
|
||||||
|
<span class="text-xs font-bold uppercase tracking-wider text-emeral-400">
|
||||||
|
{event.eventName}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2.5">
|
||||||
|
<For each={event.matches}>
|
||||||
|
{(game) => (
|
||||||
|
<a
|
||||||
|
style={{
|
||||||
|
"--delay": `${itemIndex.current++ * 25}ms`,
|
||||||
|
}}
|
||||||
|
href={`/match/${game.id}`}
|
||||||
|
class={`bg-gray-800 p-4 rounded-xl border border-gray-700/60 shadow-md flex ${
|
||||||
|
shouldAnimateOnEnter
|
||||||
|
? "animate-waterfall"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<MatchItem game={game} />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import { createStore, produce } from "solid-js/store";
|
||||||
|
|
||||||
|
export type Match = {
|
||||||
|
id: string | number;
|
||||||
|
scheduledAt: string;
|
||||||
|
event: {
|
||||||
|
id: string | number;
|
||||||
|
name: string;
|
||||||
|
matchday: string | number;
|
||||||
|
};
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MatchStoreState = {
|
||||||
|
matches: Match[];
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [matchStore, setMatchStore] = createStore<MatchStoreState>({
|
||||||
|
matches: [],
|
||||||
|
isLoading: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function loadMatches() {
|
||||||
|
if (matchStore.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMatchStore({ isLoading: true, error: null });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/v1/matches");
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to load matches (${response.status})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = (await response.json()) as Match[];
|
||||||
|
setMatchStore({ matches: data, isLoading: false, error: null });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : "Unknown error";
|
||||||
|
setMatchStore({ isLoading: false, error: message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadMatch(id: string) {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/v1/matches/" + id);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to load match ${id} (${response.status})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = (await response.json()) as Match;
|
||||||
|
|
||||||
|
patchMatch(id, data);
|
||||||
|
|
||||||
|
const stats = await fetch(`/api/v1/matches/${id}/stats`);
|
||||||
|
if (!stats.ok) {
|
||||||
|
throw new Error(`Failed to load match stats ${id} (${response.status})`);
|
||||||
|
}
|
||||||
|
patchMatch(id, (await stats.json()) as Match);
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : "Unknown error";
|
||||||
|
setMatchStore({ error: message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setMatch(updatedMatch: Match) {
|
||||||
|
setMatchStore(
|
||||||
|
"matches",
|
||||||
|
produce((matches) => {
|
||||||
|
const index = matches.findIndex((match) => match.id === updatedMatch.id);
|
||||||
|
if (index === -1) {
|
||||||
|
matches.push(updatedMatch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
matches[index] = updatedMatch;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function patchMatch(matchId: Match["id"], partialMatch: Partial<Match>) {
|
||||||
|
setMatchStore(
|
||||||
|
"matches",
|
||||||
|
produce((matches) => {
|
||||||
|
const index = matches.findIndex((match) => match.id === matchId);
|
||||||
|
if (index === -1) {
|
||||||
|
matches.push(partialMatch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches[index] = {
|
||||||
|
...matches[index],
|
||||||
|
...partialMatch,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { matchStore };
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"target": "es2023",
|
||||||
|
"module": "esnext",
|
||||||
|
"lib": ["ES2023", "DOM"],
|
||||||
|
"types": ["vite/client"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "solid-js",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"target": "es2023",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "esnext",
|
||||||
|
"types": ["node"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import solid from 'vite-plugin-solid'
|
||||||
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
tailwindcss(),
|
||||||
|
solid()],
|
||||||
|
server: {
|
||||||
|
port: 5173,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (p) => p.replace(/^\/api/, ''),
|
||||||
|
},
|
||||||
|
'/live-scores': {
|
||||||
|
target: 'ws://localhost:3000',
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,415 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "kickern.app",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"prettier": "^3.8.4",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"apps/backend": {
|
||||||
|
"name": "backend",
|
||||||
|
"version": "1.0.50",
|
||||||
|
"dependencies": {
|
||||||
|
"elysia": "latest",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"bun-types": "latest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"apps/frontend": {
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@serwist/vite": "^9.5.11",
|
||||||
|
"@serwist/window": "^9.5.11",
|
||||||
|
"@solidjs/router": "^0.16.1",
|
||||||
|
"@tailwindcss/vite": "^4.3.1",
|
||||||
|
"solid-js": "^1.9.12",
|
||||||
|
"tailwindcss": "^4.3.1",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.12.3",
|
||||||
|
"typescript": "~6.0.2",
|
||||||
|
"vite": "^8.0.12",
|
||||||
|
"vite-plugin-solid": "^2.11.12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
|
||||||
|
|
||||||
|
"@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
|
||||||
|
|
||||||
|
"@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="],
|
||||||
|
|
||||||
|
"@babel/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="],
|
||||||
|
|
||||||
|
"@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="],
|
||||||
|
|
||||||
|
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="],
|
||||||
|
|
||||||
|
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="],
|
||||||
|
|
||||||
|
"@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="],
|
||||||
|
|
||||||
|
"@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="],
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A=="],
|
||||||
|
|
||||||
|
"@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="],
|
||||||
|
|
||||||
|
"@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="],
|
||||||
|
|
||||||
|
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="],
|
||||||
|
|
||||||
|
"@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="],
|
||||||
|
|
||||||
|
"@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
||||||
|
|
||||||
|
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
|
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||||
|
|
||||||
|
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
|
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="],
|
||||||
|
|
||||||
|
"@oxc-project/types": ["@oxc-project/types@0.133.0", "", {}, "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.3", "", { "os": "android", "cpu": "arm64" }, "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.3", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA=="],
|
||||||
|
|
||||||
|
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
|
||||||
|
|
||||||
|
"@serwist/build": ["@serwist/build@9.5.11", "", { "dependencies": { "@serwist/utils": "9.5.11", "common-tags": "1.8.2", "glob": "13.0.6", "pretty-bytes": "6.1.1", "source-map": "0.8.0-beta.0", "type-fest": "5.6.0", "zod": "4.4.1" }, "peerDependencies": { "typescript": ">=5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-PQfW+LhADYFOOp0PhEnjlgJCyKor6cYa06d3rID1OpiKzkmCApJV1WYfdTBB96jXaWv6OWcWSbSV4tqDLxvaVA=="],
|
||||||
|
|
||||||
|
"@serwist/utils": ["@serwist/utils@9.5.11", "", { "peerDependencies": { "browserslist": ">=4" }, "optionalPeers": ["browserslist"] }, "sha512-zqxmwuHqWA3OwN82Wo8gFZ9QBemygJP3cap5JWAOG4UyJZgUZfmBXAXj+IMaD4eKZ/6pqrxHHDZ9uSWZmJ1mXA=="],
|
||||||
|
|
||||||
|
"@serwist/vite": ["@serwist/vite@9.5.11", "", { "dependencies": { "@serwist/build": "9.5.11", "@serwist/utils": "9.5.11", "glob": "13.0.6", "kolorist": "1.8.0", "serwist": "9.5.11", "zod": "4.4.1" }, "peerDependencies": { "rollup": ">=4.0.0", "typescript": ">=5.0.0", "vite": ">=5.0.0" }, "optionalPeers": ["rollup", "typescript"] }, "sha512-mnshiiCkcoDJqduWI5sK5NdivCaQIQnPrEoVbUzuxKTWPn8wbDyL/UYYgHRv5GdixQxTgRTHWIvvT5c1f4JSAg=="],
|
||||||
|
|
||||||
|
"@serwist/window": ["@serwist/window@9.5.11", "", { "dependencies": { "@types/trusted-types": "2.0.7", "serwist": "9.5.11" }, "peerDependencies": { "typescript": ">=5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-OrH9srhmifUvY36NuukHSZby24XTEk4pHh3pfY0GBQzA9ouU1fYh+ORWhKxH7/wkVHRr3sc4YAhjtpfL14PjjQ=="],
|
||||||
|
|
||||||
|
"@sinclair/typebox": ["@sinclair/typebox@0.34.49", "", {}, "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A=="],
|
||||||
|
|
||||||
|
"@solidjs/router": ["@solidjs/router@0.16.1", "", { "peerDependencies": { "solid-js": "^1.8.6" } }, "sha512-IhyjedgC6LRpw/8CPGGI89FrV+r0xTHzOl2c4CRyzYQ1bLepJxbVI1LLKvsavMWY5TRBRacV7hAeOhuTXkjiqg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/node": ["@tailwindcss/node@4.3.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.1" } }, "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.1", "@tailwindcss/oxide-darwin-arm64": "4.3.1", "@tailwindcss/oxide-darwin-x64": "4.3.1", "@tailwindcss/oxide-freebsd-x64": "4.3.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", "@tailwindcss/oxide-linux-x64-musl": "4.3.1", "@tailwindcss/oxide-wasm32-wasi": "4.3.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.1", "", { "os": "android", "cpu": "arm64" }, "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.1", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/vite": ["@tailwindcss/vite@4.3.1", "", { "dependencies": { "@tailwindcss/node": "4.3.1", "@tailwindcss/oxide": "4.3.1", "tailwindcss": "4.3.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ=="],
|
||||||
|
|
||||||
|
"@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="],
|
||||||
|
|
||||||
|
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||||
|
|
||||||
|
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="],
|
||||||
|
|
||||||
|
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||||
|
|
||||||
|
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
|
||||||
|
|
||||||
|
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
|
||||||
|
|
||||||
|
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@24.13.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA=="],
|
||||||
|
|
||||||
|
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
||||||
|
|
||||||
|
"babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.7", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-/O6JWUmjv03OI9lL2ry9bUjpD5S3PclM55RRJEyCdcFZ5W2SEA/59d+l2hNsk3gI6kiWRdRPdOtqZmsQzFN1pQ=="],
|
||||||
|
|
||||||
|
"babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="],
|
||||||
|
|
||||||
|
"backend": ["backend@workspace:apps/backend"],
|
||||||
|
|
||||||
|
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||||
|
|
||||||
|
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.37", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig=="],
|
||||||
|
|
||||||
|
"brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="],
|
||||||
|
|
||||||
|
"browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||||
|
|
||||||
|
"caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="],
|
||||||
|
|
||||||
|
"common-tags": ["common-tags@1.8.2", "", {}, "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="],
|
||||||
|
|
||||||
|
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||||
|
|
||||||
|
"electron-to-chromium": ["electron-to-chromium@1.5.372", "", {}, "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA=="],
|
||||||
|
|
||||||
|
"elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.7", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="],
|
||||||
|
|
||||||
|
"enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="],
|
||||||
|
|
||||||
|
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
||||||
|
|
||||||
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
|
"exact-mirror": ["exact-mirror@0.2.7", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg=="],
|
||||||
|
|
||||||
|
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
||||||
|
|
||||||
|
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||||
|
|
||||||
|
"file-type": ["file-type@22.0.1", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.5", "token-types": "^6.1.2", "uint8array-extras": "^1.5.0" } }, "sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA=="],
|
||||||
|
|
||||||
|
"frontend": ["frontend@workspace:apps/frontend"],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||||
|
|
||||||
|
"glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||||
|
|
||||||
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
|
"html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
|
||||||
|
|
||||||
|
"idb": ["idb@8.0.3", "", {}, "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg=="],
|
||||||
|
|
||||||
|
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||||
|
|
||||||
|
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
|
||||||
|
|
||||||
|
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
||||||
|
|
||||||
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
|
|
||||||
|
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||||
|
|
||||||
|
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||||
|
|
||||||
|
"kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="],
|
||||||
|
|
||||||
|
"lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
||||||
|
|
||||||
|
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
|
||||||
|
|
||||||
|
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
|
||||||
|
|
||||||
|
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
|
||||||
|
|
||||||
|
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
|
||||||
|
|
||||||
|
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
|
||||||
|
|
||||||
|
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
|
||||||
|
|
||||||
|
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
||||||
|
|
||||||
|
"lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="],
|
||||||
|
|
||||||
|
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||||
|
|
||||||
|
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||||
|
|
||||||
|
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
|
||||||
|
|
||||||
|
"merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="],
|
||||||
|
|
||||||
|
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||||
|
|
||||||
|
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
|
||||||
|
|
||||||
|
"node-releases": ["node-releases@2.0.47", "", {}, "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og=="],
|
||||||
|
|
||||||
|
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||||
|
|
||||||
|
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
||||||
|
|
||||||
|
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
||||||
|
|
||||||
|
"postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="],
|
||||||
|
|
||||||
|
"prettier": ["prettier@3.8.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q=="],
|
||||||
|
|
||||||
|
"pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
|
||||||
|
|
||||||
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||||
|
|
||||||
|
"rolldown": ["rolldown@1.0.3", "", { "dependencies": { "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.3", "@rolldown/binding-darwin-arm64": "1.0.3", "@rolldown/binding-darwin-x64": "1.0.3", "@rolldown/binding-freebsd-x64": "1.0.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", "@rolldown/binding-linux-arm64-gnu": "1.0.3", "@rolldown/binding-linux-arm64-musl": "1.0.3", "@rolldown/binding-linux-ppc64-gnu": "1.0.3", "@rolldown/binding-linux-s390x-gnu": "1.0.3", "@rolldown/binding-linux-x64-gnu": "1.0.3", "@rolldown/binding-linux-x64-musl": "1.0.3", "@rolldown/binding-openharmony-arm64": "1.0.3", "@rolldown/binding-wasm32-wasi": "1.0.3", "@rolldown/binding-win32-arm64-msvc": "1.0.3", "@rolldown/binding-win32-x64-msvc": "1.0.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g=="],
|
||||||
|
|
||||||
|
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
|
"seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="],
|
||||||
|
|
||||||
|
"seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="],
|
||||||
|
|
||||||
|
"serwist": ["serwist@9.5.11", "", { "dependencies": { "@serwist/utils": "9.5.11", "idb": "8.0.3" }, "peerDependencies": { "typescript": ">=5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-Bq6uwJFd4ET60BWI77v3VbazKHv6k7lECOiiCFwKyBu/slaCn0GHJ5L5RfsuJUKrnbD9lYUCDo6sqaKRM5M2vA=="],
|
||||||
|
|
||||||
|
"solid-js": ["solid-js@1.9.13", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-6hJeJMOcEX8ktqjpDoJZEmld3ijvcvWBDtiXBm7f4332SiFN66QeAQI1REQshvyUoISsSeJ4PHDauKYbwao9JQ=="],
|
||||||
|
|
||||||
|
"solid-refresh": ["solid-refresh@0.6.3", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/helper-module-imports": "^7.22.15", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA=="],
|
||||||
|
|
||||||
|
"source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="],
|
||||||
|
|
||||||
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
|
"strtok3": ["strtok3@10.3.5", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA=="],
|
||||||
|
|
||||||
|
"tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="],
|
||||||
|
|
||||||
|
"tailwindcss": ["tailwindcss@4.3.1", "", {}, "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q=="],
|
||||||
|
|
||||||
|
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
|
||||||
|
|
||||||
|
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
||||||
|
|
||||||
|
"token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="],
|
||||||
|
|
||||||
|
"tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"type-fest": ["type-fest@5.6.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||||
|
|
||||||
|
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
|
||||||
|
|
||||||
|
"vite": ["vite@8.0.16", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw=="],
|
||||||
|
|
||||||
|
"vite-plugin-solid": ["vite-plugin-solid@2.11.12", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-FgjPcx2OwX9h6f28jli7A4bG7PP3te8uyakE5iqsmpq3Jqi1TWLgSroC9N6cMfGRU2zXsl4Q6ISvTr2VL0QHpA=="],
|
||||||
|
|
||||||
|
"vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
|
||||||
|
|
||||||
|
"webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="],
|
||||||
|
|
||||||
|
"whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="],
|
||||||
|
|
||||||
|
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||||
|
|
||||||
|
"zod": ["zod@4.4.1", "", {}, "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node": ["@types/node@25.9.3", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg=="],
|
||||||
|
|
||||||
|
"frontend/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
||||||
|
|
||||||
|
"path-scurry/lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node/undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "kickern.app",
|
||||||
|
"private": true,
|
||||||
|
"workspaces": [
|
||||||
|
"apps/*",
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev:backend": "bun --filter backend dev",
|
||||||
|
"dev:frontend": "bun --filter frontend dev",
|
||||||
|
"dev": "bun --filter \"*\" dev"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"prettier": "^3.8.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user