73 Commits

Author SHA1 Message Date
f6e8983879 Enhance Amogus 2025-08-31 21:05:53 +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
48 changed files with 1079 additions and 189 deletions

View File

@@ -8,20 +8,8 @@ on:
workflow_dispatch:
jobs:
lint:
runs-on: ubuntu-latest
container:
image: oven/bun
steps:
- uses: actions/checkout@v4
- name: Install Biome
run: bun install -g biome
- name: Biome CI
run: biome ci
build:
runs-on: ubuntu-latest
needs: lint
container:
image: oven/bun
steps:
@@ -30,12 +18,38 @@ jobs:
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
build-and-push-docker:
needs: [build]
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:
@@ -46,7 +60,6 @@ jobs:
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:
@@ -56,8 +69,12 @@ jobs:
password: ${{ secrets.GARRISON_DOCKER_PASSWORD }}
script: |
cd monitor-im-flur
echo "Deploying Docker container..."
export HYPRLAND_INSTANCE_SIGNATURE=$(hyprctl instances -j | jq '.[0].instance' | tr -d "'\"")
hyprctl dispatch exec 'pkill firefox'
hyprctl dispatch exec 'firefox -kiosk localhost:9123'
git clean -dfx
git reset --hard HEAD
git pull
docker-compose pull
docker-compose stop || true
docker-compose rm || true
docker-compose up -d
docker-compose down
docker-compose up -d

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;"]

View File

@@ -5,7 +5,8 @@
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false
"ignoreUnknown": false,
"includes": ["**", "!**/dist"]
},
"formatter": {
"enabled": true,

View File

@@ -7,7 +7,9 @@
"@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",
@@ -35,6 +37,7 @@
"typescript": "~5.8.3",
"typescript-eslint": "^8.35.1",
"vite": "^7.0.4",
"vite-plugin-mkcert": "^1.17.8",
},
},
},
@@ -141,6 +144,8 @@
"@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.20.1", "", { "dependencies": { "flatbuffers": "^25.2.10" } }, "sha512-o5tw3+N617Ms8nDm649PWwWt6PDz8NHWBLjOOFB8bx/EJpvsvKEeHMMoapxQ71bjHzQM+4h39eCe6/nM+nBuwg=="],
"@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=="],
@@ -289,10 +294,14 @@
"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=="],
"axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
@@ -311,10 +320,14 @@
"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=="],
@@ -339,6 +352,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=="],
@@ -425,10 +440,16 @@
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatbuffers": ["flatbuffers@25.2.10", "", {}, "sha512-7JlN9ZvLDG1McO3kbX0k4v+SUAg48L1rIwEvN6ZQl/eCtgJz9UylTMzE9wrmYrcorgxm3CX/3T/w5VAub99UUw=="],
"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.4", "", { "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-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@@ -569,6 +590,10 @@
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"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=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
@@ -595,6 +620,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.0", "", { "dependencies": { "@openmeteo/sdk": "^1.19.0", "flatbuffers": "^25.2.10" } }, "sha512-YinFo02TM4wXdm9o2FBAO2u1ka3drNdnFsGNskiO8aCWvZa6nljh3ioH79ipwPdFhCrIiq/LCfpjDGXqH2RBFw=="],
"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=="],
@@ -627,6 +654,8 @@
"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=="],
@@ -749,6 +778,8 @@
"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-plugin-mkcert": ["vite-plugin-mkcert@1.17.8", "", { "dependencies": { "axios": "^1.8.3", "debug": "^4.4.0", "picocolors": "^1.1.1" }, "peerDependencies": { "vite": ">=3" } }, "sha512-S+4tNEyGqdZQ3RLAG54ETeO2qyURHWrVjUWKYikLAbmhh/iJ+36gDEja4OWwFyXNuvyXcZwNt5TZZR9itPeG5Q=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],

View File

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

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,7 +13,9 @@
"@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",
@@ -40,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

@@ -1 +0,0 @@
#!/bin/bash

View File

@@ -0,0 +1,11 @@
#!/bin/sh
echo "<!DOCTYPE html>
<html>
<head>
<title>Git Hash</title>
</head>
<body>
<pre>GITHUB_SHA = '$GITHUB_SHA';</pre>
</body>
</html>" > dist/git-hash.html

BIN
public/img/amogus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

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

View File

Before

Width:  |  Height:  |  Size: 58 KiB

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,9 +1,8 @@
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkMjQ1OTg0YjliYzE0OTNjYTdmZDJmNTA3ODgzN2U1YSIsImlhdCI6MTc1MzQwMjAzNiwiZXhwIjoyMDY4NzYyMDM2fQ.fnLSFKPdk8lkAEB-4ekdGUJ1PSCBxcAyasQF1PyrD3k";
"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: {
@@ -16,7 +15,7 @@ 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: {

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,101 @@
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 = {
key: string;
isImposter: boolean;
posX: number;
posY: number;
speedX: number;
speedY: number;
};
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),
];
};
const randNum: number = (min: number, max: number) =>
Math.random() * (max - min) + min;
const makeCrewmate: Amogus = (imposter: boolean) => ({
isImposter: imposter,
posX: randNum(0, width - 90),
posY: randNum(0, height - 120),
speedX: Math.random() > 0.5 ? randNum(5, 15) : randNum(-5, -15),
speedY: Math.random() > 0.5 ? randNum(5, 15) : randNum(-5, -15),
});
const intersect: Bool = (c1: Crewmate, c2: Crewmate) =>
Math.abs(c1.posX - c2.posX) < 80 && Math.abs(c1.posY - c2.posY) < 90;
const doMove = (crewmates: Amogus[]) =>
crewmates.map((c) => ({
...c,
posX: c.posX + c.speedX,
posY: c.posY + c.speedY,
}));
const doCollision = (crewmates: Amogus[]) =>
crewmates.map((c) => {
if (c.posX > width - 90) {
return { ...c, posX: width - 90, speedX: c.speedX * -1 };
} else if (c.posX < 0) {
return { ...c, posX: 0, speedX: c.speedX * -1 };
} else if (c.posY > height - 120) {
return { ...c, posY: height - 120, speedY: c.speedY * -1 };
} else if (c.posY < 0) {
return { ...c, posY: 0, speedY: c.speedY * -1 };
} else 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) => doCollision(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,4 @@
.container {
z-index: 100;
position: absolute;
}

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

@@ -1,47 +1,88 @@
import FourTwenty from "@components/FourTwenty/FourTwenty";
import classNames from "classnames";
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() {
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}>
<div className={style.cardWrapper}>
<div className={style.card}>
<div className={style.cardHeaderInactive}>🚊 Timetable</div>
<div className={style.cardContent}>
<div className={`${style.dashboard} ${scheme}`}>
<Amogus />
<div className={style.body}>
<CardColumn>
<Card icon="🚊" name="Timetable">
<Timetable />
</div>
</div>
</Card>
<div className={style.clock}>
<div className={style.card}>
<div className={style.cardHeaderInactive}>🕐 Clock</div>
<Datetime />
</div>
</div>
<CardRow>
<Card icon="🕐" name="Clock">
<Datetime />
</Card>
<div className={style.card}>
<div className={style.terminal}>
<div className={style.cardHeader}>🔔 Terminal</div>
<Card icon="🌤" name="Weather">
<Weather />
</Card>
<div
className={classNames(
style.bouncingWindow,
style.hidden,
)}
>
<Card icon="🍁" name="420">
<FourTwenty />
</Card>
</div>
</CardRow>
<Card icon="🔔" name="Terminal" active={true}>
<Terminal />
</div>
</div>
</Card>
<div className={style.card}>
<div className={style.cardHeaderInactive}>🧹 Flatastic</div>
<div className={style.cardContent}>
<Card icon="🧹" name="Flatastic">
<Flatastic />
</div>
</div>
</Card>
</CardColumn>
</div>
<div className={style.footer}>
<Footer />
</div>
<Footer />
</div>
);
}

View File

@@ -2,54 +2,53 @@
display: flex;
flex-direction: column;
height: 100%;
transition: 0.5s;
}
.body {
height: 100%;
padding: 30px;
overflow: scroll;
}
/* 7 to 16 */
.day {
background-color: #007c7d;
}
.cardWrapper {
margin: 30px;
height: 100%;
gap: 30px;
flex-direction: column;
display: flex;
justify-content: flex-start;
/* 16 to 23 */
.evening {
background-color: #3b5773;
}
.card {
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;
/* 23 to 8 */
.night {
background-color: #2a3f55;
}
.cardContent {
padding: 1px 100px 30px 100px;
.amogus {
z-index: 100;
position: absolute;
scale: 60%;
animation:
x 10s linear infinite alternate,
y 7s linear infinite alternate;
}
.cardHeader {
height: 30px;
color: white;
background-color: #000082;
text-align: left;
padding-left: 5px;
font-weight: bold;
@keyframes x {
from {
left: 0;
}
to {
left: calc(100vw - 70px);
}
}
.cardHeaderInactive {
height: 30px;
color: #c0c0c0;
background-color: #808080;
text-align: left;
padding-left: 5px;
font-weight: bold;
}
.clock {
width: 45%;
}
.footer {
background-color: #c0c0c0;
@keyframes y {
from {
top: 0;
}
to {
top: calc(100vh - 90px);
}
}

View File

@@ -1,4 +1,7 @@
import { useEffect, useState } from "react";
import clockImage from "/img/clock.png";
import style from "./style.module.css";
export default function Datetime() {
@@ -26,7 +29,7 @@ export default function Datetime() {
return (
<div className={style.container}>
<div className={style.icon}>
<img src="src/assets/clock.png" alt="Clock" />
<img src={clockImage} alt="Clock" />
</div>
<div className={style.textContainer}>
<div className={style.time}>

View File

@@ -19,11 +19,11 @@ img {
}
.divider {
animation: blink 3s step-end infinite;
animation: blink 3s step-end infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
opacity: 0;
}
}

View File

@@ -9,10 +9,12 @@ export default function Flatastic() {
const fetchFlatasticData = useFlatasticStore((state) => state.fetch);
const flatasticData = useFlatasticStore((state) => state.flatasticData);
const chores = (flatasticData?.chores as FlatasticChore[]) || [];
chores.sort(
(a, b) =>
a.timeLeftNext - b.timeLeftNext && b.rotationTime - a.rotationTime,
);
const users = flatasticData?.users;
const idToNameMap: Record<number, string> = {};
users.forEach((user: FlatasticUser) => {
@@ -35,11 +37,11 @@ export default function Flatastic() {
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>;
timeLeftInDays = (
<span className={style.timeLeft}>
{Math.abs(Math.floor(chore.timeLeftNext / (60 * 60 * 24)))}d
</span>
);
}
return (
@@ -56,7 +58,7 @@ export default function Flatastic() {
});
return (
<div>
<div className={style.container}>
<h1>Chores</h1>
<ul className={style.choreList}>{choresRender}</ul>
</div>

View File

@@ -1,3 +1,7 @@
.container {
padding: 1px 100px 30px 100px;
}
.choreList {
list-style-type: none;
display: flex;

View File

@@ -1,7 +1,4 @@
import { useEffect, useState } from "react";
import Marquee from "react-fast-marquee";
import pasta from "./pasta.ts";
import weedImage from "/img/weed.png";
import style from "./style.module.css";
export default function Footer() {
@@ -11,17 +8,27 @@ export default function Footer() {
<div className={style.startButton}>
<img
className={style.startIcon}
src="src/assets/weed.png"
src={weedImage}
alt="4:20"
/>
Start
</div>
<span className={style.divider}></span>
<div className={style.windows}>
<span className={style.window}>🚊 Timetable</span>
<span className={style.window}>🕐 Clock</span>
<span className={style.windowActive}>🔔 Terminal</span>
<span className={style.window}>🧹 Flatastic</span>
<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

@@ -1,52 +1,46 @@
.container {
height: 35px;
background-color: #c0c0c0;
height: 30px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 10px;
margin: 2px;
padding: 2px;
}
.taskbar {
font-weight: bold;
display: flex;
flex-direction: row;
text-align: left;
}
.startButton {
font-weight: bold;
display: inline-flex;
justify-content: space-around;
align-items: center;
width: 100px;
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: 30px;
}
.divider {
margin: auto 8px;
width: 4px;
height: 25px;
border-top: 2px solid white;
border-left: 2px solid white;
border-bottom: 2px solid #828282;
border-right: 2px solid #828282;
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;
@@ -57,6 +51,11 @@
border-right: 2px solid #828282;
}
.windowIcon {
font-size: 11pt;
margin-right: 5px;
}
.windowActive {
min-width: 150px;
padding-left: 10px;

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,8 +1,7 @@
import { useHomeAssistantStore } from "@/store/homeAssistant";
import { useEffect, useState } from "react";
import style from "./style.module.css";
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);
@@ -44,7 +43,7 @@ export default function Terminal() {
<div className={style.fetch}>
<span>
<pre>
{" "}-///:.{" "}
{" -///:. "}
<span className={style.username}>tent</span>@
<span className={style.hostname}>home</span>
</pre>
@@ -84,9 +83,8 @@ export default function Terminal() {
</div>
<div className={style.msg}>{text}</div>
<div className={style.input}>
<span className={style.prompt}>
[sus@home ~/hallway]{"$"}
</span>{" "}
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>
{" █"}
</div>
</div>
);

View File

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

View File

@@ -18,7 +18,7 @@ export default function Timetable() {
}, [fetchTimetable]);
return (
<div className={style.wrapper}>
<div className={style.container}>
<h1>Departures</h1>
<DepartureList
departures={pStreet.departureList}

View File

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

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,5 +1,7 @@
:root {
font-family: Arial, sans-serif;
font-family:
Noto Sans Condensed,
sans-serif;
line-height: 1.5;
font-weight: 400;

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

@@ -0,0 +1,389 @@
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import fetchWeatherData from "@/api/weather";
const iconNumberToPng = {
"0": {
day: {
description: "Sunny",
image: "http://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Clear",
image: "http://openweathermap.org/img/wn/01n@2x.png",
},
},
"1": {
day: {
description: "Mainly Sunny",
image: "http://openweathermap.org/img/wn/01d@2x.png",
},
night: {
description: "Mainly Clear",
image: "http://openweathermap.org/img/wn/01n@2x.png",
},
},
"2": {
day: {
description: "Partly Cloudy",
image: "http://openweathermap.org/img/wn/02d@2x.png",
},
night: {
description: "Partly Cloudy",
image: "http://openweathermap.org/img/wn/02n@2x.png",
},
},
"3": {
day: {
description: "Cloudy",
image: "http://openweathermap.org/img/wn/03d@2x.png",
},
night: {
description: "Cloudy",
image: "http://openweathermap.org/img/wn/03n@2x.png",
},
},
"45": {
day: {
description: "Foggy",
image: "http://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Foggy",
image: "http://openweathermap.org/img/wn/50n@2x.png",
},
},
"48": {
day: {
description: "Rime Fog",
image: "http://openweathermap.org/img/wn/50d@2x.png",
},
night: {
description: "Rime Fog",
image: "http://openweathermap.org/img/wn/50n@2x.png",
},
},
"51": {
day: {
description: "Light Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"53": {
day: {
description: "Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"55": {
day: {
description: "Heavy Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"56": {
day: {
description: "Light Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"57": {
day: {
description: "Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Freezing Drizzle",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"61": {
day: {
description: "Light Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"63": {
day: {
description: "Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"65": {
day: {
description: "Heavy Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Heavy Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"66": {
day: {
description: "Light Freezing Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Light Freezing Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"67": {
day: {
description: "Freezing Rain",
image: "http://openweathermap.org/img/wn/10d@2x.png",
},
night: {
description: "Freezing Rain",
image: "http://openweathermap.org/img/wn/10n@2x.png",
},
},
"71": {
day: {
description: "Light Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"73": {
day: {
description: "Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"75": {
day: {
description: "Heavy Snow",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Heavy Snow",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"77": {
day: {
description: "Snow Grains",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Grains",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"80": {
day: {
description: "Light Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Light Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"81": {
day: {
description: "Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"82": {
day: {
description: "Heavy Showers",
image: "http://openweathermap.org/img/wn/09d@2x.png",
},
night: {
description: "Heavy Showers",
image: "http://openweathermap.org/img/wn/09n@2x.png",
},
},
"85": {
day: {
description: "Light Snow Showers",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Light Snow Showers",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"86": {
day: {
description: "Snow Showers",
image: "http://openweathermap.org/img/wn/13d@2x.png",
},
night: {
description: "Snow Showers",
image: "http://openweathermap.org/img/wn/13n@2x.png",
},
},
"95": {
day: {
description: "Thunderstorm",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
"96": {
day: {
description: "Light Thunderstorms With Hail",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Light Thunderstorms With Hail",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
"99": {
day: {
description: "Thunderstorm With Hail",
image: "http://openweathermap.org/img/wn/11d@2x.png",
},
night: {
description: "Thunderstorm With Hail",
image: "http://openweathermap.org/img/wn/11n@2x.png",
},
},
};
const useWeatherStore = create(
devtools(
(set) => ({
weatherData: {},
fetchWeatherData: async () => {
const data = await fetchWeatherData();
// Process first location. Add a for-loop for multiple locations or weather models
const response = data[0];
if (response === null) {
console.error("Failed to fetch weather data");
return;
}
// Attributes for timezone and location
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;
}
// Note: The order of weather variables in the URL query and the indices below need to match!
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][isDay ? "day" : "night"].image;
weatherData.current = { ...weatherData.current, icon: url };
set({ weatherData });
},
}),
{
name: "weather-store",
},
),
);
export { useWeatherStore };

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"),
},
},
},
});