diff --git a/README.md b/README.md
index 39629d9..f37f6ac 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ First make sure you have the following dependencies installed:
- **Node.js**
- **pnpm**
-Then download all needed packages using
+Then, for each of frontend and backend, download all needed packages using
```sh
pnpm install
```
@@ -28,7 +28,7 @@ node server.js
## 🔧 Configuration
-All settings are located in [config/config.json](config/config.json). For more explainations and possible values, give a look to the documentation (incomming).
+All settings are located in [backend/config/config.json](backend/config/config.json). For more explainations and possible values, give a look to the documentation (incomming).
## 🔗 Documentation
diff --git a/.gitignore b/backend/.gitignore
similarity index 100%
rename from .gitignore
rename to backend/.gitignore
diff --git a/config/config.json b/backend/config/config.json
similarity index 100%
rename from config/config.json
rename to backend/config/config.json
diff --git a/package.json b/backend/package.json
similarity index 95%
rename from package.json
rename to backend/package.json
index 1facd76..dc18e1e 100644
--- a/package.json
+++ b/backend/package.json
@@ -1,5 +1,5 @@
{
- "name": "wf-radio",
+ "name": "wf-radio-backend",
"version": "1.0.0",
"description": "",
"main": "server.js",
diff --git a/pnpm-lock.yaml b/backend/pnpm-lock.yaml
similarity index 100%
rename from pnpm-lock.yaml
rename to backend/pnpm-lock.yaml
diff --git a/server.js b/backend/server.js
similarity index 100%
rename from server.js
rename to backend/server.js
diff --git a/src/controllers/auth.js b/backend/src/controllers/auth.js
similarity index 100%
rename from src/controllers/auth.js
rename to backend/src/controllers/auth.js
diff --git a/src/controllers/index.js b/backend/src/controllers/index.js
similarity index 100%
rename from src/controllers/index.js
rename to backend/src/controllers/index.js
diff --git a/src/controllers/modpacks.js b/backend/src/controllers/modpacks.js
similarity index 100%
rename from src/controllers/modpacks.js
rename to backend/src/controllers/modpacks.js
diff --git a/src/controllers/mods.js b/backend/src/controllers/mods.js
similarity index 100%
rename from src/controllers/mods.js
rename to backend/src/controllers/mods.js
diff --git a/src/controllers/users.js b/backend/src/controllers/users.js
similarity index 100%
rename from src/controllers/users.js
rename to backend/src/controllers/users.js
diff --git a/src/database/index.js b/backend/src/database/index.js
similarity index 100%
rename from src/database/index.js
rename to backend/src/database/index.js
diff --git a/src/database/mysql.js b/backend/src/database/mysql.js
similarity index 100%
rename from src/database/mysql.js
rename to backend/src/database/mysql.js
diff --git a/src/database/sqlite.js b/backend/src/database/sqlite.js
similarity index 100%
rename from src/database/sqlite.js
rename to backend/src/database/sqlite.js
diff --git a/src/middleware/auth.js b/backend/src/middleware/auth.js
similarity index 100%
rename from src/middleware/auth.js
rename to backend/src/middleware/auth.js
diff --git a/src/middleware/errors.js b/backend/src/middleware/errors.js
similarity index 100%
rename from src/middleware/errors.js
rename to backend/src/middleware/errors.js
diff --git a/src/models/index.js b/backend/src/models/index.js
similarity index 100%
rename from src/models/index.js
rename to backend/src/models/index.js
diff --git a/src/models/mod.js b/backend/src/models/mod.js
similarity index 100%
rename from src/models/mod.js
rename to backend/src/models/mod.js
diff --git a/src/models/modpack.js b/backend/src/models/modpack.js
similarity index 100%
rename from src/models/modpack.js
rename to backend/src/models/modpack.js
diff --git a/src/models/user.js b/backend/src/models/user.js
similarity index 100%
rename from src/models/user.js
rename to backend/src/models/user.js
diff --git a/src/routes/index.js b/backend/src/routes/index.js
similarity index 100%
rename from src/routes/index.js
rename to backend/src/routes/index.js
diff --git a/src/routes/list.js b/backend/src/routes/list.js
similarity index 100%
rename from src/routes/list.js
rename to backend/src/routes/list.js
diff --git a/src/routes/login.js b/backend/src/routes/login.js
similarity index 100%
rename from src/routes/login.js
rename to backend/src/routes/login.js
diff --git a/src/routes/modpacks.js b/backend/src/routes/modpacks.js
similarity index 100%
rename from src/routes/modpacks.js
rename to backend/src/routes/modpacks.js
diff --git a/src/routes/mods.js b/backend/src/routes/mods.js
similarity index 100%
rename from src/routes/mods.js
rename to backend/src/routes/mods.js
diff --git a/src/routes/users.js b/backend/src/routes/users.js
similarity index 100%
rename from src/routes/users.js
rename to backend/src/routes/users.js
diff --git a/src/schemas/auth.js b/backend/src/schemas/auth.js
similarity index 100%
rename from src/schemas/auth.js
rename to backend/src/schemas/auth.js
diff --git a/src/schemas/mod.js b/backend/src/schemas/mod.js
similarity index 100%
rename from src/schemas/mod.js
rename to backend/src/schemas/mod.js
diff --git a/src/schemas/modpack.js b/backend/src/schemas/modpack.js
similarity index 100%
rename from src/schemas/modpack.js
rename to backend/src/schemas/modpack.js
diff --git a/src/schemas/user.js b/backend/src/schemas/user.js
similarity index 100%
rename from src/schemas/user.js
rename to backend/src/schemas/user.js
diff --git a/src/services/authService.js b/backend/src/services/authService.js
similarity index 100%
rename from src/services/authService.js
rename to backend/src/services/authService.js
diff --git a/src/services/indexService.js b/backend/src/services/indexService.js
similarity index 100%
rename from src/services/indexService.js
rename to backend/src/services/indexService.js
diff --git a/src/services/modService.js b/backend/src/services/modService.js
similarity index 100%
rename from src/services/modService.js
rename to backend/src/services/modService.js
diff --git a/src/services/modpackService.js b/backend/src/services/modpackService.js
similarity index 100%
rename from src/services/modpackService.js
rename to backend/src/services/modpackService.js
diff --git a/src/services/userService.js b/backend/src/services/userService.js
similarity index 100%
rename from src/services/userService.js
rename to backend/src/services/userService.js
diff --git a/src/utils/appError.js b/backend/src/utils/appError.js
similarity index 100%
rename from src/utils/appError.js
rename to backend/src/utils/appError.js
diff --git a/src/utils/configManager.js b/backend/src/utils/configManager.js
similarity index 100%
rename from src/utils/configManager.js
rename to backend/src/utils/configManager.js
diff --git a/src/utils/convert.js b/backend/src/utils/convert.js
similarity index 100%
rename from src/utils/convert.js
rename to backend/src/utils/convert.js
diff --git a/src/utils/crypto.js b/backend/src/utils/crypto.js
similarity index 100%
rename from src/utils/crypto.js
rename to backend/src/utils/crypto.js
diff --git a/src/utils/sanitize.js b/backend/src/utils/sanitize.js
similarity index 100%
rename from src/utils/sanitize.js
rename to backend/src/utils/sanitize.js
diff --git a/src/utils/validate.js b/backend/src/utils/validate.js
similarity index 100%
rename from src/utils/validate.js
rename to backend/src/utils/validate.js
diff --git a/src/utils/validate_legacy.js b/backend/src/utils/validate_legacy.js
similarity index 100%
rename from src/utils/validate_legacy.js
rename to backend/src/utils/validate_legacy.js
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..ae54c6f
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Preact
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..18b808f
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "wf-radio-frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "preact": "^10.26.5"
+ },
+ "devDependencies": {
+ "@preact/preset-vite": "^2.10.1",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
new file mode 100644
index 0000000..891187e
--- /dev/null
+++ b/frontend/pnpm-lock.yaml
@@ -0,0 +1,1188 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ preact:
+ specifier: ^10.26.5
+ version: 10.26.6
+ devDependencies:
+ '@preact/preset-vite':
+ specifier: ^2.10.1
+ version: 2.10.1(@babel/core@7.27.1)(preact@10.26.6)(vite@6.3.5)
+ vite:
+ specifier: ^6.3.5
+ version: 6.3.5
+
+packages:
+
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.27.2':
+ resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.27.1':
+ resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.27.1':
+ resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-annotate-as-pure@7.27.1':
+ resolution: {integrity: sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.27.1':
+ resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.27.1':
+ resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.27.2':
+ resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-syntax-jsx@7.27.1':
+ resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-development@7.27.1':
+ resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx@7.27.1':
+ resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.27.1':
+ resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.27.1':
+ resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@esbuild/aix-ppc64@0.25.4':
+ resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.4':
+ resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.4':
+ resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.4':
+ resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.4':
+ resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.4':
+ resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.4':
+ resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.4':
+ resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.4':
+ resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.4':
+ resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.4':
+ resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.4':
+ resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.4':
+ resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.4':
+ resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.4':
+ resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.4':
+ resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.4':
+ resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.4':
+ resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.4':
+ resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.4':
+ resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.4':
+ resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.25.4':
+ resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.4':
+ resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.4':
+ resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.4':
+ resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.8':
+ resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+ '@preact/preset-vite@2.10.1':
+ resolution: {integrity: sha512-59lyGBXNfZIr5OOuBUB4/IB8AqF/ULbvYnyItgK/2BJnsGJqaeaJobRVtMp1129obHQuj8oZ/dVxB9inmH8Xig==}
+ peerDependencies:
+ '@babel/core': 7.x
+ vite: 2.x || 3.x || 4.x || 5.x || 6.x
+
+ '@prefresh/babel-plugin@0.5.1':
+ resolution: {integrity: sha512-uG3jGEAysxWoyG3XkYfjYHgaySFrSsaEb4GagLzYaxlydbuREtaX+FTxuIidp241RaLl85XoHg9Ej6E4+V1pcg==}
+
+ '@prefresh/core@1.5.3':
+ resolution: {integrity: sha512-nDzxj0tA1/M6APNAWqaxkZ+3sTdPHESa+gol4+Bw7rMc2btWdkLoNH7j9rGhUb8SThC0Vz0VoXtq+U+9azGLHg==}
+ peerDependencies:
+ preact: ^10.0.0
+
+ '@prefresh/utils@1.2.0':
+ resolution: {integrity: sha512-KtC/fZw+oqtwOLUFM9UtiitB0JsVX0zLKNyRTA332sqREqSALIIQQxdUCS1P3xR/jT1e2e8/5rwH6gdcMLEmsQ==}
+
+ '@prefresh/vite@2.4.7':
+ resolution: {integrity: sha512-zmCEDWSFHl5A7PciXa/fe+OUjoGi4iiCQclpWfpIg7LjxwWrtlUT4DfxDBcQwHfTyipS/XDm8x7WYrkiTW0q+w==}
+ peerDependencies:
+ preact: ^10.4.0
+ vite: '>=2.0.0'
+
+ '@rollup/pluginutils@4.2.1':
+ resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
+ engines: {node: '>= 8.0.0'}
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
+ babel-plugin-transform-hook-names@1.0.2:
+ resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==}
+ peerDependencies:
+ '@babel/core': ^7.12.10
+
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+ browserslist@4.24.5:
+ resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ caniuse-lite@1.0.30001717:
+ resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ css-select@5.1.0:
+ resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+ css-what@6.1.0:
+ resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+ engines: {node: '>= 6'}
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
+ electron-to-chromium@1.5.151:
+ resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ esbuild@0.25.4:
+ resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ fdir@6.4.4:
+ resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ kolorist@1.8.0:
+ resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-html-parser@6.1.13:
+ resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
+
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.2:
+ resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact@10.26.6:
+ resolution: {integrity: sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==}
+
+ rollup@4.40.2:
+ resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ simple-code-frame@1.3.0:
+ resolution: {integrity: sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.7.4:
+ resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
+ engines: {node: '>= 8'}
+
+ stack-trace@1.0.0-pre2:
+ resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==}
+ engines: {node: '>=16'}
+
+ tinyglobby@0.2.13:
+ resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
+ engines: {node: '>=12.0.0'}
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ vite-prerender-plugin@0.5.10:
+ resolution: {integrity: sha512-m4i0G5oc3LPLA02uW2XsFZmYNxZdyryz5Ksi78O9puj/ao5c8dBUW06caGwoM1TmYknTBBUyKhtqajUpoP+z8Q==}
+ peerDependencies:
+ vite: 5.x || 6.x
+
+ vite@6.3.5:
+ resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+snapshots:
+
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.27.2': {}
+
+ '@babel/core@7.27.1':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.1
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1)
+ '@babel/helpers': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.27.1
+ '@babel/types': 7.27.1
+ convert-source-map: 2.0.0
+ debug: 4.4.0
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.27.1':
+ dependencies:
+ '@babel/parser': 7.27.2
+ '@babel/types': 7.27.1
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.1.0
+
+ '@babel/helper-annotate-as-pure@7.27.1':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.27.2
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.24.5
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.27.1
+ '@babel/types': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.27.1':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.1
+
+ '@babel/parser@7.27.2':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.27.1)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-plugin-utils': 7.27.1
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1)
+ '@babel/types': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/types': 7.27.1
+
+ '@babel/traverse@7.27.1':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.1
+ debug: 4.4.0
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.27.1':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@esbuild/aix-ppc64@0.25.4':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/android-arm@0.25.4':
+ optional: true
+
+ '@esbuild/android-x64@0.25.4':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.4':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.4':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.4':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.4':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.4':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.4':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.4':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.4':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.4':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.8':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@preact/preset-vite@2.10.1(@babel/core@7.27.1)(preact@10.26.6)(vite@6.3.5)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.27.1)
+ '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.27.1)
+ '@prefresh/vite': 2.4.7(preact@10.26.6)(vite@6.3.5)
+ '@rollup/pluginutils': 4.2.1
+ babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.27.1)
+ debug: 4.4.0
+ kolorist: 1.8.0
+ vite: 6.3.5
+ vite-prerender-plugin: 0.5.10(vite@6.3.5)
+ transitivePeerDependencies:
+ - preact
+ - supports-color
+
+ '@prefresh/babel-plugin@0.5.1': {}
+
+ '@prefresh/core@1.5.3(preact@10.26.6)':
+ dependencies:
+ preact: 10.26.6
+
+ '@prefresh/utils@1.2.0': {}
+
+ '@prefresh/vite@2.4.7(preact@10.26.6)(vite@6.3.5)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@prefresh/babel-plugin': 0.5.1
+ '@prefresh/core': 1.5.3(preact@10.26.6)
+ '@prefresh/utils': 1.2.0
+ '@rollup/pluginutils': 4.2.1
+ preact: 10.26.6
+ vite: 6.3.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@rollup/pluginutils@4.2.1':
+ dependencies:
+ estree-walker: 2.0.2
+ picomatch: 2.3.1
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ optional: true
+
+ '@types/estree@1.0.7': {}
+
+ babel-plugin-transform-hook-names@1.0.2(@babel/core@7.27.1):
+ dependencies:
+ '@babel/core': 7.27.1
+
+ boolbase@1.0.0: {}
+
+ browserslist@4.24.5:
+ dependencies:
+ caniuse-lite: 1.0.30001717
+ electron-to-chromium: 1.5.151
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.3(browserslist@4.24.5)
+
+ caniuse-lite@1.0.30001717: {}
+
+ convert-source-map@2.0.0: {}
+
+ css-select@5.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.1.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ nth-check: 2.1.1
+
+ css-what@6.1.0: {}
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ electron-to-chromium@1.5.151: {}
+
+ entities@4.5.0: {}
+
+ esbuild@0.25.4:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.4
+ '@esbuild/android-arm': 0.25.4
+ '@esbuild/android-arm64': 0.25.4
+ '@esbuild/android-x64': 0.25.4
+ '@esbuild/darwin-arm64': 0.25.4
+ '@esbuild/darwin-x64': 0.25.4
+ '@esbuild/freebsd-arm64': 0.25.4
+ '@esbuild/freebsd-x64': 0.25.4
+ '@esbuild/linux-arm': 0.25.4
+ '@esbuild/linux-arm64': 0.25.4
+ '@esbuild/linux-ia32': 0.25.4
+ '@esbuild/linux-loong64': 0.25.4
+ '@esbuild/linux-mips64el': 0.25.4
+ '@esbuild/linux-ppc64': 0.25.4
+ '@esbuild/linux-riscv64': 0.25.4
+ '@esbuild/linux-s390x': 0.25.4
+ '@esbuild/linux-x64': 0.25.4
+ '@esbuild/netbsd-arm64': 0.25.4
+ '@esbuild/netbsd-x64': 0.25.4
+ '@esbuild/openbsd-arm64': 0.25.4
+ '@esbuild/openbsd-x64': 0.25.4
+ '@esbuild/sunos-x64': 0.25.4
+ '@esbuild/win32-arm64': 0.25.4
+ '@esbuild/win32-ia32': 0.25.4
+ '@esbuild/win32-x64': 0.25.4
+
+ escalade@3.2.0: {}
+
+ estree-walker@2.0.2: {}
+
+ fdir@6.4.4(picomatch@4.0.2):
+ optionalDependencies:
+ picomatch: 4.0.2
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ globals@11.12.0: {}
+
+ he@1.2.0: {}
+
+ js-tokens@4.0.0: {}
+
+ jsesc@3.1.0: {}
+
+ json5@2.2.3: {}
+
+ kolorist@1.8.0: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ magic-string@0.30.17:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ node-html-parser@6.1.13:
+ dependencies:
+ css-select: 5.1.0
+ he: 1.2.0
+
+ node-releases@2.0.19: {}
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.2: {}
+
+ postcss@8.5.3:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact@10.26.6: {}
+
+ rollup@4.40.2:
+ dependencies:
+ '@types/estree': 1.0.7
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.40.2
+ '@rollup/rollup-android-arm64': 4.40.2
+ '@rollup/rollup-darwin-arm64': 4.40.2
+ '@rollup/rollup-darwin-x64': 4.40.2
+ '@rollup/rollup-freebsd-arm64': 4.40.2
+ '@rollup/rollup-freebsd-x64': 4.40.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.40.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.40.2
+ '@rollup/rollup-linux-arm64-gnu': 4.40.2
+ '@rollup/rollup-linux-arm64-musl': 4.40.2
+ '@rollup/rollup-linux-loongarch64-gnu': 4.40.2
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-musl': 4.40.2
+ '@rollup/rollup-linux-s390x-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-musl': 4.40.2
+ '@rollup/rollup-win32-arm64-msvc': 4.40.2
+ '@rollup/rollup-win32-ia32-msvc': 4.40.2
+ '@rollup/rollup-win32-x64-msvc': 4.40.2
+ fsevents: 2.3.3
+
+ semver@6.3.1: {}
+
+ simple-code-frame@1.3.0:
+ dependencies:
+ kolorist: 1.8.0
+
+ source-map-js@1.2.1: {}
+
+ source-map@0.7.4: {}
+
+ stack-trace@1.0.0-pre2: {}
+
+ tinyglobby@0.2.13:
+ dependencies:
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+
+ update-browserslist-db@1.1.3(browserslist@4.24.5):
+ dependencies:
+ browserslist: 4.24.5
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ vite-prerender-plugin@0.5.10(vite@6.3.5):
+ dependencies:
+ kolorist: 1.8.0
+ magic-string: 0.30.17
+ node-html-parser: 6.1.13
+ simple-code-frame: 1.3.0
+ source-map: 0.7.4
+ stack-trace: 1.0.0-pre2
+ vite: 6.3.5
+
+ vite@6.3.5:
+ dependencies:
+ esbuild: 0.25.4
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.3
+ rollup: 4.40.2
+ tinyglobby: 0.2.13
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ yallist@3.1.1: {}
diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml
new file mode 100644
index 0000000..efc037a
--- /dev/null
+++ b/frontend/pnpm-workspace.yaml
@@ -0,0 +1,2 @@
+onlyBuiltDependencies:
+ - esbuild
diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/frontend/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/app.jsx b/frontend/src/app.jsx
new file mode 100644
index 0000000..9efff17
--- /dev/null
+++ b/frontend/src/app.jsx
@@ -0,0 +1,43 @@
+import { useState } from 'preact/hooks'
+import preactLogo from './assets/preact.svg'
+import viteLogo from '/vite.svg'
+import './styles/app.css'
+
+export function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
+ Vite + Preact
+
+
setCount((count) => count + 1)}>
+ count is {count}
+
+
+ Edit src/app.jsx and save to test HMR
+
+
+
+ Check out{' '}
+
+ create-preact
+
+ , the official Preact + Vite starter
+
+
+ Click on the Vite and Preact logos to learn more
+
+ >
+ )
+}
diff --git a/frontend/src/assets/preact.svg b/frontend/src/assets/preact.svg
new file mode 100644
index 0000000..908f17d
--- /dev/null
+++ b/frontend/src/assets/preact.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
new file mode 100644
index 0000000..008c962
--- /dev/null
+++ b/frontend/src/main.jsx
@@ -0,0 +1,5 @@
+import { render } from 'preact'
+import './styles/index.css'
+import { App } from './app.jsx'
+
+render( , document.getElementById('app'))
diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css
new file mode 100644
index 0000000..088ed3a
--- /dev/null
+++ b/frontend/src/styles/app.css
@@ -0,0 +1,25 @@
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.preact:hover {
+ filter: drop-shadow(0 0 2em #673ab8aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css
new file mode 100644
index 0000000..08a3ac9
--- /dev/null
+++ b/frontend/src/styles/index.css
@@ -0,0 +1,68 @@
+:root {
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+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;
+ }
+}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 0000000..b995c32
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [preact()],
+})