122 Commits

Author SHA1 Message Date
564660f7a6 Update .env
All checks were successful
CI / build (push) Successful in 16s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 35s
2025-12-11 12:00:59 +01:00
bb4378a5ab add line 3
All checks were successful
CI / build (push) Successful in 18s
CI / lint (push) Successful in 19s
CI / create-and-publish-docker-image (push) Successful in 27s
2025-11-27 20:20:05 +01:00
054f64867a Update src/components/Terminal/Terminal.tsx
All checks were successful
CI / build (push) Successful in 10s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Successful in 28s
2025-11-16 21:36:39 +01:00
31687a50e7 Update src/components/Terminal/Terminal.tsx
All checks were successful
CI / build (push) Successful in 21s
CI / lint (push) Successful in 20s
CI / create-and-publish-docker-image (push) Successful in 38s
2025-10-17 11:23:21 +02:00
94c2031707 weed regression
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Successful in 13s
2025-09-24 20:24:10 +02:00
29512969bc always use day weather icons
All checks were successful
CI / build (push) Successful in 15s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 14s
2025-09-24 20:19:35 +02:00
380e74bb2f good commit
All checks were successful
CI / build (push) Successful in 15s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 15s
2025-09-24 20:17:01 +02:00
13818fcaa6 quick timetable style fix
All checks were successful
CI / build (push) Successful in 16s
CI / lint (push) Successful in 19s
CI / create-and-publish-docker-image (push) Successful in 40s
2025-09-24 20:14:48 +02:00
ff89115f36 pegasus, more like MEGASUS
All checks were successful
CI / build (push) Successful in 29s
CI / lint (push) Successful in 11s
CI / create-and-publish-docker-image (push) Successful in 1m16s
2025-09-24 19:44:51 +02:00
4f362ca2de quick commit 2025-09-24 19:43:02 +02:00
42066195da fix docker-compose yml
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 15s
2025-09-03 15:26:54 +02:00
f7c97169d0 check git hash to reset page
All checks were successful
CI / build (push) Successful in 34s
CI / lint (push) Successful in 8s
CI / create-and-publish-docker-image (push) Successful in 13s
2025-09-03 15:15:08 +02:00
5cb323a1d2 remove useless import
Some checks failed
CI / build (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / create-and-publish-docker-image (push) Has been cancelled
2025-09-03 14:57:57 +02:00
8314c4daf8 fix sorting of chores 2025-09-03 14:57:35 +02:00
cb4ce4188e Amogus cleanup
All checks were successful
CI / build (pull_request) Successful in 12s
CI / lint (pull_request) Successful in 10s
CI / create-and-publish-docker-image (pull_request) Successful in 14s
CI / build (push) Successful in 12s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Successful in 12s
2025-09-01 20:24:19 +02:00
53db7e795c Bad collision 2025-09-01 20:24:19 +02:00
3606f9b043 restart firefox after pull 2025-09-01 20:24:19 +02:00
5da900c1c3 Enhance Amogus 2025-09-01 20:24:19 +02:00
8653365af1 rename github folder
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Successful in 14s
2025-08-31 23:55:45 +02:00
d914f47640 Merge branch 'better-deploy'
Some checks failed
CI / build (push) Successful in 15s
CI / lint (push) Successful in 13s
CI / create-and-publish-docker-image (push) Has been cancelled
2025-08-31 21:04:52 +02:00
668d260fd6 fix typo in ci
All checks were successful
CI / build (push) Successful in 15s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 18s
2025-08-31 18:36:41 +02:00
03dc0984f3 quic commit
Some checks failed
CI / build (push) Successful in 13s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Failing after 16s
2025-08-31 18:26:33 +02:00
0d94904c50 set HYPRLAND_INSTANCE_SIGNATURE
Some checks failed
CI / build (push) Successful in 13s
CI / create-and-publish-docker-image (push) Failing after 7s
CI / lint (push) Successful in 8s
2025-08-31 18:25:32 +02:00
2c805ab513 dont publish if lint fails
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 9s
CI / create-and-publish-docker-image (push) Successful in 11s
CI / build (pull_request) Successful in 12s
CI / lint (pull_request) Successful in 9s
CI / create-and-publish-docker-image (pull_request) Successful in 12s
2025-08-31 18:22:15 +02:00
2b21310dfb add githooks and setup.sh 2025-08-31 18:22:15 +02:00
756e709181 correct permission on shell script 2025-08-31 18:22:15 +02:00
9872b64fbd create git hash html 2025-08-31 18:22:15 +02:00
b6c9c51ec3 docker image now uses dist folder from build step for deploy 2025-08-31 18:22:15 +02:00
83f872577b ensure git-hash.js is in dist folder 2025-08-31 18:22:15 +02:00
2b489e83ba write git sha env variable into docker container 2025-08-31 18:22:15 +02:00
6189b80ff1 Bouncing Amogus
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 11s
CI / create-and-publish-docker-image (push) Successful in 19s
2025-08-31 18:21:01 +02:00
df2999516d auto restart firefox after publish; write git hash into file for server
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 10s
CI / create-and-publish-docker-image (push) Successful in 18s
2025-08-31 16:48:10 +02:00
24f0aa75d5 code style fix
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 9s
CI / build-and-push-docker (push) Successful in 18s
2025-08-31 16:02:49 +02:00
8f9b2c6abe uncomment (the most) important code
Some checks failed
CI / build (push) Successful in 13s
CI / lint (push) Failing after 9s
CI / build-and-push-docker (push) Successful in 19s
2025-08-31 16:01:43 +02:00
6595a7f8bb fix code style issues
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 9s
CI / build-and-push-docker (push) Successful in 18s
2025-08-31 15:59:22 +02:00
c95c9de320 fix code style issues 2025-08-31 15:58:58 +02:00
f7de45e47c add small 420 widget 2025-08-31 15:58:31 +02:00
7556d0496a Amogus 2025-08-31 01:10:19 +02:00
7d68cce351 fix code style 2025-08-30 23:51:26 +02:00
e051a1aa4f add token for biome 2025-08-30 23:51:26 +02:00
e9ef31e7ee use biome giithub action 2025-08-30 23:51:26 +02:00
bba4960276 use bunx to run biome 2025-08-30 23:51:26 +02:00
b1d639f618 run bun install before lint 2025-08-30 23:51:26 +02:00
1702e0c408 run multiple lint commands in one sub step 2025-08-30 23:51:26 +02:00
f87d3da269 Add missing semicolon 2025-08-30 23:33:55 +02:00
bbee38af9b Change margin to padding becaue I am dumb 2025-08-30 23:29:46 +02:00
55d86dbcaf fix ci
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 9s
CI / build-and-push-docker (push) Successful in 18s
2025-08-30 23:24:51 +02:00
e366379a57 fix typo in docker-compose file 2025-08-30 23:24:51 +02:00
19aa35195f add nginx file to docker container 2025-08-30 23:24:51 +02:00
4926c3b388 Fix header and make content scroll on overflow 2025-08-30 23:17:10 +02:00
45a02b84f2 Fix timetable width
All checks were successful
CI / build (push) Successful in 11s
CI / lint (push) Successful in 8s
CI / build-and-push-docker (push) Successful in 12s
2025-08-30 22:52:18 +02:00
7face12353 use docker compose down command to stop container 2025-08-30 22:34:33 +02:00
59dc667c15 Fix card header alignment and add weather to footer 2025-08-30 22:30:17 +02:00
0347ead200 Add headers to card component 2025-08-30 22:04:30 +02:00
9dbb0d6b4d Card container components for a cleaner dashboard 2025-08-30 21:24:48 +02:00
6c0e427d0e fix doctype error
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 9s
CI / build-and-push-docker (push) Successful in 25s
2025-08-29 16:16:12 +02:00
5f5f0c46fe try fix cors issues
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 7s
CI / build-and-push-docker (push) Successful in 12s
2025-08-29 15:57:21 +02:00
12f1e0ed69 use dist as name for build artifact
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 7s
CI / build-and-push-docker (push) Successful in 20s
2025-08-29 14:55:07 +02:00
01081dd26d fix docker compose file
Some checks failed
CI / build (push) Successful in 12s
CI / lint (push) Successful in 6s
CI / build-and-push-docker (push) Failing after 9s
2025-08-29 14:53:36 +02:00
9d4b5db64d use nginx for prod
Some checks failed
CI / build (push) Successful in 12s
CI / lint (push) Successful in 10s
CI / build-and-push-docker (push) Has been cancelled
2025-08-29 14:52:44 +02:00
795df16f5b revert dockerfile
All checks were successful
CI / build (push) Successful in 12s
CI / lint (push) Successful in 7s
CI / build-and-push-docker (push) Successful in 36s
2025-08-29 14:37:34 +02:00
55af06c573 revert dockerfile
All checks were successful
CI / build (push) Successful in 14s
CI / lint (push) Successful in 9s
CI / build-and-push-docker (push) Successful in 36s
2025-08-29 14:34:59 +02:00
a05eb48143 ci test
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 7s
CI / build-and-push-docker (push) Successful in 12s
2025-08-29 14:32:02 +02:00
86e301cad6 fix typo in dockerfile
All checks were successful
CI / build (push) Successful in 13s
CI / lint (push) Successful in 7s
CI / build-and-push-docker (push) Successful in 18s
2025-08-29 14:28:36 +02:00
ae4b2b6179 fix dockerfile
Some checks failed
CI / build (push) Successful in 12s
CI / lint (push) Successful in 8s
CI / build-and-push-docker (push) Failing after 11s
2025-08-29 14:27:38 +02:00
8ffb850322 fix dockerfile
All checks were successful
CI / build (push) Successful in 20s
CI / lint (push) Successful in 8s
CI / build-and-push-docker (push) Successful in 54s
2025-08-29 14:21:52 +02:00
9d0d458fe3 ci test commit
Some checks failed
CI / build (pull_request) Successful in 11s
CI / lint (pull_request) Has been cancelled
CI / build-and-push-docker (pull_request) Has been cancelled
CI / build (push) Successful in 11s
CI / lint (push) Successful in 8s
CI / build-and-push-docker (push) Successful in 18s
2025-08-29 14:01:37 +02:00
2cb457c776 ci test commit 2025-08-29 13:56:53 +02:00
18bf7cb6ce fix path in dockerfile 2025-08-29 13:55:21 +02:00
a625aee9d8 use nginx for docker image 2025-08-29 13:54:43 +02:00
65fa8badd8 only create artifact for build 2025-08-29 13:51:00 +02:00
a18a1bfc9b fix biome when dist folder is present 2025-08-29 13:48:47 +02:00
aeb8e836eb create buid artifact 2025-08-29 13:43:50 +02:00
8126813216 ci test commit 2025-08-29 13:39:00 +02:00
8d644dbd35 ci test commit 2025-08-29 13:38:49 +02:00
94b4c24bb3 ci test commit 2025-08-29 13:38:20 +02:00
c80e5e9f07 ci test commit 2025-08-29 13:37:38 +02:00
a40f8c875d ci test commit 2025-08-29 13:34:36 +02:00
085cbe3363 ci test commit 2025-08-29 13:31:48 +02:00
042cbe97c5 ci test commit 2025-08-29 13:29:39 +02:00
abb4db5864 use lower artifact up/download actions 2025-08-29 13:27:30 +02:00
466b73652c set path for build artifact 2025-08-29 13:26:06 +02:00
63322a2c56 use artifacts instead of checkout 2025-08-29 13:25:02 +02:00
3a5e5ab2b9 revert biome action 2025-08-29 13:20:36 +02:00
20bf530f18 use biome action directly 2025-08-29 13:19:19 +02:00
69f46059e0 add weather module 2025-08-29 13:15:38 +02:00
b27be08b87 install classnames 2025-08-29 12:13:49 +02:00
66ad042bf1 fix rebase issues 2025-08-29 11:57:14 +02:00
79117da969 Add Card components 2025-08-29 11:53:29 +02:00
afde557605 New font and new footer 2025-08-29 11:52:37 +02:00
6dfa50f3ed Make dashboard change background based on time of day 2025-08-29 11:52:37 +02:00
a4fe525b9e highlight due date
All checks were successful
CI / lint (push) Successful in 14s
CI / build (push) Successful in 17s
CI / build-and-push-docker (push) Successful in 31s
2025-08-28 22:51:18 +02:00
d37dbc4f62 sort chores using due date, color tasks according to due level 2025-08-28 22:51:18 +02:00
c7b03a93f0 fix code style, use names from api instead of hardcoding for flatmates users 2025-08-28 22:51:18 +02:00
c924ab893e Full tram stop names and final prompt in terminal 2025-08-28 22:48:06 +02:00
05c62ed6bb New Terminal 2025-08-28 22:37:20 +02:00
481f103ba0 Make clock divider blink 2025-08-28 21:36:53 +02:00
aa8da0bb56 Terminal window
All checks were successful
CI / lint (pull_request) Successful in 8s
CI / build (pull_request) Successful in 10s
CI / build-and-push-docker (pull_request) Successful in 13s
2025-08-28 20:38:45 +02:00
42419e2e3b Clock widget and more copypasta 2025-08-28 18:08:58 +02:00
b1adbe74de Windows look update 2025-08-28 18:08:58 +02:00
241db688c2 A e s t h e t i c s 2025-08-28 18:08:58 +02:00
7f12cb59d8 HomeAssistant update 2025-08-28 18:08:58 +02:00
0cb9867bc7 Footer 2025-08-28 18:08:58 +02:00
97d9a04b29 Dashboard with cards 2025-08-28 18:08:58 +02:00
97737def29 Timetable styling 2025-08-28 18:08:58 +02:00
ef67915621 Devcontainer support 2025-08-28 18:08:58 +02:00
040178e395 manual trigger for ci
All checks were successful
CI / lint (push) Successful in 10s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Successful in 14s
2025-08-28 18:06:36 +02:00
01f6a07672 use password to login
All checks were successful
CI / lint (push) Successful in 9s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Successful in 14s
2025-08-28 16:02:05 +02:00
10508f5ecd add debug code in ci.yml
Some checks failed
CI / lint (push) Successful in 8s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Failing after 13s
2025-08-28 15:59:00 +02:00
5fe9376533 use docker compose instead of docker in ci.yml
Some checks failed
CI / lint (push) Successful in 9s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Failing after 13s
2025-08-28 15:55:12 +02:00
f694284c29 fix false username in ci.yml
Some checks failed
CI / lint (push) Successful in 8s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Failing after 12s
2025-08-28 15:51:06 +02:00
414b59ddb1 quick commit
Some checks failed
CI / build (push) Successful in 9s
CI / lint (push) Successful in 17s
CI / build-and-push-docker (push) Failing after 25s
2025-08-28 15:48:32 +02:00
63f906bb02 update server on main changes
Some checks failed
CI / lint (push) Successful in 10s
CI / build (push) Successful in 9s
Build Docker Image / build-and-push-docker (push) Has been cancelled
2025-08-28 15:47:45 +02:00
194b0b58ed fix typo in url
All checks were successful
CI / build (push) Successful in 10s
CI / lint (push) Successful in 16s
Build Docker Image / build-and-push-docker (push) Successful in 11s
2025-08-28 13:36:27 +02:00
9b17385043 also push image
Some checks failed
CI / build (push) Successful in 11s
CI / lint (push) Successful in 7s
Build Docker Image / build-and-push-docker (push) Failing after 19s
2025-08-28 13:32:51 +02:00
7875b8edef add docker build.yml
All checks were successful
CI / build (push) Successful in 10s
CI / lint (push) Successful in 8s
Build Docker Image / build-docker (push) Successful in 55s
2025-08-28 13:28:01 +02:00
e17829e7fa create github action
All checks were successful
CI / build (push) Successful in 19s
CI / lint (push) Successful in 8s
2025-08-28 13:08:32 +02:00
1e634ed122 Merge branch 'runner' into 'main'
Runner

See merge request arifhasanic/monitor-im-flur!1
2025-08-27 22:02:55 +00:00
16131521bc remove tags from gitlab yaml 2025-08-27 23:38:47 +02:00
741720ed07 add build image script 2025-08-27 23:34:53 +02:00
4ae7e7968b fix gitlab ci yml 2025-08-27 22:54:09 +02:00
90e6842d71 setup ci, fix files using biome 2025-08-27 22:51:50 +02:00
67 changed files with 2016 additions and 377 deletions

View File

@@ -0,0 +1,55 @@
{
"name": "bun",
"image": "oven/bun:debian",
"privileged": true,
"features": {
"ghcr.io/devcontainers/features/common-utils:1": {
"version": "latest",
"configureZshAsDefaultShell": true,
"username": "bun",
"userUid": "1000",
"userGid": "1000"
},
"ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {
"packages": "stow,tmux,ripgrep,python3-venv,python3-virtualenv"
}
},
"remoteUser": "bun",
"workspaceFolder": "/home/bun/ws",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/bun/ws,type=bind",
"containerEnv": {},
"runArgs": [
"--net=host",
"-e",
"DISPLAY=${env:DISPLAY}",
"-e",
"TERM=${env:TERM}",
"-e",
"SHELL=${env:SHELL}",
"-v",
"${env:SSH_AUTH_SOCK}:/tmp/ssh-agent.socket",
"-e",
"SSH_AUTH_SOCK=/tmp/ssh-agent.socket"
],
"mounts": [
{
"source": "/tmp/.X11-unix",
"target": "/tmp/.X11-unix",
"type": "bind",
"consistency": "cached"
},
{
"source": "/dev/dri",
"target": "/dev/dri",
"type": "bind",
"consistency": "cached"
},
{
"source": "/dev/shm",
"target": "/dev/shm",
"type": "bind",
"consistency": "cached"
}
],
"postCreateCommand": {}
}

2
.env
View File

@@ -1 +1 @@
VITE_FLATTASTIC_API_KEY="Lrq8tXOeK4aA1563zvS1soZZElKoomz2"
VITE_FLATTASTIC_API_KEY="bqOh7YBZR9fChJo81bCsTinMtGpC5aok"

78
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,78 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
container:
image: oven/bun
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: bun install
- name: Build
run: bun run build
- name: Write Git-Hash into html
run: ./pipeline/create-git-hash-html.sh
- name: Create Build Artifact
uses: christopherhx/gitea-upload-artifact@v4
with:
name: dist
path: dist
lint:
runs-on: ubuntu-latest
needs: build
container:
image: oven/bun
steps:
- uses: actions/checkout@v4
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest
token: ${{ secrets.BIOME_TOKEN }}
- name: Run Biome
run: biome ci .
create-and-publish-docker-image:
needs: [lint]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: christopherhx/gitea-download-artifact@v4
with:
name: dist
path: dist
- name: Log in to Docker Registry
uses: docker/login-action@v2
with:
registry: git.rivercry.com
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
run: docker build -t git.rivercry.com/wg/monitor-im-flur .
- name: Push Docker image
run: docker push git.rivercry.com/wg/monitor-im-flur
- name: Deploy via SSH
uses: appleboy/ssh-action@v0.1.10
with:
host: rivercry.com
port: 20022
username: docker
password: ${{ secrets.GARRISON_DOCKER_PASSWORD }}
script: |
cd monitor-im-flur
git clean -dfx
git reset --hard HEAD
git pull
docker-compose pull
docker-compose down
docker-compose up -d

View File

@@ -1,3 +0,0 @@
# Ignore artifacts:
build
coverage

View File

@@ -1,4 +0,0 @@
{
"tabWidth": 4,
"useTabs": false
}

View File

@@ -1,15 +1,5 @@
FROM oven/bun
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install
COPY . .
RUN bun run build
EXPOSE 5173
CMD ["bun", "run", "dev", "--host"]
FROM nginx:alpine
COPY ./dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

188
README.md
View File

@@ -1,69 +1,135 @@
# React + TypeScript + Vite
## monitor-im-flur
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
![Build Status](https://git.rivercry.com/wg/monitor-im-flur/badges/master/pipeline.svg)
Currently, two official plugins are available:
Hallway / common-area wall monitor dashboard. A single-page React + Vite app that surfaces useful household + transit + weather + fun data on a passive display.
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
### Key Features
* Realtime-ish autorefresh via git commit hash file (`/git-hash.html`) hot-reloads the deployed page when a new build is published.
* Dynamic theming (day / evening / night) based on current time.
* Public transport departures (KVV) for two nearby stops (IDs 7000044 & 7000045).
* Weather (current, hourly, daily min/max) via OpenMeteo.
* Flatastic chores integration (tasks + flatmates) with API key.
* Home Assistant readings (tent temperature + humidity) displayed in a faux terminal with rotating shitposts.
* 4:20 easter egg card + Amogus sprite + other playful flourishes.
* Docker / Nginx static deployment image (`git.rivercry.com/wg/monitor-im-flur:latest`).
* Strict linting + formatting (ESLint AirBnB + Prettier + Biome optional).
* Zustand + RTK (toolkit present) state management (currently Zustand in active use).
## Expanding the ESLint configuration
### Tech Stack
* React 19 + TypeScript + Vite
* Zustand (with devtools) for app stores (weather, kvv, flatastic, home assistant)
* Nginx (static file serving) inside minimal Docker image
* OpenMeteo, Flatastic, KVV, Home Assistant external APIs
* Git hash pipeline script to trigger client selfreloads
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default tseslint.config([
globalIgnores(["dist"]),
{
files: ["**/*.{ts,tsx}"],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
]);
### Project Structure (abridged)
```
src/
api/ # External data fetchers
components/ # UI building blocks (Cards, Timetable, Weather, Terminal, etc.)
store/ # Zustand stores encapsulating fetch + state
types/ # Type definitions for external data
pipeline/
create-git-hash-html.sh # Injects current commit hash into dist
Dockerfile # Nginx static hosting
docker-compose.yml # Example runtime service definition
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from "eslint-plugin-react-x";
import reactDom from "eslint-plugin-react-dom";
export default tseslint.config([
globalIgnores(["dist"]),
{
files: ["**/*.{ts,tsx}"],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs["recommended-typescript"],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
]);
### Environment Configuration
Create a `.env` (or `.env.local`) for Vite with the following (only what you need):
```
VITE_FLATTASTIC_API_KEY=your_flatastic_api_key
# (Planned) VITE_HOME_ASSISTANT_TOKEN=your_long_lived_token # NOTE: currently hardcoded see Security section
```
Vite automatically exposes variables prefixed with `VITE_` to the client bundle. Do NOT place secrets without that prefix but remember: anything in the client bundle is public. For sensitive data consider a tiny proxy backend instead of calling APIs directly from the browser.
### Security Notice
`src/api/homeAssistant.ts` currently contains a hardcoded longlived Home Assistant token. This should be refactored before any public deployment:
1. Remove the literal token from the repository.
2. Load it via environment variable during build (`import.meta.env.VITE_HOME_ASSISTANT_TOKEN`) OR
3. Prefer a minimal server proxy so the token never ships to the browser.
### Development
Install dependencies (Bun is inferred from `bun.lock`, but npm/pnpm/yarn also work).
```
bun install
```
Run the dev server (HTTPS support possible with `vite-plugin-mkcert` if certificates are trusted):
```
bun run dev
```
Open: http://localhost:5173
### Lint & Format
```
bun run lint
```
Optionally run Biome (if desired):
```
npx biome check --apply .
```
### Build
```
bun run build
```
Outputs production bundle to `dist/`.
### Docker Image
Build locally:
```
docker build -t monitor-im-flur:local .
```
Run:
```
docker run --rm -p 9123:80 monitor-im-flur:local
```
Or use compose (uses published image):
```
docker compose up -d
```
Visit: http://localhost:9123
### Git Hash AutoReload Mechanism
`pipeline/create-git-hash-html.sh` writes the current commit (`$GITHUB_SHA`) to `dist/git-hash.html` during CI. The dashboard polls `/git-hash.html` every 10s; when the value changes it performs `window.location.reload()`. Ensure your CI runs the script after `vite build` and before creating the Docker image.
Pseudo CI step example:
```
vite build
GITHUB_SHA=$(git rev-parse HEAD) ./pipeline/create-git-hash-html.sh
docker build -t git.rivercry.com/wg/monitor-im-flur:$(git rev-parse --short HEAD) .
```
### Data Sources
* KVV Departures: Public endpoint (JSON) for stop IDs 7000044 / 7000045.
* Weather: OpenMeteo forecast API (lat 49.0094, lon 8.4044, Europe/Berlin TZ).
* Flatastic: Auth via `x-api-key` (user provided).
* Home Assistant: Longlived bearer token (refactor recommended).
### Adding a New Card
1. Create a directory under `src/components/<NewCard>/` with `NewCard.tsx` & optional `style.module.css`.
2. Wrap content with existing `Card` component (`icon` + `name` props).
3. Register inside `Dashboard.tsx` where layout lives (using `CardColumn` / `CardRow`).
### State Management Notes
All data fetching is encapsulated inside zustand store `fetch` methods invoked on an interval within the respective components. Consider centralizing polling or using React Query if complexity grows.
### Potential Improvements / TODO
* Remove hardcoded Home Assistant token.
* Error + loading states (currently optimistic, failures would be silent / console only).
* Retry & backoff strategy for network calls.
* Dark mode override / manual theme toggle.
* Accessibility pass (ARIA, focus management) current dashboard is mostly passive.
* Tests (none yet). Could add Vitest + React Testing Library.
* Switch transit API code to gracefully handle outages (KVV sometimes rate limits).
### License
Add a license file if you plan to share externally (currently unspecified).
### Support / Contact
Internal project (wg). For issues open a ticket on Gitea: https://git.rivercry.com/wg/monitor-im-flur
---
Generated README draft adjust repository paths / badge branch name if different (e.g., replace `master` with your default branch).

View File

@@ -1,12 +1,12 @@
{
"$schema": "https://biomejs.dev/schemas/2.1.2/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false
"ignoreUnknown": false,
"includes": ["**", "!**/dist"]
},
"formatter": {
"enabled": true,

278
bun.lock
View File

@@ -7,9 +7,12 @@
"@reduxjs/toolkit": "^2.8.2",
"@types/lodash": "^4.17.20",
"@types/node": "^24.1.0",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"openmeteo": "^1.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-fast-marquee": "^1.6.5",
"react-redux": "^9.2.0",
"redux-persist": "^6.0.0",
"zustand": "^5.0.6",
@@ -34,6 +37,7 @@
"typescript": "~5.8.3",
"typescript-eslint": "^8.35.1",
"vite": "^7.0.4",
"vite-plugin-mkcert": "^1.17.8",
},
},
},
@@ -56,135 +60,135 @@
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-9zajnk59PMpjBkty3bK2IrjUsUHvqe9HWwyAWQBjGLE7MIBjbX2vwv1XPEhmO2RRuGoTkVx3WCanHrjAytICLA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.0", "", {}, "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="],
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
"@eslint/js": ["@eslint/js@9.31.0", "", {}, "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw=="],
"@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.4", "", { "dependencies": { "@eslint/core": "^0.15.1", "levn": "^0.4.1" } }, "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@openmeteo/sdk": ["@openmeteo/sdk@1.23.0", "", { "dependencies": { "flatbuffers": "^25.9.23" } }, "sha512-haGK9vDCYkSq/ikp68NJwgZS1jT9LqUeJEq/tTKqO18g5e/V1m0qKs1Cqt3c7elws2/hbTvX7VLvt8gqoMxU2w=="],
"@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.8.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A=="],
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-hBjYg0aaRL1O2Z0IqWhnTLytnjDIxekmRxm1snsHjHaKVmIF1HiImWqsq+PuEbn6zdMlkIj9WofK1vR8jjx+Xw=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.45.1", "", { "os": "android", "cpu": "arm" }, "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.45.1", "", { "os": "android", "cpu": "arm64" }, "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.45.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.45.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.45.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.45.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.45.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.45.1", "", { "os": "linux", "cpu": "arm" }, "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.45.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.45.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.45.1", "", { "os": "linux", "cpu": "none" }, "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.45.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.45.1", "", { "os": "linux", "cpu": "none" }, "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.45.1", "", { "os": "linux", "cpu": "none" }, "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.45.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.45.1", "", { "os": "linux", "cpu": "x64" }, "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.45.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.45.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.45.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.45.1", "", { "os": "win32", "cpu": "x64" }, "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="],
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
@@ -192,31 +196,31 @@
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
"@swc/core": ["@swc/core@1.13.2", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.23" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.2", "@swc/core-darwin-x64": "1.13.2", "@swc/core-linux-arm-gnueabihf": "1.13.2", "@swc/core-linux-arm64-gnu": "1.13.2", "@swc/core-linux-arm64-musl": "1.13.2", "@swc/core-linux-x64-gnu": "1.13.2", "@swc/core-linux-x64-musl": "1.13.2", "@swc/core-win32-arm64-msvc": "1.13.2", "@swc/core-win32-ia32-msvc": "1.13.2", "@swc/core-win32-x64-msvc": "1.13.2" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-YWqn+0IKXDhqVLKoac4v2tV6hJqB/wOh8/Br8zjqeqBkKa77Qb0Kw2i7LOFzjFNZbZaPH6AlMGlBwNrxaauaAg=="],
"@swc/core": ["@swc/core@1.15.3", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.3", "@swc/core-darwin-x64": "1.15.3", "@swc/core-linux-arm-gnueabihf": "1.15.3", "@swc/core-linux-arm64-gnu": "1.15.3", "@swc/core-linux-arm64-musl": "1.15.3", "@swc/core-linux-x64-gnu": "1.15.3", "@swc/core-linux-x64-musl": "1.15.3", "@swc/core-win32-arm64-msvc": "1.15.3", "@swc/core-win32-ia32-msvc": "1.15.3", "@swc/core-win32-x64-msvc": "1.15.3" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q=="],
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-44p7ivuLSGFJ15Vly4ivLJjg3ARo4879LtEBAabcHhSZygpmkP8eyjyWxrH3OxkY1eRZSIJe8yRZPFw4kPXFPw=="],
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ=="],
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.13.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Lb9EZi7X2XDAVmuUlBm2UvVAgSCbD3qKqDCxSI4jEOddzVOpNCnyZ/xEampdngUIyDDhhJLYU9duC+Mcsv5Y+A=="],
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A=="],
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.13.2", "", { "os": "linux", "cpu": "arm" }, "sha512-9TDe/92ee1x57x+0OqL1huG4BeljVx0nWW4QOOxp8CCK67Rpc/HHl2wciJ0Kl9Dxf2NvpNtkPvqj9+BUmM9WVA=="],
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.3", "", { "os": "linux", "cpu": "arm" }, "sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg=="],
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.13.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KJUSl56DBk7AWMAIEcU83zl5mg3vlQYhLELhjwRFkGFMvghQvdqQ3zFOYa4TexKA7noBZa3C8fb24rI5sw9Exg=="],
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw=="],
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.13.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-teU27iG1oyWpNh9CzcGQ48ClDRt/RCem7mYO7ehd2FY102UeTws2+OzLESS1TS1tEZipq/5xwx3FzbVgiolCiQ=="],
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g=="],
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.13.2", "", { "os": "linux", "cpu": "x64" }, "sha512-dRPsyPyqpLD0HMRCRpYALIh4kdOir8pPg4AhNQZLehKowigRd30RcLXGNVZcc31Ua8CiPI4QSgjOIxK+EQe4LQ=="],
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A=="],
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.13.2", "", { "os": "linux", "cpu": "x64" }, "sha512-CCxETW+KkYEQDqz1SYC15YIWYheqFC+PJVOW76Maa/8yu8Biw+HTAcblKf2isrlUtK8RvrQN94v3UXkC2NzCEw=="],
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.3", "", { "os": "linux", "cpu": "x64" }, "sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug=="],
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.13.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Wv/QTA6PjyRLlmKcN6AmSI4jwSMRl0VTLGs57PHTqYRwwfwd7y4s2fIPJVBNbAlXd795dOEP6d/bGSQSyhOX3A=="],
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA=="],
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.13.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-PuCdtNynEkUNbUXX/wsyUC+t4mamIU5y00lT5vJcAvco3/r16Iaxl5UCzhXYaWZSNVZMzPp9qN8NlSL8M5pPxw=="],
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw=="],
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.13.2", "", { "os": "win32", "cpu": "x64" }, "sha512-qlmMkFZJus8cYuBURx1a3YAG2G7IW44i+FEYV5/32ylKkzGNAr9tDJSA53XNnNXkAB5EXSPsOz7bn5C3JlEtdQ=="],
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.3", "", { "os": "win32", "cpu": "x64" }, "sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog=="],
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
"@swc/types": ["@swc/types@0.1.23", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw=="],
"@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -224,35 +228,35 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="],
"@types/lodash": ["@types/lodash@4.17.21", "", {}, "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="],
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
"@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.38.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/type-utils": "8.38.0", "@typescript-eslint/utils": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.48.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/type-utils": "8.48.0", "@typescript-eslint/utils": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.48.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.38.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.48.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", "@typescript-eslint/typescript-estree": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.38.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.38.0", "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.48.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.48.0", "@typescript-eslint/types": "^8.48.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.48.0", "", { "dependencies": { "@typescript-eslint/types": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0" } }, "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.38.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.48.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.48.0", "", { "dependencies": { "@typescript-eslint/types": "8.48.0", "@typescript-eslint/typescript-estree": "8.48.0", "@typescript-eslint/utils": "8.48.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.48.0", "", {}, "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.38.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.38.0", "@typescript-eslint/tsconfig-utils": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.48.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.48.0", "@typescript-eslint/tsconfig-utils": "8.48.0", "@typescript-eslint/types": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.48.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", "@typescript-eslint/typescript-estree": "8.48.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.48.0", "", { "dependencies": { "@typescript-eslint/types": "8.48.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg=="],
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@3.11.0", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.27", "@swc/core": "^1.12.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7" } }, "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w=="],
@@ -288,9 +292,13 @@
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
"axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="],
"axe-core": ["axe-core@4.11.0", "", {}, "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ=="],
"axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -298,8 +306,6 @@
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
@@ -310,17 +316,21 @@
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"confusing-browser-globals": ["confusing-browser-globals@1.0.11", "", {}, "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
@@ -330,7 +340,7 @@
"data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
@@ -338,6 +348,8 @@
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
@@ -360,11 +372,11 @@
"es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
"esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="],
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.31.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.31.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ=="],
"eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="],
"eslint-config-airbnb": ["eslint-config-airbnb@19.0.4", "", { "dependencies": { "eslint-config-airbnb-base": "^15.0.0", "object.assign": "^4.1.2", "object.entries": "^1.1.5" }, "peerDependencies": { "eslint": "^7.32.0 || ^8.2.0", "eslint-plugin-import": "^2.25.3", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0" } }, "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew=="],
@@ -380,13 +392,13 @@
"eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="],
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w=="],
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.4", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg=="],
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
"eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.20", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA=="],
"eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.24", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
@@ -406,28 +418,28 @@
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatbuffers": ["flatbuffers@25.9.23", "", {}, "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="],
"for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
"form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@@ -436,6 +448,8 @@
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
"generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
@@ -444,7 +458,7 @@
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="],
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
@@ -468,7 +482,7 @@
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"immer": ["immer@10.1.1", "", {}, "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw=="],
"immer": ["immer@11.0.0", "", {}, "sha512-XtRG4SINt4dpqlnJvs70O2j6hH7H0X8fUzFsjMn1rwnETaxwp83HLNimXBjZ78MrKl3/d3/pkzDH0o0Lkxm37Q=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
@@ -496,7 +510,7 @@
"is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
"is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
"is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
@@ -504,8 +518,6 @@
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="],
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
@@ -534,7 +546,7 @@
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
@@ -564,9 +576,9 @@
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
@@ -594,6 +606,8 @@
"object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="],
"openmeteo": ["openmeteo@1.2.2", "", { "dependencies": { "@openmeteo/sdk": "^1.22.0", "flatbuffers": "^25.9.23" } }, "sha512-n0FeYOFts9Tr/KYajfPvFVaYKd0PDQRuG3xnkgVsyagOI91QkVcSo2+CLIYgN4LlGCCVM5FZ5e+dswSG81PGZA=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
@@ -626,13 +640,15 @@
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
"react-fast-marquee": ["react-fast-marquee@1.6.5", "", { "peerDependencies": { "react": ">= 16.8.0 || ^18.0.0", "react-dom": ">= 16.8.0 || ^18.0.0" } }, "sha512-swDnPqrT2XISAih0o74zQVE2wQJFMvkx+9VZXYYNSLb/CUcAzU9pNj637Ar2+hyRw6b4tP6xh4GQZip2ZCpQpg=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -654,11 +670,7 @@
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rollup": ["rollup@4.45.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.45.1", "@rollup/rollup-android-arm64": "4.45.1", "@rollup/rollup-darwin-arm64": "4.45.1", "@rollup/rollup-darwin-x64": "4.45.1", "@rollup/rollup-freebsd-arm64": "4.45.1", "@rollup/rollup-freebsd-x64": "4.45.1", "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", "@rollup/rollup-linux-arm-musleabihf": "4.45.1", "@rollup/rollup-linux-arm64-gnu": "4.45.1", "@rollup/rollup-linux-arm64-musl": "4.45.1", "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", "@rollup/rollup-linux-riscv64-gnu": "4.45.1", "@rollup/rollup-linux-riscv64-musl": "4.45.1", "@rollup/rollup-linux-s390x-gnu": "4.45.1", "@rollup/rollup-linux-x64-gnu": "4.45.1", "@rollup/rollup-linux-x64-musl": "4.45.1", "@rollup/rollup-win32-arm64-msvc": "4.45.1", "@rollup/rollup-win32-ia32-msvc": "4.45.1", "@rollup/rollup-win32-x64-msvc": "4.45.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="],
"safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
@@ -666,7 +678,7 @@
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -714,9 +726,7 @@
"synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
"tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
@@ -734,17 +744,19 @@
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"typescript-eslint": ["typescript-eslint@8.38.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.38.0", "@typescript-eslint/parser": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/utils": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg=="],
"typescript-eslint": ["typescript-eslint@8.48.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.48.0", "@typescript-eslint/parser": "8.48.0", "@typescript-eslint/typescript-estree": "8.48.0", "@typescript-eslint/utils": "8.48.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw=="],
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
"vite": ["vite@7.0.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", "picomatch": "^4.0.2", "postcss": "^8.5.6", "rollup": "^4.40.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.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", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw=="],
"vite": ["vite@7.2.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.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", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w=="],
"vite-plugin-mkcert": ["vite-plugin-mkcert@1.17.9", "", { "dependencies": { "axios": "^1.12.2", "debug": "^4.4.3", "picocolors": "^1.1.1" }, "peerDependencies": { "vite": ">=3" } }, "sha512-SwI7yqp2Cq4r2XItarnHRCj2uzHPqevbxFNMLpyN+LDXd5w1vmZeM4l5X/wCZoP4mjPQYN+9+4kmE6e3nPO5fg=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
@@ -760,32 +772,26 @@
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zustand": ["zustand@5.0.6", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A=="],
"zustand": ["zustand@5.0.8", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-import-resolver-node/resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
"eslint-import-resolver-node/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
}
}

View File

@@ -1,6 +1,6 @@
services:
monitor-im-flur:
build: .
image: git.rivercry.com/wg/monitor-im-flur:latest
ports:
- "9123:5173"
- "9123:80"
restart: unless-stopped

View File

@@ -1,9 +1,9 @@
import js from "@eslint/js";
import globals from "globals";
import { globalIgnores } from "eslint/config";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import tseslint from "typescript-eslint";
import { globalIgnores } from "eslint/config";
export default tseslint.config([
globalIgnores(["dist"]),

12
githooks/pre-commit Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
echo "Running pre-commit hooks..."
biome check --write
biome lint --write
if git diff --quiet; then
exit 0
else
git add -u
fi

View File

@@ -1,4 +1,3 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

27
nginx.conf Normal file
View File

@@ -0,0 +1,27 @@
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html /git-hash.js;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
log_not_found off;
}
}
}

View File

@@ -13,9 +13,12 @@
"@reduxjs/toolkit": "^2.8.2",
"@types/lodash": "^4.17.20",
"@types/node": "^24.1.0",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"openmeteo": "^1.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-fast-marquee": "^1.6.5",
"react-redux": "^9.2.0",
"redux-persist": "^6.0.0",
"zustand": "^5.0.6"
@@ -39,6 +42,7 @@
"prettier": "3.6.2",
"typescript": "~5.8.3",
"typescript-eslint": "^8.35.1",
"vite": "^7.0.4"
"vite": "^7.0.4",
"vite-plugin-mkcert": "^1.17.8"
}
}

View File

@@ -0,0 +1,3 @@
#!/bin/sh
echo "$GITHUB_SHA" > dist/git-hash.html

BIN
public/img/amogus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
public/img/clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
public/img/imposter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

BIN
public/img/weed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

3
setup.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
git config --local core.hooksPath githooks

View File

@@ -1,42 +1,7 @@
#root {
height: 100vh;
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
padding: 0;
text-align: left;
}

View File

@@ -1,16 +1,9 @@
import "@/App.css";
import Flatastic from "@/components/Flatastic/Flatastic";
import HomeAssistant from "@/components/HomeAssistant/HomeAssistant";
import Timetable from "@/components/Timetable/Timetable";
import Dashboard from "@/components/Dashboard/Dashboard";
function App() {
return (
<>
<Timetable />
<Flatastic />
<HomeAssistant />
</>
);
return <Dashboard />;
}
export default App;

View File

@@ -1,12 +1,13 @@
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkMjQ1OTg0YjliYzE0OTNjYTdmZDJmNTA3ODgzN2U1YSIsImlhdCI6MTc1MzQwMjAzNiwiZXhwIjoyMDY4NzYyMDM2fQ.fnLSFKPdk8lkAEB-4ekdGUJ1PSCBxcAyasQF1PyrD3k";
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3N2JmOTk1ODI3MzA0ZWIzOWYwNThjMzQ4YTY3ZDJkYyIsImlhdCI6MTc1NjQ3NTM4OSwiZXhwIjoyMDcxODM1Mzg5fQ.TZZ4SUGlERuIVrhzC_wfCN-qS1wSAKNN9uMMDjkqOgA";
async function fetchTentHumidity() {
const url = "/api/states/sensor.third_reality_inc_3rths0224z_luftfeuchtigkeit_2";
const url = `https://home.rivercry.com/api/states/sensor.third_reality_inc_3rths0224z_luftfeuchtigkeit_2`;
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
}
Authorization: `Bearer ${token}`,
},
});
const data = await response.json();
@@ -14,12 +15,12 @@ async function fetchTentHumidity() {
}
async function fetchTentTemperature() {
const url = "/api/states/sensor.third_reality_inc_3rths0224z_temperatur_2";
const url = `https://home.rivercry.com/api/states/sensor.third_reality_inc_3rths0224z_temperatur_2`;
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
}
Authorization: `Bearer ${token}`,
},
});
const data = await response.json();
@@ -27,4 +28,4 @@ async function fetchTentTemperature() {
return data.state;
}
export { fetchTentHumidity, fetchTentTemperature };
export { fetchTentHumidity, fetchTentTemperature };

View File

@@ -1,5 +1,5 @@
async function fetchKvvDepartures(stopId: number) {
const API_URL = `https://projekte.kvv-efa.de/sl3-alone/XSLT_DM_REQUEST?outputFormat=JSON&coordOutputFormat=WGS84%5Bdd.ddddd%5D&command=&itdLPxx_timeFormat=12&language=de&itdLPxx_useJs=1&std3_suggestMacro=std3_suggest&std3_commonMacro=dm&itdLPxx_contractor=&std3_contractorMacro=&includeCompleteStopSeq=1&useAllStops=1&name_dm=${stopId}&type_dm=any&itdDateTimeDepArr=dep&includedMeans=checkbox&itdLPxx_ptActive=on&useRealtime=1&std3_inclMOT_0Macro=true&std3_inclMOT_1Macro=true&std3_inclMOT_4Macro=true&std3_inclMOT_5Macro=true&imparedOptionsActive=1&nameInfo_dm=${stopId}&itdLPxx_multiStepDm=2&deleteAssignedStops=1&mode=direct&line=kvv%253A22301%253AE%253AH%253As25&line=kvv%253A22301%253AE%253AR%253As25&line=kvv%253A21012%253AE%253AH%253As25&line=kvv%253A21012%253AE%253AR%253As25&line=kvv%253A22305%253AE%253AH%253As25&line=kvv%253A22305%253AE%253AR%253As25&line=kvv%253A22308%253AE%253AR%253As25&line=kvv%253A22311%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AR%253As25&itdLPxx_snippet=1&itdLPxx_template=dmresults&limit=10`;
const API_URL = `https://projekte.kvv-efa.de/sl3-alone/XSLT_DM_REQUEST?outputFormat=JSON&coordOutputFormat=WGS84%5Bdd.ddddd%5D&command=&itdLPxx_timeFormat=12&language=de&itdLPxx_useJs=1&std3_suggestMacro=std3_suggest&std3_commonMacro=dm&itdLPxx_contractor=&std3_contractorMacro=&includeCompleteStopSeq=1&useAllStops=1&name_dm=${stopId}&type_dm=any&itdDateTimeDepArr=dep&includedMeans=checkbox&itdLPxx_ptActive=on&useRealtime=1&std3_inclMOT_0Macro=true&std3_inclMOT_1Macro=true&std3_inclMOT_4Macro=true&std3_inclMOT_5Macro=true&imparedOptionsActive=1&nameInfo_dm=${stopId}&itdLPxx_multiStepDm=2&deleteAssignedStops=1&mode=direct&line=kvv%253A22301%253AE%253AH%253As25&line=kvv%253A22301%253AE%253AR%253As25&line=kvv%253A21012%253AE%253AH%253As25&line=kvv%253A21012%253AE%253AR%253As25&line=kvv%253A22305%253AE%253AH%253As25&line=kvv%253A22305%253AE%253AR%253As25&line=kvv%253A22308%253AE%253AR%253As25&line=kvv%253A22311%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AH%253As25&line=kvv%253A22351%253AE%253AR%253As25&&line=kvv%3A21003%3AE%3AH%3As25&line=kvv%3A21003%3AE%3AR%3As25itdLPxx_snippet=1&itdLPxx_template=dmresults&limit=10`;
const data = await fetch(API_URL, {
method: "GET",

34
src/api/weather.ts Normal file
View File

@@ -0,0 +1,34 @@
import { fetchWeatherApi } from "openmeteo";
const params = {
latitude: 49.0094,
longitude: 8.4044,
daily: ["temperature_2m_max", "temperature_2m_min"],
hourly: [
"temperature_2m",
"precipitation",
"rain",
"precipitation_probability",
],
current: [
"temperature_2m",
"precipitation",
"rain",
"showers",
"snowfall",
"relative_humidity_2m",
"apparent_temperature",
"weather_code",
"cloud_cover",
"is_day",
],
timezone: "Europe/Berlin",
timeformat: "unixtime",
};
const url = "https://api.open-meteo.com/v1/forecast";
function fetchWeatherData() {
return fetchWeatherApi(url, params);
}
export default fetchWeatherData;

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,132 @@
import { useEffect, useState } from "react";
import amogus from "/img/amogus.png";
import imposter from "/img/imposter.png";
import style from "./style.module.css";
type Amogus = {
isImposter: boolean;
posX: number;
posY: number;
speedX: number;
speedY: number;
};
const amogusWidth = 70;
const amogusHeight = 70;
const { innerWidth: width, innerHeight: height } = window;
const getImage = (sus: Amogus) => (sus.isImposter ? imposter : amogus);
const makeInitialCrewmates = (): Amogus[] => {
return [
makeCrewmate(true),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
makeCrewmate(false),
];
};
const randNum = (min: number, max: number): number =>
Math.random() * (max - min) + min;
const makeCrewmate = (imposter: boolean): Amogus => ({
isImposter: imposter,
posX: randNum(0, width - amogusWidth),
posY: randNum(0, height - amogusHeight),
speedX: Math.random() > 0.5 ? randNum(4, 10) : randNum(-4, -10),
speedY: Math.random() > 0.5 ? randNum(4, 10) : randNum(-4, -10),
});
const intersect = (c1: Amogus, c2: Amogus): boolean =>
Math.abs(c1.posX - c2.posX) < amogusWidth - 20 &&
Math.abs(c1.posY - c2.posY) < amogusHeight - 20;
const doMove = (crewmates: Amogus[]) =>
crewmates.map((c) => ({
...c,
posX: c.posX + c.speedX,
posY: c.posY + c.speedY,
}));
const doCollisionWalls = (crewmates: Amogus[]) =>
crewmates.map((c) => {
if (c.posX > width - amogusWidth) {
return {
...c,
posX: width - amogusWidth,
speedX: c.speedX * -1,
};
} else if (c.posX < -20) {
return { ...c, posX: -20, speedX: c.speedX * -1 };
} else if (c.posY > height - amogusHeight) {
return {
...c,
posY: height - amogusHeight,
speedY: c.speedY * -1,
};
} else if (c.posY < -20) {
return { ...c, posY: -20, speedY: c.speedY * -1 };
} else return c;
});
// TODO: This is ugly
const doCollisionOthers = (crewmates: Amogus[]) =>
crewmates.map((c) => {
const intersections = crewmates
.filter((o) => o !== c) // don't collide with yourself pls
.filter((o) => intersect(c, o));
if (intersections.some((o) => Math.abs(o.posX - c.posX) < 50)) {
return { ...c, speedX: c.speedX * -1 };
}
if (intersections.some((o) => Math.abs(o.posY - c.posY) < 50)) {
return { ...c, speedY: c.speedY * -1 };
}
return c;
});
const doKills = (crewmates: Amogus[]) => {
const imposters = crewmates.filter((c) => c.isImposter);
const alive = crewmates
.filter((c) => !c.isImposter)
.filter((c) => imposters.every((i) => !intersect(i, c)));
return imposters.concat(alive);
};
const checkReset = (crewmates: Amogus[]) =>
crewmates.every((c) => c.isImposter) ? makeInitialCrewmates() : crewmates;
const renderCrewmate = (crewmate: Amogus, key: number) => (
<div
key={key}
className={style.container}
style={{ top: crewmate.posY, left: crewmate.posX }}
>
<img src={getImage(crewmate)} alt="Amogus" />
</div>
);
export default function Amogus() {
const [crewmates, setCrewmates] = useState(() => makeInitialCrewmates());
useEffect(() => {
const timer = setInterval(() => {
setCrewmates((c) => doMove(c));
setCrewmates((c) => doCollisionWalls(c));
setCrewmates((c) => doCollisionOthers(c));
setCrewmates((c) => doKills(c));
setCrewmates((c) => checkReset(c));
}, 50);
return () => {
clearInterval(timer);
};
}, []);
return <>{crewmates.map((c, index) => renderCrewmate(c, index))}</>;
}

View File

@@ -0,0 +1,13 @@
.container {
z-index: 100;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
img {
width: 70px;
height: 70px;
object-fit: contain;
}
}

View File

@@ -0,0 +1,26 @@
import CardHeader from "@/components/CardHeader/CardHeader";
import style from "./style.module.css";
export default function Card({
icon,
name,
children,
active = false,
header = true,
}: {
icon: string;
name: string;
active?: boolean;
header?: boolean;
children: React.ReactNode;
}) {
return (
<div className={style.card}>
{header ? (
<CardHeader icon={icon} content={name} active={active} />
) : null}
<div className={style.cardContent}>{children}</div>
</div>
);
}

View File

@@ -0,0 +1,16 @@
.card {
display: flex;
flex-direction: column;
justify-content: flex-start;
background-color: #c0c0c0;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
margin: 10px;
}
.cardContent {
display: flex;
height: 100%;
}

View File

@@ -0,0 +1,9 @@
import style from "./style.module.css";
export function CardRow({ children }) {
return <div className={style.cardRow}>{children}</div>;
}
export function CardColumn({ children }) {
return <div className={style.cardColumn}>{children}</div>;
}

View File

@@ -0,0 +1,16 @@
.cardColumn {
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: 30px;
}
.cardRow {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: stretch;
gap: 30px;
}

View File

@@ -0,0 +1,18 @@
import classNames from "classnames";
import style from "./style.module.css";
export default function CardHeader({ icon, content, active = false }) {
return (
<div
className={classNames(style.container, {
[`${style.active}`]: active,
})}
>
<div className={style.title}>
<div className={style.icon}>{icon}</div>
<div className={style.content}>{content}</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,27 @@
.container {
height: 28px;
display: flex;
flex-direction: row;
margin: 2px;
justify-content: space-between;
align-items: center;
color: #c0c0c0;
background-color: #808080;
}
.active {
color: white;
background-color: #000082;
}
.title {
display: flex;
flex-direction: row;
font-weight: bold;
gap: 7px;
padding-left: 5px;
}
.icon {
font-size: 10pt;
}

View File

@@ -0,0 +1,101 @@
import FourTwenty from "@components/FourTwenty/FourTwenty";
import { useEffect, useState } from "react";
import Amogus from "@/components/Amogus/Amogus";
import Card from "@/components/Card/Card";
import {
CardColumn,
CardRow,
} from "@/components/CardContainers/CardContainers";
import Datetime from "@/components/Datetime/Datetime";
import Flatastic from "@/components/Flatastic/Flatastic";
import Footer from "@/components/Footer/Footer";
import Terminal from "@/components/Terminal/Terminal";
import Timetable from "@/components/Timetable/Timetable";
import Weather from "@/components/Weather/Weather";
import style from "./style.module.css";
export default function Dashboard() {
// '/git-hash.html' contains the current git commit hash, check it every 10 seconds and reload if it isn't the same
const [gitHash, setGitHash] = useState("");
useEffect(() => {
const interval = setInterval(async () => {
const response = await fetch("/git-hash.html");
const text = await response.text();
const newHash = text.trim();
console.log("Fetched git hash:", newHash);
if (gitHash === "") {
setGitHash(newHash);
}
if (gitHash !== "" && newHash !== gitHash) {
setGitHash(newHash);
window.location.reload();
}
}, 10000);
return () => clearInterval(interval);
}, [gitHash]);
const schemes = [style.day, style.evening, style.night];
const [schemeIndex, setSchemeIndex] = useState(0);
const scheme = schemes[schemeIndex];
// change background color based on time of day
useEffect(() => {
const timer = setInterval(
() => {
const d = new Date();
const hour = d.getHours();
if (hour >= 7 && hour < 16) {
setSchemeIndex(0);
} else if (hour >= 16 && hour < 23) {
setSchemeIndex(1);
} else {
setSchemeIndex(2);
}
},
20 * 60 * 1000,
);
return () => {
clearInterval(timer);
};
}, []);
return (
<div className={`${style.dashboard} ${scheme}`}>
<div className={style.body}>
<CardColumn>
<Card icon="🚊" name="Timetable">
<Timetable />
</Card>
<CardRow>
<Card icon="🕐" name="Clock">
<Datetime />
</Card>
<Card icon="🌤" name="Weather">
<Weather />
</Card>
<Card icon="🍁" name="420">
<FourTwenty />
</Card>
</CardRow>
<Card icon="🔔" name="Terminal" active={true}>
<Terminal />
</Card>
<Card icon="🧹" name="Flatastic">
<Flatastic />
</Card>
</CardColumn>
</div>
<Amogus />
<Footer />
</div>
);
}

View File

@@ -0,0 +1,29 @@
.dashboard {
display: flex;
flex-direction: column;
height: 100%;
transition: 0.5s;
}
.body {
height: 100%;
padding: 30px;
overflow: scroll;
scrollbar-width: none;
}
/* 7 to 16 */
.day {
background-color: #007c7d;
}
/* 16 to 23 */
.evening {
background-color: #3b5773;
}
/* 23 to 8 */
.night {
background-color: #2a3f55;
}

View File

@@ -0,0 +1,44 @@
import { useEffect, useState } from "react";
import clockImage from "/img/clock.png";
import style from "./style.module.css";
export default function Datetime() {
const locale = "de";
const [today, setDate] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setDate(new Date());
}, 20 * 1000);
return () => {
clearInterval(timer);
};
}, []);
const date = today.toLocaleDateString(locale, {
month: "long",
day: "numeric",
year: "numeric",
});
const hour = today.getHours().toString().padStart(2, "0");
const minute = today.getMinutes().toString().padStart(2, "0");
return (
<div className={style.container}>
<div className={style.icon}>
<img src={clockImage} alt="Clock" />
</div>
<div className={style.textContainer}>
<div className={style.time}>
{hour}
<span className={style.divider}>:</span>
{minute}
</div>
<div className={style.date}>{date}</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,29 @@
.container {
display: flex;
flex-direction: row;
align-items: center;
padding-right: 25px;
}
img {
height: 100px;
scale: 130%;
object-fit: cover;
}
.textContainer {
font-size: 16pt;
font-weight: bold;
display: flex;
flex-direction: column;
}
.divider {
animation: blink 3s step-end infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
}

View File

@@ -58,11 +58,13 @@ export default function DepartureList(props: {
return (
<div className={style.container}>
<h2>{name} Departures</h2>
<div className={style.heading}>
<h2>{name}</h2>
</div>
<div className={style.departureLists}>
{departureTables(left)}
{departureTables(right)}
</div>
{departureTables(left)}
{departureTables(right)}
</div>
</div>
);
}

View File

@@ -1,12 +1,23 @@
.container {
display: flex;
flex-direction: column;
align-items: center;
align-items: stretch;
padding: 0 10px 20px 10px;
margin-bottom: 20px;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
}
.departureLists {
display: flex;
flex-direction: row;
justify-content: space-between;
justify-content: space-around;
width: 100%;
}
.heading {
text-align: left;
padding-left: 30px;
}

View File

@@ -1,37 +1,83 @@
import { useFlatasticStore } from "@/store/flatastic";
import classNames from "classnames";
import { useEffect } from "react";
import { useFlatasticStore } from "@/store/flatastic";
import type { FlatasticChore, FlatasticUser } from "@/types/flatasticChore";
import style from "./style.module.css";
import type { FlatasticChore } from "@/types/flatasticChore";
function choreItem(chore: FlatasticChore, idToNameMap: Record<number, string>) {
let className = "";
let timeLeftInDays = null;
const idToNameMap: Record<number, string> = {
1836104: "Gruber",
1836101: "Darius",
1593610: "Arif",
1860060: "Rishab",
};
export default function Flatastic() {
const fetchChores = useFlatasticStore((state) => state.fetch);
const chores = useFlatasticStore((state) => state.chores);
useEffect(() => {
fetchChores();
const interval = setInterval(() => {
fetchChores();
}, 60000);
return () => clearInterval(interval);
}, [fetchChores]);
if (chore.rotationTime === -1) {
className = "irregular";
} else {
className = chore.timeLeftNext <= 0 ? "due" : "notDue";
timeLeftInDays = (
<span className={style.timeLeft}>
{Math.abs(Math.floor(chore.timeLeftNext / (60 * 60 * 24)))}d
</span>
);
}
return (
<div>
<h1>Flatastic Chores</h1>
<ul>
{chores.map((chore: FlatasticChore) => (
<li key={chore.id} style={{ textAlign: "left" }}>
{idToNameMap[chore.currentUser]}: {chore.title} -
Points: {chore.points}
</li>
))}
<li
key={chore.id}
className={classNames(style.chore, style[className])}
>
<span className={style.userName}>
{`${idToNameMap[chore.currentUser]}`}
</span>
: {chore.title} {timeLeftInDays} {"🪙".repeat(chore.points)}
</li>
);
}
export default function Flatastic() {
const fetchFlatasticData = useFlatasticStore((state) => state.fetch);
const flatasticData = useFlatasticStore((state) => state.flatasticData);
const chores = (flatasticData?.chores as FlatasticChore[]) || [];
const regularChores: FlatasticChore[] = [];
const irregularChores: FlatasticChore[] = [];
chores.forEach((chore) => {
if (chore.rotationTime === -1) {
irregularChores.push(chore);
} else {
regularChores.push(chore);
}
});
regularChores.sort((a, b) => a.lastDoneDate - b.lastDoneDate);
const users = flatasticData?.users;
const idToNameMap: Record<number, string> = {};
users.forEach((user: FlatasticUser) => {
idToNameMap[user.id] = user.firstName;
});
useEffect(() => {
fetchFlatasticData();
const interval = setInterval(() => {
fetchFlatasticData();
}, 60000);
return () => clearInterval(interval);
}, [fetchFlatasticData]);
const regularChoresRender = regularChores.map((chore) => {
return choreItem(chore, idToNameMap);
});
const irregularChoresRender = irregularChores.map((chore) => {
return choreItem(chore, idToNameMap);
});
return (
<div className={style.container}>
<h1>Chores</h1>
<ul className={style.choreList}>
{[...regularChoresRender, ...irregularChoresRender]}
</ul>
</div>
);

View File

@@ -0,0 +1,42 @@
.container {
padding: 1px 100px 30px 100px;
}
.choreList {
list-style-type: none;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
padding: 10px 0;
}
.chore {
padding: 5px 10px;
text-align: left;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
}
.userName {
font-weight: bold;
}
.irregular {
background-color: #aaaaaa;
}
.due {
background-color: #e4877e;
}
.notDue {
background-color: #a6cfa6;
}
.timeLeft {
font-weight: bold;
}

View File

@@ -0,0 +1,36 @@
import weedImage from "/img/weed.png";
import style from "./style.module.css";
export default function Footer() {
return (
<div className={style.container}>
<div className={style.taskbar}>
<div className={style.startButton}>
<img
className={style.startIcon}
src={weedImage}
alt="4:20"
/>
Start
</div>
<div className={style.windows}>
<span className={style.window}>
<span className={style.windowIcon}>🚊</span>Timetable
</span>
<span className={style.window}>
<span className={style.windowIcon}>🕐</span>Clock
</span>
<span className={style.windowActive}>
<span className={style.windowIcon}>🔔</span>Terminal
</span>
<span className={style.window}>
<span className={style.windowIcon}>🧹</span>Flatastic
</span>
<span className={style.window}>
<span className={style.windowIcon}></span>Weather
</span>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,9 @@
const pasta = [
'Ok, so I was playing the hit game Among Us the other day, and when the game started, a red bean-shaped character that appeared to be wearing a spacesuit told me "shh," while having his index finger in front of where his mouth should be. I believe this act made this red bean character extremely suspicious. To understand why this red bean character is suspicious, we first must understand how the game “Among Us” works. The game consists of 10 bean-shaped characters, called crewmates, that are given tasks for them to complete. As these characters do their tasks, they may witness abnormal things that are not supposed to happen, such as the lights turning off on their own, sudden reactor meltdown and other crewmates dying. These acts show that there is an imposter among the crewmates that is sabotaging and is trying to kill everyone. Now why is this important to determine why the red bean is suspicious? Well now we know how the game works, now we must analyze the red beans actions. At the beginning of the game, the red bean tells us “shh” while having his index finger in front of where his mouth should be. This action suggests that the red bean wants us to be quiet, or keep our mouths shut. Now why would the red bean want us to do this? This could be because the red bean wants to limit our communication in order to prevent us from spreading information. What information does the red bean want to prevent from spreading? We can assume that the reason why the red bean wants to prevent us from spreading information, is because he is actually the imposter, and he is planning on committing the crimes mentioned earlier. He does not want others to find out about actions he will cause, therefore he does not want us to communicate with each other. This concludes the reason for why I believe the red bean from the hit game Among Us is suspicious. So if you happen to see a red bean-shaped character wearing a spacesuit, please be careful.',
"「真正的Emo」只有DC的硬核emo和90年代末 的 Screamo 局,而所謂的「中西部 Emo」 不過 是被真正 Emo所影響的另類搖滾罷了。每次聽到 有人說什麼 My Chemical Romance 不是正宗的 Emo,但又覺得 Sunny Day Real Estate 是的時 候,我他媽就覺得有夠智障,因為他們和 My Chemical Romance 其實一樣都是假 Emo(只能 說他們是被emo影響的樂團)。真正的 Emo 應該 聽起來很強烈、甚至帶著一些憤怒的活力!假 Emo則軟弱、自卑,那些廢物把精力和情感錯誤 地注入音樂當中,只能說他們所謂的emo是失敗 的嘗試罷了。一些真正的Emo 團包括Pg 99、 Rites of Spring、Cap'n Jazz(絕對是中西部樂 團圈裡面唯一真正的 Emo 樂團)和Loma Prieta。那些假的 Emo 團像是 American Football My Chemical Romance Mineral... 等。EMO就該屬於硬核,不是獨立曲風、更別說 是流行龐克、另類搖滾、或是他媽的任何其他主 流類型!!!",
'"YoU tOucHEd ThAt BlOcK So yOu HavE tO PuLl tHat OnE Out" Go fuck yourself, that\'s not how the fucking game is played, you dumb, the fuck, asshole. Quoted from the official Jenga rules: "Players may tap a block to find a loose one. Any blocks moved but not played should be replaced, unless doing so would make the tower fall." You\'ve never even fucking read the rules have you, you shithead idiot. What, is the game over in 3 seconds, if you just so happen to touch a load bearing block first? FUCKING NO DUMBASS. Learn to read you illiterate fuck.',
"I can't fucking take it any more. Among Us has singlehandedly ruined my life. The other day my teacher was teaching us Greek Mythology and he mentioned a pegasus and I immediately thought 'Pegasus? more like Mega Sus!!!!' and I've never wanted to kms more. I can't look at a vent without breaking down and fucking crying. I can't eat pasta without thinking 'IMPASTA??? THATS PRETTY SUS!!!!' Skit 4 by Kanye West. The lyrics ruined me. A Mongoose, or the 25th island of greece. The scientific name for pig. I can't fucking take it anymore. Please fucking end my suffering.",
"What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little \"clever\" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.",
];
export default pasta;

View File

@@ -0,0 +1,68 @@
.container {
background-color: #c0c0c0;
height: 30px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 2px;
}
.taskbar {
display: flex;
flex-direction: row;
text-align: left;
}
.startButton {
font-weight: bold;
display: inline-flex;
justify-content: space-around;
align-items: center;
width: 80px;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
margin-right: 10px;
}
.startIcon {
height: 20px;
}
.windows {
display: flex;
flex-direction: row;
align-items: center;
gap: 5px;
}
.window {
height: 25px;
min-width: 150px;
padding-left: 10px;
display: inline-flex;
align-items: center;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
}
.windowIcon {
font-size: 11pt;
margin-right: 5px;
}
.windowActive {
min-width: 150px;
padding-left: 10px;
display: inline-flex;
align-items: center;
border-bottom: 2px solid white;
border-right: 2px solid white;
border-left: 2px solid #828282;
border-top: 2px solid #828282;
}

View File

@@ -0,0 +1,37 @@
import style from "./style.module.css";
// function Timer({ hours, minutes }: { hours: number; minutes: number }) {
// const x = hours > 0 ? `${hours}h ` : "";
// const y = minutes > 0 ? `${minutes % 60}m` : "";
// return (
// <div>
// <p>
// {x}
// {y}
// </p>
// </div>
// );
// }
// function FourTwentyLoading() {}
function FourTwentySmoking() {
return (
<div className={style.container}>
<img
className={style.image}
src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExMjFlYnhzYzJnc3ZzejBnOGZzcHFpNGpxOHNrN2dwcnZ3NmZ2eWJ0dyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5xaOcLRnsWIB0CkfE3u/giphy.gif"
alt="Smoking"
/>
</div>
);
}
export default function FourTwenty() {
return (
<div>
<FourTwentySmoking />
</div>
);
}

View File

@@ -0,0 +1,5 @@
.container img {
all: unset;
object-fit: contain;
width: 200px;
}

View File

@@ -1,9 +1,15 @@
import { useEffect } from "react";
import { useHomeAssistantStore } from "@/store/homeAssistant";
import style from "./style.module.css";
export default function Timetable() {
const fetchHomeAssistantData = useHomeAssistantStore((state) => state.fetch);
const tentTemperature = useHomeAssistantStore((state) => state.tentTemperature);
const fetchHomeAssistantData = useHomeAssistantStore(
(state) => state.fetch,
);
const tentTemperature = useHomeAssistantStore(
(state) => state.tentTemperature,
);
const tentHumidity = useHomeAssistantStore((state) => state.tentHumidity);
useEffect(() => {
@@ -16,9 +22,17 @@ export default function Timetable() {
return (
<div>
<h1>Tent</h1>
<p>Temperature: {tentTemperature}°C</p>
<p>Humidity: {tentHumidity}%</p>
<div className={style.cardContainer}>
<div className={style.card}>
<h4>Temperature</h4>
<p>{tentTemperature}°C</p>
</div>
<div className={style.card}>
<h4>Humidity</h4>
<p>{tentHumidity}%</p>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,21 @@
.cardContainer {
padding-top: 20px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: 20px;
}
.card {
height: 150px;
width: 150px;
display: flex;
flex-direction: column;
align-items: stretch;
text-align: center;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
}

View File

@@ -0,0 +1,91 @@
import { useEffect, useState } from "react";
import { useHomeAssistantStore } from "@/store/homeAssistant";
import pasta from "./pasta.ts";
import style from "./style.module.css";
export default function Terminal() {
const [index, setIndex] = useState(0);
// random shitpost every minute
useEffect(() => {
const timer = setInterval(() => {
setIndex(Math.floor(Math.random() * pasta.length));
}, 60 * 1000);
return () => {
clearInterval(timer);
};
}, []);
const text = pasta[index];
const fetchHomeAssistantData = useHomeAssistantStore(
(state) => state.fetch,
);
const tentTemperature = useHomeAssistantStore(
(state) => state.tentTemperature,
);
const tentHumidity = useHomeAssistantStore((state) => state.tentHumidity);
useEffect(() => {
fetchHomeAssistantData();
const interval = setInterval(() => {
fetchHomeAssistantData();
}, 60000);
return () => clearInterval(interval);
}, [fetchHomeAssistantData]);
return (
<div className={style.container}>
<div className={style.input}>
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>{" "}
tentfetch
</div>
<div className={style.fetch}>
<span>
<pre>
{" -///:. "}
<span className={style.username}>tent</span>@
<span className={style.hostname}>home</span>
</pre>
</span>
<span>
<pre>
{" "}smhhhhmh\`{" "}os{" "}Arch Linux
</pre>
</span>
<span>
<pre>
{" "}:N{" "}Ns{" "}temp{" "}
<span className={style.temp}>{tentTemperature}°C</span>
</pre>
</span>
<span>
<pre>
{" "}hNNmmmmNNN{" "}humidity{" "}
<span className={style.humidity}>{tentHumidity}%</span>
</pre>
</span>
<span>
<pre>
{" "}NNssussNNN{" "}plants{" "}
<span className={style.plants}>bau mal 1 du hs</span>
</pre>
</span>
<span>
<pre>
{" "}sNn:{" "}sNNo
</pre>
</span>
</div>
<div className={style.input}>
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>{" "}
cat msg.txt
</div>
<div className={style.msg}>{text}</div>
<div className={style.input}>
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>
{" █"}
</div>
</div>
);
}

View File

@@ -0,0 +1,9 @@
const pasta = [
'Ok, so I was playing the hit game Among Us the other day, and when the game started, a red bean-shaped character that appeared to be wearing a spacesuit told me "shh," while having his index finger in front of where his mouth should be. I believe this act made this red bean character extremely suspicious. To understand why this red bean character is suspicious, we first must understand how the game “Among Us” works. The game consists of 10 bean-shaped characters, called crewmates, that are given tasks for them to complete. As these characters do their tasks, they may witness abnormal things that are not supposed to happen, such as the lights turning off on their own, sudden reactor meltdown and other crewmates dying. These acts show that there is an imposter among the crewmates that is sabotaging and is trying to kill everyone. Now why is this important to determine why the red bean is suspicious? Well now we know how the game works, now we must analyze the red beans actions. At the beginning of the game, the red bean tells us “shh” while having his index finger in front of where his mouth should be. This action suggests that the red bean wants us to be quiet, or keep our mouths shut. Now why would the red bean want us to do this? This could be because the red bean wants to limit our communication in order to prevent us from spreading information. What information does the red bean want to prevent from spreading? We can assume that the reason why the red bean wants to prevent us from spreading information, is because he is actually the imposter, and he is planning on committing the crimes mentioned earlier. He does not want others to find out about actions he will cause, therefore he does not want us to communicate with each other. This concludes the reason for why I believe the red bean from the hit game Among Us is suspicious. So if you happen to see a red bean-shaped character wearing a spacesuit, please be careful.',
"「真正的Emo」只有DC的硬核emo和90年代末 的 Screamo 局,而所謂的「中西部 Emo」 不過 是被真正 Emo所影響的另類搖滾罷了。每次聽到 有人說什麼 My Chemical Romance 不是正宗的 Emo,但又覺得 Sunny Day Real Estate 是的時 候,我他媽就覺得有夠智障,因為他們和 My Chemical Romance 其實一樣都是假 Emo(只能 說他們是被emo影響的樂團)。真正的 Emo 應該 聽起來很強烈、甚至帶著一些憤怒的活力!假 Emo則軟弱、自卑,那些廢物把精力和情感錯誤 地注入音樂當中,只能說他們所謂的emo是失敗 的嘗試罷了。一些真正的Emo 團包括Pg 99、 Rites of Spring、Cap'n Jazz(絕對是中西部樂 團圈裡面唯一真正的 Emo 樂團)和Loma Prieta。那些假的 Emo 團像是 American Football My Chemical Romance Mineral... 等。EMO就該屬於硬核,不是獨立曲風、更別說 是流行龐克、另類搖滾、或是他媽的任何其他主 流類型!!!",
'"YoU tOucHEd ThAt BlOcK So yOu HavE tO PuLl tHat OnE Out" Go fuck yourself, that\'s not how the fucking game is played, you dumb, the fuck, asshole. Quoted from the official Jenga rules: "Players may tap a block to find a loose one. Any blocks moved but not played should be replaced, unless doing so would make the tower fall." You\'ve never even fucking read the rules have you, you shithead idiot. What, is the game over in 3 seconds, if you just so happen to touch a load bearing block first? FUCKING NO DUMBASS. Learn to read you illiterate fuck.',
"I can't fucking take it any more. Among Us has singlehandedly ruined my life. The other day my teacher was teaching us Greek Mythology and he mentioned a pegasus and I immediately thought 'Pegasus? more like Mega Sus!!!!' and I've never wanted to kms more. I can't look at a vent without breaking down and fucking crying. I can't eat pasta without thinking 'IMPASTA??? THATS PRETTY SUS!!!!' Skit 4 by Kanye West. The lyrics ruined me. A Mongoose, or the 25th island of greece. The scientific name for pig. I can't fucking take it anymore. Please fucking end my suffering.",
"What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little \"clever\" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.",
];
export default pasta;

View File

@@ -0,0 +1,47 @@
.container {
display: flex;
flex-direction: column;
font-family: monospace;
font-size: 10pt;
background-color: black;
color: white;
width: 100%;
height: 290px;
overflow: hidden;
}
.fetch {
display: flex;
flex-direction: column;
padding-bottom: 10px;
}
.prompt {
color: lightgreen;
}
.username {
color: violet;
}
.hostname {
color: skyblue;
}
.temp {
color: pink;
font-weight: bold;
}
.humidity {
color: skyblue;
font-weight: bold;
}
.plants {
color: lightgreen;
}
pre {
margin: 0;
}

View File

@@ -2,6 +2,8 @@ import { useEffect } from "react";
import DepartureList from "@/components/DepartureList/DepartureList";
import { useKVVStore } from "@/store/kvv";
import style from "./style.module.css";
export default function Timetable() {
const fetchTimetable = useKVVStore((state) => state.fetch);
const pStreet = useKVVStore((state) => state.pStreet);
@@ -16,10 +18,16 @@ export default function Timetable() {
}, [fetchTimetable]);
return (
<div>
<h1>Timetable</h1>
<DepartureList departures={pStreet.departureList} name="P-Street" />
<DepartureList departures={hStreet.departureList} name="H-Street" />
<div className={style.container}>
<h1>Departures</h1>
<DepartureList
departures={pStreet.departureList}
name="Philippstraße"
/>
<DepartureList
departures={hStreet.departureList}
name="Händelstraße"
/>
</div>
);
}

View File

@@ -0,0 +1,4 @@
.container {
padding: 1px 100px 30px 100px;
width: 100%;
}

View File

@@ -10,12 +10,32 @@ export default function TimetableRow({
const hour = String(departure.dateTime.hour).padStart(2, "0");
const minute = String(departure.dateTime.minute).padStart(2, "0");
const dateTimeString = `${hour}:${minute}`;
const lineNumber = departure.servingLine.number;
return (
<tr className={styles.timetableRow}>
<td>{dateTimeString}</td>
<td>{departure.servingLine.number}</td>
<td>({departure.servingLine.direction})</td>
<td className={styles.departureTime}>{dateTimeString}</td>
<td
className={`${lineNumberToStyle(lineNumber)} ${styles.lineNumber}`}
>
{lineNumber}
</td>
<td>{departure.servingLine.direction}</td>
</tr>
);
}
const lineNumberToStyle = (number) => {
switch (number) {
case "S2":
return styles.S2;
case "S5":
case "S51":
return styles.S5;
case "S1":
case "S11":
return styles.S1;
default:
return styles.lineNumberDefault;
}
};

View File

@@ -1,3 +1,31 @@
td {
padding: 4px 7px;
}
.timetableRow {
text-align: left;
}
.departureTime {
font-weight: 600;
}
.lineNumber {
text-align: center;
}
.S2 {
background-color: rgba(200, 100, 200, 0.2);
}
.S5 {
background-color: rgba(230, 20, 20, 0.2);
}
.S1 {
background-color: rgba(20, 180, 90, 0.2);
}
.lineNumberDefault {
background-color: rgba(100, 100, 100, 0.2);
}

View File

@@ -0,0 +1,41 @@
import { useEffect } from "react";
import { useWeatherStore } from "@/store/weather";
import styles from "./style.module.css";
export default function Weather() {
const weatherData = useWeatherStore((state) => state.weatherData);
const fetchWeatherData = useWeatherStore((state) => state.fetchWeatherData);
useEffect(() => {
fetchWeatherData();
const interval = setInterval(() => {
fetchWeatherData();
}, 10 * 60000);
return () => clearInterval(interval);
}, [fetchWeatherData]);
if (!weatherData.current) {
return <div>Loading...</div>;
}
return (
<div className={styles.weatherContainer}>
<div className={styles.currentTemperature}>
<img
src={weatherData.current.icon}
alt={weatherData.current.weather_description}
/>
<span>{weatherData.current.temperature_2m.toFixed(1)}°C</span>
</div>
<div className={styles.dailyTemperatures}>
<span className={styles.minTemperature}>
{weatherData.daily.temperature_2m_min[0].toFixed(1)}°C
</span>
<span className={styles.maxTemperature}>
{weatherData.daily.temperature_2m_max[0].toFixed(1)}°C
</span>
</div>
</div>
);
}

View File

@@ -0,0 +1,30 @@
.weatherContainer {
display: flex;
flex-direction: row;
width: 100%;
padding: 3px;
padding-right: 15px;
}
.currentTemperature {
display: flex;
align-items: center;
font-size: 2rem;
font-weight: bold;
padding-right: 5px;
}
.dailyTemperatures {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-temperature {
color: blue;
}
.max-temperature {
color: red;
}

View File

@@ -1,16 +1,20 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
font-family:
Noto Sans Condensed,
sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
color: #213547;
background-color: #ffffff;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scrollbar-width: none;
}
a {
@@ -18,9 +22,6 @@ a {
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
@@ -42,7 +43,7 @@ button {
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
background-color: #f9f9f9;
cursor: pointer;
transition: border-color 0.25s;
}
@@ -53,16 +54,3 @@ button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@@ -1,12 +1,23 @@
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import Flatastic from "@/api/flatastic";
import type { FlatasticChore } from "@/types/flatasticChore";
import type { FlatasticChore, FlatasticUser } from "@/types/flatasticChore";
// biome-ignore format: deep
function parseInformationData(data): FlatasticUser[] {
return data.flatmates.map((user: { id: string; firstName: string }) => ({
id: user.id as string,
firstName: user.firstName as string,
}));
}
const useFlatasticStore = create(
devtools(
(set) => ({
chores: [],
flatasticData: {
chores: [] as FlatasticChore[],
users: [] as FlatasticUser[],
},
fetch: async () => {
if (!import.meta.env.VITE_FLATTASTIC_API_KEY) {
throw new Error("Flatastic API Key is not set");
@@ -15,9 +26,14 @@ const useFlatasticStore = create(
import.meta.env.VITE_FLATTASTIC_API_KEY,
);
const data = await flatastic.getTaskList();
const dataB = await flatastic.getInformation();
console.log("Flatastic chores fetched:", data);
set({ chores: data as FlatasticChore[] });
set({
flatasticData: {
chores: data as FlatasticChore[],
users: parseInformationData(dataB),
},
});
},
}),
{

View File

@@ -16,11 +16,6 @@ const useKVVStore = create(
const hStreetJson = await hStreetData.json();
const pStreetJson = await pStreetData.json();
console.log("KVV departures fetched:", {
hStreet: hStreetJson,
pStreet: pStreetJson,
});
set({
hStreet: hStreetJson as DepartureType[],
pStreet: pStreetJson as DepartureType[],

384
src/store/weather.ts Normal file
View File

@@ -0,0 +1,384 @@
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import fetchWeatherData from "@/api/weather";
const iconNumberToPng = {
"0": {
day: {
description: "Sunny",
image: "https://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Clear",
image: "https://openweathermap.org/img/wn/01n@2x.png",
},
},
"1": {
day: {
description: "Mainly Sunny",
image: "https://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Mainly Clear",
image: "https://openweathermap.org/img/wn/01n@2x.png",
},
},
"2": {
day: {
description: "Partly Cloudy",
image: "https://openweathermap.org/img/wn/02d@2x.png",
},
night: {
description: "Partly Cloudy",
image: "https://openweathermap.org/img/wn/02n@2x.png",
},
},
"3": {
day: {
description: "Cloudy",
image: "https://openweathermap.org/img/wn/03d@2x.png",
},
night: {
description: "Cloudy",
image: "https://openweathermap.org/img/wn/03n@2x.png",
},
},
"45": {
day: {
description: "Foggy",
image: "https://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Foggy",
image: "https://openweathermap.org/img/wn/50n@2x.png",
},
},
"48": {
day: {
description: "Rime Fog",
image: "https://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Rime Fog",
image: "https://openweathermap.org/img/wn/50n@2x.png",
},
},
"51": {
day: {
description: "Light Drizzle",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Drizzle",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"53": {
day: {
description: "Drizzle",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Drizzle",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"55": {
day: {
description: "Heavy Drizzle",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Drizzle",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"56": {
day: {
description: "Light Freezing Drizzle",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Freezing Drizzle",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"57": {
day: {
description: "Freezing Drizzle",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Freezing Drizzle",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"61": {
day: {
description: "Light Rain",
image: "https://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Rain",
image: "https://openweathermap.org/img/wn/10n@2x.png",
},
},
"63": {
day: {
description: "Rain",
image: "https://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Rain",
image: "https://openweathermap.org/img/wn/10n@2x.png",
},
},
"65": {
day: {
description: "Heavy Rain",
image: "https://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Heavy Rain",
image: "https://openweathermap.org/img/wn/10n@2x.png",
},
},
"66": {
day: {
description: "Light Freezing Rain",
image: "https://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Freezing Rain",
image: "https://openweathermap.org/img/wn/10n@2x.png",
},
},
"67": {
day: {
description: "Freezing Rain",
image: "https://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Freezing Rain",
image: "https://openweathermap.org/img/wn/10n@2x.png",
},
},
"71": {
day: {
description: "Light Snow",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"73": {
day: {
description: "Snow",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"75": {
day: {
description: "Heavy Snow",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Heavy Snow",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"77": {
day: {
description: "Snow Grains",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Grains",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"80": {
day: {
description: "Light Showers",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Showers",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"81": {
day: {
description: "Showers",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Showers",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"82": {
day: {
description: "Heavy Showers",
image: "https://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Showers",
image: "https://openweathermap.org/img/wn/09n@2x.png",
},
},
"85": {
day: {
description: "Light Snow Showers",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow Showers",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"86": {
day: {
description: "Snow Showers",
image: "https://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Showers",
image: "https://openweathermap.org/img/wn/13n@2x.png",
},
},
"95": {
day: {
description: "Thunderstorm",
image: "https://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm",
image: "https://openweathermap.org/img/wn/11n@2x.png",
},
},
"96": {
day: {
description: "Light Thunderstorms With Hail",
image: "https://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Light Thunderstorms With Hail",
image: "https://openweathermap.org/img/wn/11n@2x.png",
},
},
"99": {
day: {
description: "Thunderstorm With Hail",
image: "https://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm With Hail",
image: "https://openweathermap.org/img/wn/11n@2x.png",
},
},
};
const useWeatherStore = create(
devtools(
(set) => ({
weatherData: {},
fetchWeatherData: async () => {
const data = await fetchWeatherData();
const response = data[0];
if (response === null) {
console.error("Failed to fetch weather data");
return;
}
const utcOffsetSeconds = response.utcOffsetSeconds();
const current = response.current();
const hourly = response.hourly();
const daily = response.daily();
if (!current || !hourly || !daily) {
console.error("Failed to fetch weather data");
return;
}
const weatherData = {
current: {
time: current.time(),
temperature_2m: current.variables(0)?.value(),
precipitation: current.variables(1)?.value(),
rain: current.variables(2)?.value(),
showers: current.variables(3)?.value(),
snowfall: current.variables(4)?.value(),
relative_humidity_2m: current.variables(5)?.value(),
apparent_temperature: current.variables(6)?.value(),
weather_code: current.variables(7)?.value(),
cloud_cover: current.variables(8)?.value(),
is_day: current.variables(9)?.value(),
},
hourly: {
time: [
...Array(
(Number(hourly.timeEnd()) -
Number(hourly.time())) /
hourly.interval(),
),
].map(
(_, i) =>
new Date(
(Number(hourly.time()) +
i * hourly.interval() +
utcOffsetSeconds) *
1000,
),
),
temperature_2m: hourly.variables(0)?.valuesArray(),
precipitation: hourly.variables(1)?.valuesArray(),
rain: hourly.variables(2)?.valuesArray(),
precipitation_probability: hourly
.variables(3)
?.valuesArray(),
},
daily: {
time: [
...Array(
(Number(daily.timeEnd()) -
Number(daily.time())) /
daily.interval(),
),
].map(
(_, i) =>
new Date(
(Number(daily.time()) +
i * daily.interval() +
utcOffsetSeconds) *
1000,
),
),
temperature_2m_max: daily.variables(0)?.valuesArray(),
temperature_2m_min: daily.variables(1)?.valuesArray(),
},
};
// const isDay = weatherData.current.is_day === 1;
const weatherCode = weatherData.current.weather_code;
const url = iconNumberToPng[weatherCode].day.image;
weatherData.current = { ...weatherData.current, icon: url };
set({ weatherData });
},
}),
{
name: "weather-store",
},
),
);
export { useWeatherStore };

View File

@@ -1,3 +1,13 @@
interface Flatastic {
users: Array<FlatasticUser>;
chores: Array<FlatasticChore>;
}
interface FlatasticUser {
id: number;
firstName: string;
}
interface FlatasticChore {
id: number;
title: string;
@@ -6,8 +16,8 @@ interface FlatasticChore {
points: number;
rotationTime: number;
currentUser: number;
lastDoneDate: string;
lastDoneDate: number;
timeLeftNext: number;
}
export type { FlatasticChore };
export type { Flatastic, FlatasticChore, FlatasticUser };

View File

@@ -1,10 +1,10 @@
import path from "node:path";
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";
import mkcert from "vite-plugin-mkcert";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
plugins: [react(), mkcert()],
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
@@ -16,14 +16,4 @@ export default defineConfig({
"@slices": path.resolve(__dirname, "src/store/slices"),
},
},
server: {
proxy: {
"/api": {
target: "https://home.rivercry.com",
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, "/api"),
},
},
},
});