From d1d49ecc498ff65213d503b86de5a5181d89c751 Mon Sep 17 00:00:00 2001 From: Tueem Date: Wed, 24 Jun 2026 11:58:59 +0200 Subject: [PATCH] feat(frontend): add files --- assets.go | 24 +- frontend/.gitignore | 24 + frontend/.oxlintrc.json | 8 + frontend/README.md | 32 + frontend/index.html | 13 + frontend/package-lock.json | 1487 ++++++++++++++++++ frontend/package.json | 27 + frontend/public/favicon.svg | 1 + frontend/public/icons.svg | 24 + frontend/public/logo.png | Bin 0 -> 69362 bytes frontend/src/App.css | 184 +++ frontend/src/App.tsx | 23 + frontend/src/api/index.ts | 101 ++ frontend/src/assets/hero.png | Bin 0 -> 13057 bytes frontend/src/assets/react.svg | 1 + frontend/src/assets/vite.svg | 1 + frontend/src/components/ConfirmDialog.css | 66 + frontend/src/components/ConfirmDialog.tsx | 27 + frontend/src/components/Footer.css | 53 + frontend/src/components/Footer.tsx | 16 + frontend/src/components/Header.css | 64 + frontend/src/components/Header.tsx | 44 + frontend/src/components/LockScreen.css | 36 + frontend/src/components/LockScreen.tsx | 19 + frontend/src/components/SearchableSelect.css | 104 ++ frontend/src/components/SearchableSelect.tsx | 64 + frontend/src/index.css | 116 ++ frontend/src/main.tsx | 10 + frontend/src/pages/admin/Admin.css | 255 +++ frontend/src/pages/admin/index.tsx | 338 ++++ frontend/src/pages/result/Result.css | 45 + frontend/src/pages/result/index.tsx | 82 + frontend/src/pages/voting/Voting.css | 85 + frontend/src/pages/voting/index.tsx | 145 ++ frontend/src/types/index.ts | 13 + frontend/tsconfig.app.json | 25 + frontend/tsconfig.json | 7 + frontend/tsconfig.node.json | 23 + frontend/vite.config.ts | 23 + 39 files changed, 3607 insertions(+), 3 deletions(-) create mode 100644 frontend/.gitignore create mode 100644 frontend/.oxlintrc.json create mode 100644 frontend/README.md create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/public/favicon.svg create mode 100644 frontend/public/icons.svg create mode 100644 frontend/public/logo.png create mode 100644 frontend/src/App.css create mode 100644 frontend/src/App.tsx create mode 100644 frontend/src/api/index.ts create mode 100644 frontend/src/assets/hero.png create mode 100644 frontend/src/assets/react.svg create mode 100644 frontend/src/assets/vite.svg create mode 100644 frontend/src/components/ConfirmDialog.css create mode 100644 frontend/src/components/ConfirmDialog.tsx create mode 100644 frontend/src/components/Footer.css create mode 100644 frontend/src/components/Footer.tsx create mode 100644 frontend/src/components/Header.css create mode 100644 frontend/src/components/Header.tsx create mode 100644 frontend/src/components/LockScreen.css create mode 100644 frontend/src/components/LockScreen.tsx create mode 100644 frontend/src/components/SearchableSelect.css create mode 100644 frontend/src/components/SearchableSelect.tsx create mode 100644 frontend/src/index.css create mode 100644 frontend/src/main.tsx create mode 100644 frontend/src/pages/admin/Admin.css create mode 100644 frontend/src/pages/admin/index.tsx create mode 100644 frontend/src/pages/result/Result.css create mode 100644 frontend/src/pages/result/index.tsx create mode 100644 frontend/src/pages/voting/Voting.css create mode 100644 frontend/src/pages/voting/index.tsx create mode 100644 frontend/src/types/index.ts create mode 100644 frontend/tsconfig.app.json create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/vite.config.ts diff --git a/assets.go b/assets.go index 5e903b9..326b6f2 100644 --- a/assets.go +++ b/assets.go @@ -1,6 +1,24 @@ -package outfitvotingabi26 +package assets -import "embed" +import ( + "embed" + "io/fs" + "net/http" +) -//go:embed frontend +//go:embed frontend/dist/* var frontendFS embed.FS + +func HttpServer() http.Handler { + fs, err := fs.Sub(frontendFS, "frontend/dist") + if err != nil { + panic(err) + } + return http.FileServerFS(fs) +} + +func ServeIndex(w http.ResponseWriter, r *http.Request) { + file, _ := frontendFS.ReadFile("frontend/dist/index.html") + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(file) +} 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/.oxlintrc.json b/frontend/.oxlintrc.json new file mode 100644 index 0000000..6fa991d --- /dev/null +++ b/frontend/.oxlintrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "typescript", "oxc"], + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..d6af7e3 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,32 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the Oxlint configuration + +If you are developing a production application, we recommend enabling type-aware lint rules by installing `oxlint-tsgolint` and editing `.oxlintrc.json`: + +```json +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "typescript", "oxc"], + "options": { + "typeAware": true + }, + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} +``` + +See the [Oxlint rules documentation](https://oxc.rs/docs/guide/usage/linter/rules) for the full list of rules and categories. diff --git a/frontend/index.html b/frontend/index.html index e69de29..3d944d7 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Outfit-Voting Abi26 + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..85fcd6c --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,1487 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "lucide-react": "^1.21.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.0" + }, + "devDependencies": { + "@types/node": "^24.13.2", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "oxlint": "^1.69.0", + "typescript": "~6.0.2", + "vite": "^8.1.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.137.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz", + "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.71.0.tgz", + "integrity": "sha512-ImGmd1njEg4FEJH03jhRnveEegtO3czCtfptvaHivKAZQIYATbVFBrrzbaYMYv0oJioTnxZAZVSyV+oL7W8S2g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.71.0.tgz", + "integrity": "sha512-4A5BEexBrwY1YFF8Kiq/lp/wQPRG79G3BWIE1FuWaM5MvmpYSd+7ZySVcKkHdwo0UDzdQGddp6pD9mpctMqLnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.71.0.tgz", + "integrity": "sha512-9wJA9GJulLwS2usU3CEisI/ESDO1n1z9eyTCvApMDrAkbJ1ve0mORgTMjcWWsKxkzkeZ2N/Gpra5IQE7x8tYgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.71.0.tgz", + "integrity": "sha512-PlLCjS06V0PeJMAJwzjrExw1sYNW9Gch3JtNlcwwZDXGlTYDuwHNN89zYH8LTXFfgkVtsYvs2nv0FqrzyuFDzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.71.0.tgz", + "integrity": "sha512-Lhil7bWre0ncxbUoDoxfS0JzpTz17BRQKW7iwoAUY8GJ66+WwJEfYPCFJ1P0WgVZR5/O/b3Q2pENlHOjeXLOGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.71.0.tgz", + "integrity": "sha512-Oo9/L58PYD3RC0x05d2upAPLllHytTjHQGsnC06P6Ynn7jKkp5mdImQxXdJ3+FnBaKspNpGogzgVsi6g872LiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.71.0.tgz", + "integrity": "sha512-mSHfyfgJrEbyIR29ejaeS50BdPk+GoNPlC1dckpDiUZbJAIel68sjSMdOt4WY0/gva+ECC7FNITQkxMJU+vSBw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.71.0.tgz", + "integrity": "sha512-n9yY4M2tiy3aij4AqtlnspzpfdpeT5JQfK2/w2d8oyp5W0FRwOb1dIeX99nORNcxGr08iD9bH8N5XFz3I2iy8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.71.0.tgz", + "integrity": "sha512-fJZrs5sDZtTaPIOiemRQQmo82Ezy+vOGXemPc4Ok7iVVsYsFa7SlW6Z5XN819VfsqBHRm3NJ3rTdnR8+bJYJdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.71.0.tgz", + "integrity": "sha512-cwl7VKGERIy9p+G+AvZdfy/06q0aHXaTt/mMRReC751iuNYJgqKjB7NydXSS30nBT9vtr2tunciOtrR4fD6FUA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.71.0.tgz", + "integrity": "sha512-eZ8ieVXvzGi8jr7+ybQGPK2STw3mldfxZlgA2738iflfB/rzA69sE6m5rDRpQaxC7dpm745Enlh1Tod0QAk9Gg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.71.0.tgz", + "integrity": "sha512-puMDbQYe6+NXwfMusojoA7CXGn2b3utukmd23PQqc1E3XhVCwyZ+FueSMzDYeNgDV2dUfIVXAAKZBcFDeCL6sA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.71.0.tgz", + "integrity": "sha512-4NJLxBs1ujISCt3L/1FcywLs73PWtJuw+piD6feK2V6h6OS6P7xu9/sWt1DTRLibe6QCzmfZzmM/2HPORoV/Lg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.71.0.tgz", + "integrity": "sha512-cFDaiR8L3430qp88tfZnvFlt3KotFhR/DlbIL0nHOMMYiG/9Wy4l+6f7t8G8pTa9bd8Lt8+M0y/qjRQ/xcB74g==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.71.0.tgz", + "integrity": "sha512-orfixdt76KlpNly9z0PkWBBNfwjKz+JFVLP/7wnVchlKNU9Dpt9InU/ZggeSej6fC7qwHmHNOGlhLnQXcYoGuA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.71.0.tgz", + "integrity": "sha512-9emQu2lAp6yhPB3XuI+++vR+l/o6JR1X+EpxwcumPdQXBWXEPAsquPGL7l158EqU8SebQMXTUa/S5zN98juyHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.71.0.tgz", + "integrity": "sha512-bd5kI8spYwTm3BILDtGhi73zoup5dw8MlPQNT8YB3BD5UIsjNe3K9/4ctrzQMX4SZMoK5HgzVLkLJzacEXB7fA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.71.0.tgz", + "integrity": "sha512-W4HvOHGzVLHcrmFu+bMrJlho+/yrlX5ZNdJZqGe8MEldkQG+RHYhxxad9P4jvWAYFmIqUA5i9DQ8QsJqSU9GIw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.71.0.tgz", + "integrity": "sha512-D2kyEIPHk/G/wiZLnwTVC/sVst+T/lKldVOjAFpgTIBUAOlry72e5OiapDbDBF4LfJLkN5ypJb/8Eu6yJzkveQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.2.tgz", + "integrity": "sha512-2cZ+7xRS+DBcuJBJKnfzsbleumJhBqSlJVpuzHC0nTqfd3QQ7Vx2/x5YR/D7cBamKSeWplwo82Fn9lqYUDEMfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.2.tgz", + "integrity": "sha512-RkPMJnygxsgOYdkfqgpwY0/Fzm8d0VQe6HGU2/B00Xa9eqdLbrII+DOKAodbJAn3ZL1AJxGHkZRPYazgGY6Ljw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.2.tgz", + "integrity": "sha512-Uiczh6vFhwyfd7WNe7Q7mCA4KxAiLdz7jPE/WGizfRpIieoyFuNVMmM8HqZ9HwudTkY6/AeMQwlNJ9NJijguWw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.2.tgz", + "integrity": "sha512-+TpdtTRgHiJFjCVFbw311SuLk3KfytPOQQn+VlAEv+gBxYPtL7E6JS9e/tk+8CwxhIZvemJKo4rTKgfWNsKkkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.2.tgz", + "integrity": "sha512-4lv1/tkmi7ueIVHnyreaOeUpiZP26BH9rRy6hoYfR9310A2B9nUEVRDvBx69vx64Nr3eTPPRkyciqJJs+j9Jmw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.2.tgz", + "integrity": "sha512-gBSUVO0eaWgw1JMjK3gB8BMlX2Mk148s2lTiVT3e9vjVxbl7UDfMWWY8CfIaaqiXuM9fVTMxIpUz6CAo/B6Vlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.2.tgz", + "integrity": "sha512-LjQP/iZLBu8o8PjIfk4x3At0/mT6h282pvz8Z5LAyhGbu/kDezyO7ea62rF5uoqmgnIYqbN/MqJ3Si3Aymi7xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.2.tgz", + "integrity": "sha512-X/7bVLWelEsbyWDUSXt7zVsTniLLPIY2n1rH58qr78l9i7MNbbxBWD8gI2vRfBWf4NUXJCUuQnfZDsp32LqsfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.2.tgz", + "integrity": "sha512-gb6dYKW/1KDorGXyy48glEBJs/sxVSC5pcVrox/pFGV4mvwSFeg2sK5L2tRkVsVlh7kueqOgg4GEcuipJcGuKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.2.tgz", + "integrity": "sha512-JY4w85pU3iAiJVMh5nuk4/Mh9GjMsupe8MrIN53rwxAZW64GKrWeJBuN6SxQg9QTU5uB1cxyhDzW8jqRn1EABw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.2.tgz", + "integrity": "sha512-xvpA7o5KCYLB0Rwscmuylb1/zHHSUx4g4xilm4prC5jP76pEUlzBmMbgpbh7bVDbId4NcfT96gN5i6mE6UDaiw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.2.tgz", + "integrity": "sha512-p/ts6KBLjuk49Bp21XH77poQGt02iNz7ChgHep7tudPOaLinR/De/RHdxF8w8Yj4r/bF/bqXwH6PZrB2sA+Nvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.2.tgz", + "integrity": "sha512-VMu/wmrZ9hJzYlRhbw7jK5PODlugyKZ5mOdX78+lS8OvuFkWNQdz1pFLrI2p3P0pjXOmUZ7B48o5VnMH9QOGtg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.5" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.2.tgz", + "integrity": "sha512-xtUJqs8qEkuSviS0n1tsohaPuz3a1SPhZywOji4Oo+sgrJs8daEDMZ0QtqL0OS7dx8PoVpg2J/ZZycPY5I2+Zg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.2.tgz", + "integrity": "sha512-85YiLQqjUKgSO/Zjnf9e0XIn5Ymrh1fLDWBeAkZqpuBR/3R8TpfoHXuyblqyQrftSSgWO9qpcHN8mkyKsLraoA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/node": { + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", + "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", + "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lucide-react": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.21.0.tgz", + "integrity": "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/oxlint": { + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.71.0.tgz", + "integrity": "sha512-U1m1X+C0vDj7DC1e13IoZULzEcPczE7UOMTs8VlZGHUEIUaSTZKo5qkPsQEfzpgnQ29Pea/w3Xntk62UCecxZw==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.71.0", + "@oxlint/binding-android-arm64": "1.71.0", + "@oxlint/binding-darwin-arm64": "1.71.0", + "@oxlint/binding-darwin-x64": "1.71.0", + "@oxlint/binding-freebsd-x64": "1.71.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.71.0", + "@oxlint/binding-linux-arm-musleabihf": "1.71.0", + "@oxlint/binding-linux-arm64-gnu": "1.71.0", + "@oxlint/binding-linux-arm64-musl": "1.71.0", + "@oxlint/binding-linux-ppc64-gnu": "1.71.0", + "@oxlint/binding-linux-riscv64-gnu": "1.71.0", + "@oxlint/binding-linux-riscv64-musl": "1.71.0", + "@oxlint/binding-linux-s390x-gnu": "1.71.0", + "@oxlint/binding-linux-x64-gnu": "1.71.0", + "@oxlint/binding-linux-x64-musl": "1.71.0", + "@oxlint/binding-openharmony-arm64": "1.71.0", + "@oxlint/binding-win32-arm64-msvc": "1.71.0", + "@oxlint/binding-win32-ia32-msvc": "1.71.0", + "@oxlint/binding-win32-x64-msvc": "1.71.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.22.1", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-router": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz", + "integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz", + "integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==", + "license": "MIT", + "dependencies": { + "react-router": "7.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/rolldown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.2.tgz", + "integrity": "sha512-x0CrQQqCXWGeI8dTvFfN/Dnv3yMKT9hv5jFjlOreKAx9wqLq9wz7VvLLHyaAXC90/CpggTu9SisSbsJJTPSjNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.137.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.2", + "@rolldown/binding-darwin-arm64": "1.1.2", + "@rolldown/binding-darwin-x64": "1.1.2", + "@rolldown/binding-freebsd-x64": "1.1.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.2", + "@rolldown/binding-linux-arm64-gnu": "1.1.2", + "@rolldown/binding-linux-arm64-musl": "1.1.2", + "@rolldown/binding-linux-ppc64-gnu": "1.1.2", + "@rolldown/binding-linux-s390x-gnu": "1.1.2", + "@rolldown/binding-linux-x64-gnu": "1.1.2", + "@rolldown/binding-linux-x64-musl": "1.1.2", + "@rolldown/binding-openharmony-arm64": "1.1.2", + "@rolldown/binding-wasm32-wasi": "1.1.2", + "@rolldown/binding-win32-arm64-msvc": "1.1.2", + "@rolldown/binding-win32-x64-msvc": "1.1.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz", + "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "~1.1.2", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..8e8a51b --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,27 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "oxlint", + "preview": "vite preview" + }, + "dependencies": { + "lucide-react": "^1.21.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.0" + }, + "devDependencies": { + "@types/node": "^24.13.2", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "oxlint": "^1.69.0", + "typescript": "~6.0.2", + "vite": "^8.1.0" + } +} diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/frontend/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/icons.svg b/frontend/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/frontend/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/logo.png b/frontend/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..01a8bfdfe1ef8e75168640f02f27491d2c3e9274 GIT binary patch literal 69362 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≫dj>sigRerF+ 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 div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..95d4ae9 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { Footer } from './components/Footer'; +import VotingPage from './pages/voting'; +import AdminPage from './pages/admin'; +import ResultPage from './pages/result'; + +export const App: React.FC = () => { + return ( + +
+ + } /> + } /> + } /> + +
+
+
+ ); +}; + +export default App; diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts new file mode 100644 index 0000000..f067c4b --- /dev/null +++ b/frontend/src/api/index.ts @@ -0,0 +1,101 @@ +import type { VoteOption, VoteResult } from '../types'; + +const API_BASE = '/api'; + +export const api = { + getVoteLocked: async (): Promise => { + const res = await fetch(`${API_BASE}/vote/locked`); + if (!res.ok) throw new Error('Failed to fetch vote lock state'); + return res.json(); + }, + + getResultLocked: async (): Promise => { + const res = await fetch(`${API_BASE}/result/locked`); + if (!res.ok) throw new Error('Failed to fetch result lock state'); + return res.json(); + }, + + getVoteOptions: async (): Promise => { + const res = await fetch(`${API_BASE}/vote`); + if (res.status === 423) throw new Error('Locked'); + if (!res.ok) throw new Error('Failed to fetch options'); + return res.json(); + }, + + incVote: async (id: string): Promise => { + const res = await fetch(`${API_BASE}/vote/${id}/inc`, { method: 'PATCH' }); + if (!res.ok) throw new Error('Failed to submit vote'); + }, + + getResults: async (): Promise => { + const res = await fetch(`${API_BASE}/result`); + if (res.status === 423) throw new Error('Locked'); + if (!res.ok) throw new Error('Failed to fetch results'); + return res.json(); + }, + + // Admin Endpoints + setVoteLocked: async (value: boolean): Promise => { + const res = await fetch(`${API_BASE}/vote/locked`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ Value: value }) + }); + if (!res.ok) throw new Error('Failed to set lock'); + }, + + setResultLocked: async (value: boolean): Promise => { + const res = await fetch(`${API_BASE}/result/locked`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ Value: value }) + }); + if (!res.ok) throw new Error('Failed to set lock'); + }, + + addVoteEntry: async (name: string, category: string): Promise => { + const res = await fetch(`${API_BASE}/vote`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ Name: name, Category: category }) + }); + if (!res.ok) throw new Error('Failed to add entry'); + return res.json(); + }, + + deleteVoteEntry: async (id: string): Promise => { + const res = await fetch(`${API_BASE}/vote/${id}`, { method: 'DELETE' }); + if (!res.ok) throw new Error('Failed to delete entry'); + }, + + bulkDeleteVoteEntries: async (ids: string[]): Promise => { + const res = await fetch(`${API_BASE}/vote/bulk`, { + method: 'DELETE', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(ids) + }); + if (!res.ok) throw new Error('Failed to delete entries'); + }, + + setVoteCount: async (id: string, votes: number): Promise => { + const res = await fetch(`${API_BASE}/vote/${id}/override`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ Votes: votes }) + }); + if (!res.ok) throw new Error('Failed to override vote'); + }, + + getUser: async (): Promise => { + try { + const res = await fetch(`/admin`); + return res.headers.get('user'); + } catch { + return null; + } + }, + + logout: async (): Promise => { + await fetch(`${API_BASE}/auth/logout`); + } +}; diff --git a/frontend/src/assets/hero.png b/frontend/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..02251f4b956c55af2d76fd0788124d7eee2b45eb GIT binary patch literal 13057 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 P00000NkvXXu0mjft=yBf literal 0 HcmV?d00001 diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/frontend/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/vite.svg b/frontend/src/assets/vite.svg new file mode 100644 index 0000000..5101b67 --- /dev/null +++ b/frontend/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/frontend/src/components/ConfirmDialog.css b/frontend/src/components/ConfirmDialog.css new file mode 100644 index 0000000..113715c --- /dev/null +++ b/frontend/src/components/ConfirmDialog.css @@ -0,0 +1,66 @@ +.dialog-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + padding: 1rem; +} + +.dialog-panel { + max-width: 400px; + width: 100%; + padding: 2rem; +} + +.dialog-title { + margin: 0 0 1rem 0; + font-family: 'Sora', sans-serif; + font-size: 1.5rem; +} + +.dialog-message { + color: var(--text-muted); + margin-bottom: 2rem; + line-height: 1.5; +} + +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 1rem; +} + +.btn-cancel, .btn-confirm { + padding: 0.75rem 1.5rem; + border-radius: var(--radius-m); + border: none; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; +} + +.btn-cancel { + background: transparent; + color: var(--text); + border: 1px solid var(--panel-border); +} + +.btn-cancel:hover { + background: rgba(255, 255, 255, 0.1); +} + +.btn-confirm { + background: var(--teal); + color: var(--bg); +} + +.btn-confirm:hover { + background: #25d9ff; + transform: translateY(-2px); + box-shadow: 0 4px 15px var(--teal-soft); +} diff --git a/frontend/src/components/ConfirmDialog.tsx b/frontend/src/components/ConfirmDialog.tsx new file mode 100644 index 0000000..db44da5 --- /dev/null +++ b/frontend/src/components/ConfirmDialog.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import './ConfirmDialog.css'; + +interface ConfirmDialogProps { + isOpen: boolean; + title: string; + message: string; + onConfirm: () => void; + onCancel: () => void; +} + +export const ConfirmDialog: React.FC = ({ isOpen, title, message, onConfirm, onCancel }) => { + if (!isOpen) return null; + + return ( +
+
+

{title}

+

{message}

+
+ + +
+
+
+ ); +}; diff --git a/frontend/src/components/Footer.css b/frontend/src/components/Footer.css new file mode 100644 index 0000000..f028817 --- /dev/null +++ b/frontend/src/components/Footer.css @@ -0,0 +1,53 @@ +.footer { + margin-top: auto; + padding: 1.5rem 0 0.5rem 0; + text-align: center; + background: transparent; + border: none; + box-shadow: none; + backdrop-filter: none; + -webkit-backdrop-filter: none; +} + +.footer-content { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: 1.5rem; + font-size: 0.75rem; + color: var(--text-muted); + opacity: 0.6; + transition: opacity 0.2s ease; +} + +.footer-content:hover { + opacity: 1; +} + +.footer-link { + color: inherit; + text-decoration: underline; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.footer-link:hover { + color: var(--teal); +} + +.footer-credits { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; +} + +.footer-credits p { + margin: 0; +} + +.footer-credits strong { + font-weight: 500; + color: var(--text); + margin-left: 0.2rem; +} diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx new file mode 100644 index 0000000..fcf1b27 --- /dev/null +++ b/frontend/src/components/Footer.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import './Footer.css'; + +export const Footer: React.FC = () => { + return ( +
+ ); +}; diff --git a/frontend/src/components/Header.css b/frontend/src/components/Header.css new file mode 100644 index 0000000..4abc5a1 --- /dev/null +++ b/frontend/src/components/Header.css @@ -0,0 +1,64 @@ +.app-header { + position: fixed; + top: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + border-bottom: 1px solid var(--panel-border); + background: rgba(8, 14, 20, 0.6); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + z-index: 100; +} + +.header-brand { + display: flex; + align-items: center; + gap: 1rem; + text-decoration: none; + color: var(--text); +} + +.header-brand:hover { + opacity: 0.9; +} + +.header-logo { + height: 40px; + width: auto; + filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.1)); +} + +.header-title { + font-family: 'Sora', sans-serif; + font-size: 1.5rem; + font-weight: 600; + color: var(--text); + letter-spacing: 0.5px; +} + +.header-admin { + display: flex; + align-items: center; + gap: 1.5rem; +} + +.header-username { + font-size: 1rem; + font-weight: 500; + color: var(--teal); + background: var(--teal-soft); + padding: 0.4rem 0.8rem; + border-radius: var(--radius-m); +} + +@media (max-width: 600px) { + .app-header { + flex-direction: column; + gap: 1rem; + padding: 1rem; + } +} diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx new file mode 100644 index 0000000..994e781 --- /dev/null +++ b/frontend/src/components/Header.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { LogOut } from 'lucide-react'; +import { Link } from 'react-router-dom'; +import './Header.css'; + +interface HeaderProps { + showAdminControls?: boolean; + username?: string | null; + onLogout?: () => void; + showResultsLink?: boolean; +} + +export const Header: React.FC = ({ showAdminControls, username, onLogout, showResultsLink }) => { + return ( +
+ + Goethe+ Logo + Outfit-Voting Abi26 + + +
+ {showResultsLink && ( + + Ergebnisse + + )} + {showAdminControls && ( + <> + {username && ( + + {username} + + )} + {onLogout && ( + + )} + + )} +
+
+ ); +}; diff --git a/frontend/src/components/LockScreen.css b/frontend/src/components/LockScreen.css new file mode 100644 index 0000000..3ebafdf --- /dev/null +++ b/frontend/src/components/LockScreen.css @@ -0,0 +1,36 @@ +.lock-screen { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 4rem 2rem; + text-align: center; + margin: auto 0; +} + +.lock-icon-container { + width: 96px; + height: 96px; + background: var(--teal-soft); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 2rem; + color: var(--teal); + box-shadow: 0 0 40px var(--teal-soft); +} + +.lock-title { + font-family: 'Sora', sans-serif; + font-size: 2rem; + margin: 0 0 1rem 0; +} + +.lock-message { + color: var(--text-muted); + font-size: 1.1rem; + max-width: 400px; + line-height: 1.6; +} diff --git a/frontend/src/components/LockScreen.tsx b/frontend/src/components/LockScreen.tsx new file mode 100644 index 0000000..be83140 --- /dev/null +++ b/frontend/src/components/LockScreen.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Lock } from 'lucide-react'; +import './LockScreen.css'; + +interface LockScreenProps { + message?: string; +} + +export const LockScreen: React.FC = ({ message = "Voting oder Zählung noch nicht abgeschlossen" }) => { + return ( +
+
+ +
+

Derzeit Gesperrt

+

{message}

+
+ ); +}; diff --git a/frontend/src/components/SearchableSelect.css b/frontend/src/components/SearchableSelect.css new file mode 100644 index 0000000..68738e7 --- /dev/null +++ b/frontend/src/components/SearchableSelect.css @@ -0,0 +1,104 @@ +.search-select { + position: relative; + width: 100%; + font-family: 'Outfit', sans-serif; +} + +.search-select.disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.select-header { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--panel-border); + border-radius: var(--radius-m); + padding: 0.8rem 1rem; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + transition: all 0.2s ease; +} + +.search-select:not(.disabled) .select-header:hover { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.15); +} + +.chevron { + transition: transform 0.2s ease; +} +.chevron.open { + transform: rotate(180deg); +} + +.select-dropdown { + position: absolute; + top: calc(100% + 0.5rem); + left: 0; + right: 0; + z-index: 50; + display: flex; + flex-direction: column; + max-height: 300px; + overflow: hidden; + padding: 0; +} + +.search-box { + display: flex; + align-items: center; + padding: 0.8rem 1rem; + border-bottom: 1px solid var(--panel-border); + gap: 0.5rem; +} + +.search-icon { + color: var(--text-muted); +} + +.search-box input { + background: transparent; + border: none; + outline: none; + width: 100%; + color: var(--text); + font-size: 0.95rem; +} + +.options-list { + overflow-y: auto; + padding: 0.5rem; +} + +.options-list::-webkit-scrollbar { + width: 6px; +} +.options-list::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 10px; +} + +.option-item { + padding: 0.6rem 1rem; + border-radius: var(--radius-m); + cursor: pointer; + transition: background 0.2s; +} + +.option-item:hover { + background: rgba(255, 255, 255, 0.05); +} + +.option-item.selected { + background: var(--teal-soft); + color: var(--teal); + font-weight: 500; +} + +.no-options { + padding: 1rem; + text-align: center; + color: var(--text-muted); +} diff --git a/frontend/src/components/SearchableSelect.tsx b/frontend/src/components/SearchableSelect.tsx new file mode 100644 index 0000000..a2f7295 --- /dev/null +++ b/frontend/src/components/SearchableSelect.tsx @@ -0,0 +1,64 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { ChevronDown, Search } from 'lucide-react'; +import './SearchableSelect.css'; + +interface Option { value: string; label: string; } + +interface SearchableSelectProps { + options: Option[]; + value: string; + onChange: (val: string) => void; + disabled?: boolean; +} + +export const SearchableSelect: React.FC = ({ options, value, onChange, disabled }) => { + const [isOpen, setIsOpen] = useState(false); + const [search, setSearch] = useState(''); + const ref = useRef(null); + + useEffect(() => { + const handleClick = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) setIsOpen(false); + }; + document.addEventListener('mousedown', handleClick); + return () => document.removeEventListener('mousedown', handleClick); + }, []); + + const filtered = options.filter(o => o.label.toLowerCase().includes(search.toLowerCase())); + const selected = options.find(o => o.value === value); + + return ( +
+
!disabled && setIsOpen(!isOpen)}> + {selected ? selected.label : 'Bitte wählen...'} + +
+ {isOpen && ( +
+
+ + setSearch(e.target.value)} + /> +
+
+ {filtered.map(o => ( +
{ onChange(o.value); setIsOpen(false); setSearch(''); }} + > + {o.label} +
+ ))} + {filtered.length === 0 &&
Keine Ergebnisse
} +
+
+ )} +
+ ); +}; diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..f4b313d --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,116 @@ +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=Sora:wght@500;600;700&display=swap'); + +:root { + --bg: #010407; + --bg-soft: #061019; + --panel: rgba(8, 14, 20, 0.82); + --panel-border: rgba(255, 255, 255, 0.09); + --text: #f4f8fc; + --text-muted: rgba(231, 238, 244, 0.66); + --teal: #17c1e7; + --teal-soft: rgba(23, 193, 231, 0.35); + --success: #55e783; + --danger: #ff5f69; + --shadow-soft: 0 16px 40px rgba(0, 0, 0, 0.45); + --radius-xl: 28px; + --radius-l: 20px; + --radius-m: 14px; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html, +body, +#root { + min-height: 100vh; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; +} + +body { + font-family: 'Outfit', 'Segoe UI', sans-serif; + background: + radial-gradient(1050px 520px at 85% -12%, rgba(120, 236, 255, 0.21), transparent 56%), + radial-gradient(780px 380px at 12% -8%, rgba(0, 173, 217, 0.24), transparent 52%), + var(--bg); + background-attachment: fixed; + color: var(--text); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +button, +input, +textarea, +select { + font: inherit; + color: inherit; +} + +a { + color: inherit; + text-decoration: none; +} + +/* Base Panel Style */ +.panel { + background: var(--panel); + border: 1px solid var(--panel-border); + border-radius: var(--radius-l); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} + +/* Main Layout */ +.app-container { + flex: 1; + display: flex; + flex-direction: column; + max-width: 1200px; + width: 100%; + margin: 0 auto; + padding: 100px 2rem 2rem 2rem; +} + +@media (max-width: 768px) { + .app-container { + padding: 120px 1rem 1rem 1rem; + } +} + +/* Shared Categories Grid & Cards */ +.categories-grid { + display: flex; + flex-direction: column; + align-items: center; + gap: 2rem; +} + +.category-card { + width: 100%; + max-width: 600px; + padding: 2.2rem; + display: flex; + flex-direction: column; + gap: 1.5rem; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.category-card:hover { + transform: translateY(-2px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5); +} + +.category-title { + margin: 0; + font-family: 'Sora', sans-serif; + font-size: 1.5rem; + color: var(--teal); +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..3d7150d --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/frontend/src/pages/admin/Admin.css b/frontend/src/pages/admin/Admin.css new file mode 100644 index 0000000..413834a --- /dev/null +++ b/frontend/src/pages/admin/Admin.css @@ -0,0 +1,255 @@ +.admin-page { + flex: 1; + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.admin-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5rem; +} + +.admin-header h2 { + margin: 0; + font-family: 'Sora', sans-serif; + color: var(--teal); +} + +.btn-logout { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.6rem 1.2rem; + background: transparent; + color: var(--danger); + border: 1px solid var(--danger); + border-radius: var(--radius-m); + cursor: pointer; + transition: all 0.2s; + font-weight: 500; +} + +.btn-logout:hover { + background: var(--danger); + color: #fff; +} + +.admin-controls { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +@media (max-width: 768px) { + .admin-controls { + grid-template-columns: 1fr; + } +} + +.control-card { + padding: 1.5rem; +} + +.control-card h3 { + margin: 0 0 1.5rem 0; + font-family: 'Sora', sans-serif; +} + +.lock-toggles { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.toggle-btn { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 1rem; + border-radius: var(--radius-m); + border: none; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; +} + +.toggle-btn.unlocked { + background: var(--success); + color: #000; +} + +.toggle-btn.locked { + background: var(--danger); + color: #fff; +} + +.bulk-add-form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.bulk-add-form input, +.bulk-add-form textarea { + background: rgba(255, 255, 255, 0.05); + border: 1px solid var(--panel-border); + padding: 0.8rem; + border-radius: var(--radius-m); + color: var(--text); +} + +.btn-primary { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + background: var(--teal); + color: var(--bg); + padding: 0.8rem; + border: none; + border-radius: var(--radius-m); + font-weight: 600; + cursor: pointer; + transition: all 0.2s; +} + +.btn-primary:hover { + background: #25d9ff; +} + +.bulk-actions { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.5rem; + background: rgba(255, 95, 105, 0.1); + border-color: var(--danger); +} + +.btn-danger { + display: flex; + align-items: center; + gap: 0.5rem; + background: var(--danger); + color: #fff; + border: none; + padding: 0.6rem 1.2rem; + border-radius: var(--radius-m); + cursor: pointer; +} + +.admin-tables { + display: flex; + flex-direction: column; + gap: 2rem; +} + +.admin-table-panel { + padding: 0; + overflow: hidden; +} + +.table-header-flex { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5rem; + border-bottom: 1px solid var(--panel-border); + background: rgba(0, 0, 0, 0.2); +} + +.table-title { + margin: 0; + font-family: 'Sora', sans-serif; + color: var(--teal); +} + +.btn-icon.add-to-cat { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + font-weight: 500; + background: rgba(255, 255, 255, 0.05); + padding: 0.4rem 0.8rem; +} + +.btn-icon.add-to-cat:hover { + background: var(--teal-soft); + color: var(--teal); +} + +.admin-table { + width: 100%; + border-collapse: collapse; +} + +.admin-table th, +.admin-table td { + padding: 1rem 1.5rem; + text-align: left; + border-bottom: 1px solid var(--panel-border); +} + +.admin-table th { + background: rgba(255, 255, 255, 0.02); + color: var(--text-muted); + font-weight: 500; +} + +.admin-table tr:hover td { + background: rgba(255, 255, 255, 0.02); +} + +.vote-badge { + background: var(--teal-soft); + color: var(--teal); + padding: 0.2rem 0.6rem; + border-radius: 12px; + font-weight: 600; +} + +.edit-input { + width: 60px; + background: rgba(0,0,0,0.3); + border: 1px solid var(--teal); + color: var(--text); + padding: 0.3rem; + border-radius: 4px; +} + +.action-buttons { + display: flex; + gap: 0.5rem; +} + +.btn-icon { + background: transparent; + border: none; + cursor: pointer; + padding: 0.4rem; + border-radius: 4px; + color: var(--text-muted); + transition: all 0.2s; +} + +.btn-icon.edit:hover { + color: var(--teal); + background: var(--teal-soft); +} + +.btn-icon.delete:hover { + color: var(--danger); + background: rgba(255, 95, 105, 0.2); +} + +.btn-icon.save { + color: var(--success); + background: rgba(85, 231, 131, 0.1); + padding: 0.4rem 0.8rem; + font-size: 0.85rem; +} diff --git a/frontend/src/pages/admin/index.tsx b/frontend/src/pages/admin/index.tsx new file mode 100644 index 0000000..2c2a198 --- /dev/null +++ b/frontend/src/pages/admin/index.tsx @@ -0,0 +1,338 @@ +import { useEffect, useState, useMemo } from 'react'; +import { api } from '../../api'; +import type { VoteOption } from '../../types'; +import { ConfirmDialog } from '../../components/ConfirmDialog'; +import { Header } from '../../components/Header'; +import { Trash2, Edit2, Lock, Unlock, Plus } from 'lucide-react'; +import './Admin.css'; + +export default function AdminPage() { + const [options, setOptions] = useState([]); + const [voteLocked, setVoteLocked] = useState(false); + const [resultLocked, setResultLocked] = useState(false); + const [loading, setLoading] = useState(true); + const [username, setUsername] = useState(null); + + // Confirm Dialog State + const [dialog, setDialog] = useState<{ isOpen: boolean; title: string; message: string; action: () => void }>({ + isOpen: false, title: '', message: '', action: () => {} + }); + + // Bulk Add State + const [bulkCategory, setBulkCategory] = useState(''); + const [bulkNames, setBulkNames] = useState(''); + + // Bulk Delete State + const [selectedIds, setSelectedIds] = useState>(new Set()); + + // Edit State + const [editId, setEditId] = useState(null); + const [editVotes, setEditVotes] = useState(0); + + // Filter & Sort State + const [nameFilter, setNameFilter] = useState(''); + const [sortBy, setSortBy] = useState<'votes_desc' | 'votes_asc' | 'name_asc' | 'name_desc'>('votes_desc'); + + const handleSort = (field: 'votes' | 'name') => { + if (field === 'votes') { + setSortBy(prev => prev === 'votes_desc' ? 'votes_asc' : 'votes_desc'); + } else { + setSortBy(prev => prev === 'name_asc' ? 'name_desc' : 'name_asc'); + } + }; + + const loadData = async () => { + try { + const opts = await api.getResults(); + const vLocked = await api.getVoteLocked(); + const rLocked = await api.getResultLocked(); + const user = await api.getUser(); + setOptions(opts); + setVoteLocked(vLocked); + setResultLocked(rLocked); + setUsername(user); + } catch (err) { + console.error(err); + alert('Fehler beim Laden der Admin-Daten. Möglicherweise nicht authentifiziert.'); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + document.title = 'Admin - Outfit-Voting Abi26'; + loadData(); + }, []); + + const openDialog = (title: string, message: string, action: () => void) => { + setDialog({ isOpen: true, title, message, action }); + }; + + const closeDialog = () => setDialog({ ...dialog, isOpen: false }); + + const toggleVoteLock = () => { + openDialog( + voteLocked ? "Voting entsperren?" : "Voting sperren?", + voteLocked ? "Das Voting wird für alle Nutzer geöffnet." : "Das Voting wird gesperrt und niemand kann mehr abstimmen.", + async () => { + await api.setVoteLocked(!voteLocked); + setVoteLocked(!voteLocked); + closeDialog(); + } + ); + }; + + const toggleResultLock = () => { + openDialog( + resultLocked ? "Ergebnisse entsperren?" : "Ergebnisse sperren?", + resultLocked ? "Die Ergebnisse werden für alle sichtbar." : "Die Ergebnisse werden für die Öffentlichkeit gesperrt.", + async () => { + await api.setResultLocked(!resultLocked); + setResultLocked(!resultLocked); + closeDialog(); + } + ); + }; + + const handleLogout = async () => { + await api.logout(); + window.location.href = '/'; + }; + + const handleBulkAdd = async () => { + if (!bulkCategory.trim() || !bulkNames.trim()) return; + const names = bulkNames.split('\n').map(n => n.trim()).filter(n => n.length > 0); + if (names.length === 0) return; + + for (const name of names) { + await api.addVoteEntry(name, bulkCategory); + } + setBulkNames(''); + setBulkCategory(''); + loadData(); + }; + + const handleBulkDelete = async () => { + if (selectedIds.size === 0) return; + openDialog( + "Ausgewählte Einträge löschen?", + `Möchtest du wirklich ${selectedIds.size} Einträge löschen?`, + async () => { + await api.bulkDeleteVoteEntries(Array.from(selectedIds)); + setSelectedIds(new Set()); + loadData(); + closeDialog(); + } + ); + }; + + const handleDelete = (id: string) => { + openDialog("Eintrag löschen?", "Dieser Eintrag wird unwiderruflich gelöscht.", async () => { + await api.deleteVoteEntry(id); + loadData(); + closeDialog(); + }); + }; + + const saveEdit = async (id: string) => { + await api.setVoteCount(id, editVotes); + setEditId(null); + loadData(); + }; + + const toggleSelect = (id: string) => { + const next = new Set(selectedIds); + if (next.has(id)) next.delete(id); + else next.add(id); + setSelectedIds(next); + }; + + const categories = useMemo(() => { + const cats = new Set(); + options.forEach(o => cats.add(o.Category)); + return Array.from(cats).sort(); + }, [options]); + + if (loading) return
Laden...
; + + return ( + <> +
+
+
+

Admin Dashboard

+
+ +
+
+

Sperren & Freigaben

+
+ + +
+
+ +
+

Einträge hinzufügen (Bulk)

+
+ setBulkCategory(e.target.value)} + list="category-list" + /> + + {categories.map(c => +