From b01e1cd5869f1681e3845151ba2374a9d84334f8 Mon Sep 17 00:00:00 2001 From: Ari Yeger Date: Tue, 15 Jul 2025 13:35:27 -0400 Subject: [PATCH] client initial commit --- client/.gitignore | 25 + client/.vscode/extensions.json | 3 + client/README.md | 5 + client/index.html | 13 + client/package-lock.json | 1851 +++++++++++++++++++++++++++ client/package.json | 27 + client/src/App.vue | 61 + client/src/assets/css/base.css | 187 +++ client/src/assets/css/style.css | 520 ++++++++ client/src/assets/img/scales-ph.jpg | Bin 0 -> 37046 bytes client/src/components/Navbar.vue | 186 +++ client/src/globals.ts | 19 + client/src/main.ts | 28 + client/src/models/TransferTypes.ts | 12 + client/src/models/User.ts | 6 + client/src/models/rest.ts | 30 + client/src/models/session.ts | 65 + client/src/router/index.ts | 69 + client/src/views/MainPage.vue | 9 + client/src/views/NotFoundPage.vue | 11 + client/src/vite-env.d.ts | 1 + client/tsconfig.app.json | 33 + client/tsconfig.json | 7 + client/tsconfig.node.json | 27 + client/vite.config.ts | 22 + 25 files changed, 3217 insertions(+) create mode 100644 client/.gitignore create mode 100644 client/.vscode/extensions.json create mode 100644 client/README.md create mode 100644 client/index.html create mode 100644 client/package-lock.json create mode 100644 client/package.json create mode 100644 client/src/App.vue create mode 100644 client/src/assets/css/base.css create mode 100644 client/src/assets/css/style.css create mode 100644 client/src/assets/img/scales-ph.jpg create mode 100644 client/src/components/Navbar.vue create mode 100644 client/src/globals.ts create mode 100644 client/src/main.ts create mode 100644 client/src/models/TransferTypes.ts create mode 100644 client/src/models/User.ts create mode 100644 client/src/models/rest.ts create mode 100644 client/src/models/session.ts create mode 100644 client/src/router/index.ts create mode 100644 client/src/views/MainPage.vue create mode 100644 client/src/views/NotFoundPage.vue create mode 100644 client/src/vite-env.d.ts create mode 100644 client/tsconfig.app.json create mode 100644 client/tsconfig.json create mode 100644 client/tsconfig.node.json create mode 100644 client/vite.config.ts diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..8b17450 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local +.env.* +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/client/.vscode/extensions.json b/client/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/client/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..33895ab --- /dev/null +++ b/client/README.md @@ -0,0 +1,5 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 0000000..2d5d20d --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,1851 @@ +{ + "name": "ijy-client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ijy-client", + "version": "0.0.0", + "dependencies": { + "jwt-decode": "^4.0.0", + "vue": "^3.5.17", + "vue-router": "^4.5.1", + "vue-toast-notification": "^3.1.3" + }, + "devDependencies": { + "@types/node": "^24.0.10", + "@vitejs/plugin-vue": "^6.0.0", + "@vue/tsconfig": "^0.7.0", + "axios": "^1.6.5", + "bootstrap": "^5.3.3", + "typescript": "~5.8.3", + "vite": "^7.0.4", + "vue-tsc": "^2.2.12" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", + "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.0.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz", + "integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.0.tgz", + "integrity": "sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.19" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", + "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.15" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", + "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", + "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.15", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz", + "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/shared": "3.5.17", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz", + "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz", + "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/compiler-core": "3.5.17", + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz", + "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", + "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.15", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^1.0.3", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz", + "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz", + "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz", + "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/runtime-core": "3.5.17", + "@vue/shared": "3.5.17", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz", + "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "vue": "3.5.17" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz", + "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", + "license": "MIT" + }, + "node_modules/@vue/tsconfig": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz", + "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": "5.x", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/alien-signals": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", + "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bootstrap": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.45.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.45.1", + "@rollup/rollup-android-arm64": "4.45.1", + "@rollup/rollup-darwin-arm64": "4.45.1", + "@rollup/rollup-darwin-x64": "4.45.1", + "@rollup/rollup-freebsd-arm64": "4.45.1", + "@rollup/rollup-freebsd-x64": "4.45.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", + "@rollup/rollup-linux-arm-musleabihf": "4.45.1", + "@rollup/rollup-linux-arm64-gnu": "4.45.1", + "@rollup/rollup-linux-arm64-musl": "4.45.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-gnu": "4.45.1", + "@rollup/rollup-linux-riscv64-musl": "4.45.1", + "@rollup/rollup-linux-s390x-gnu": "4.45.1", + "@rollup/rollup-linux-x64-gnu": "4.45.1", + "@rollup/rollup-linux-x64-musl": "4.45.1", + "@rollup/rollup-win32-arm64-msvc": "4.45.1", + "@rollup/rollup-win32-ia32-msvc": "4.45.1", + "@rollup/rollup-win32-x64-msvc": "4.45.1", + "fsevents": "~2.3.2" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.4.tgz", + "integrity": "sha512-SkaSguuS7nnmV7mfJ8l81JGBFV7Gvzp8IzgE8A8t23+AxuNX61Q5H1Tpz5efduSN7NHC8nQXD3sKQKZAu5mNEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.2", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "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", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "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 + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz", + "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-sfc": "3.5.17", + "@vue/runtime-dom": "3.5.17", + "@vue/server-renderer": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-toast-notification": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vue-toast-notification/-/vue-toast-notification-3.1.3.tgz", + "integrity": "sha512-XNyWqwLIGBFfX5G9sK+clq3N3IPlhDjzNdbZaXkEElcotPlWs0wWZailk1vqhdtLYT/93Y4FHAVuzyatLmPZRA==", + "license": "MIT", + "engines": { + "node": ">=12.15.0" + }, + "peerDependencies": { + "vue": "^3.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz", + "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.15", + "@vue/language-core": "2.2.12" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..51e38a9 --- /dev/null +++ b/client/package.json @@ -0,0 +1,27 @@ +{ + "name": "ijy-client", + "private": false, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "jwt-decode": "^4.0.0", + "vue": "^3.5.17", + "vue-router": "^4.5.1", + "vue-toast-notification": "^3.1.3" + }, + "devDependencies": { + "@types/node": "^24.0.10", + "@vitejs/plugin-vue": "^6.0.0", + "@vue/tsconfig": "^0.7.0", + "axios": "^1.6.5", + "bootstrap": "^5.3.3", + "typescript": "~5.8.3", + "vite": "^7.0.4", + "vue-tsc": "^2.2.12" + } +} diff --git a/client/src/App.vue b/client/src/App.vue new file mode 100644 index 0000000..4ff46e4 --- /dev/null +++ b/client/src/App.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/client/src/assets/css/base.css b/client/src/assets/css/base.css new file mode 100644 index 0000000..ff0b863 --- /dev/null +++ b/client/src/assets/css/base.css @@ -0,0 +1,187 @@ +/* color palette from */ +:root { + --vt-c-white: #E7E7E7; + --vt-c-black: #181818; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-black); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); + + --color-nav-text-light: #178c85ff; + --color-nav-text-light-hover: #12706aff; + --color-nav-text-light-active: #093835ff; + + --color-nav-text-dark: #a8a8a8ff; + --color-nav-text-dark-hover: #dbdbdbff; + --color-nav-text-dark-active: #ffffff; + + --color-background-light: #99edcdff; + --color-background-soft-light: #57e1acff; + --color-background-mute-light: #23c788ff; + + --color-background-dark: #23c788; + --color-background-soft-dark: #57e1acff; + --color-background-mute-dark: #99edcdff; + + --primary-light: #99edcdff; + --color-primary-hover-light: #57e1acff; + --color-primary-active-light: #23c788ff; + --color-primary-disabled-light: #909090ff; + + --primary-dark: #23c788ff; + --color-primary-hover-dark: #57e1acff; + --color-primary-active-dark: #99edcdff; + --color-primary-disabled-dark: #909090ff; + + --secondary-light: #7fd9bfff; + --color-secondary-hover-light: #178c8524; + --color-secondary-active-light: #c9c8fbff; + --color-secondary-disabled-light: #88d3d3ff; + + --secondary-dark: #60AEAEff; + --color-secondary-hover-dark: #4f9b9bff; + --color-secondary-active-dark: #3e7776ff; + --color-secondary-disabled-dark: #88d3d3ff; + + --user-font: 'Public Sans', sans-serif; + --user-font-reversion: 'Public Sans', sans-serif; + + --color-modal-background-light: #b9b9b9ff; + --color-modal-background-light-inverted: #464646ff; + + --color-modal-background-dark: #464646ff; + --color-modal-background-dark-inverted: #b9b9b9ff; + + --color-form-background-light: #cdcdcdff; + + --color-form-background-dark: #323232ff; + + --color-border-light-1: #333333ff; + --color-border-light-2: #6D6D6Dff; + + --color-border-dark-1: #ccccccff; + --color-border-dark-2: #929292ff; +} + +/* semantic color variables for this project */ +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--color-background-dark); + --color-background-reversion: var(--color-background-dark); + --color-background-soft: var(--color-background-soft-dark); + --color-background-mute: var(--color-background-mute-dark); + + --color-border: var(--color-border-dark-1); + --color-border-invert: var(--color-border-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-primary: var(--primary-dark); + --color-primary-reversion: var(--primary-dark); + --color-secondary: var(--secondary-dark); + --color-secondary-reversion: var(--secondary-dark); + --color-primary-hover: var(--color-primary-hover-dark); + --color-secondary-hover: var(--color-secondary-hover-dark); + --color-primary-active: var(--color-primary-active-dark); + --color-secondary-active: var(--color-secondary-active-dark); + + --color-primary-disabled: var(--color-primary-disabled-dark); + --color-secondary-disabled: var(--color-secondary-disabled-dark); + --color-modal-background: var(--color-modal-background-dark); + --color-modal-background-inverted: var(--color-modal-background-dark-inverted); + --color-form-background: var(--color-form-background-dark); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-1); + --color-primary-font: var(--color-text); + --color-secondary-font: var(--color-text); + --color-background-font: var(--color-text); + --color-background-mute-font: var(--color-text); + --color-background-soft-font: var(--color-text); + --color-modal-background-font: var(--color-text); + --color-form-background-font: var(--color-text); + --color-modal-background-inverted-font: var(--color-text); + --color-nav-text: var(--color-nav-text-dark); + --color-nav-text-hover: var(--color-nav-text-dark-hover); + --color-nav-text-active: var(--color-nav-text-dark-active); + } +} +@media (prefers-color-scheme: light), (prefers-color-scheme: no-preference), (prefers-color-scheme: dark) { + :root { + --color-nav-text: var(--color-nav-text-light); + --color-text: var(--color-nav-text); + --color-background: var(--color-background-light); + --color-background-reversion: var(--color-background-light); + --color-background-soft: var(--color-background-soft-light); + --color-background-mute: var(--color-background-mute-light); + + --color-border: var(--color-border-light-1); + --color-border-invert: var(--color-border-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --section-gap: 160px; + --color-primary: var(--primary-light); + --color-primary-reversion: var(--primary-light); + --color-secondary: var(--secondary-light); + --color-secondary-reversion: var(--secondary-light); + --color-primary-hover: var(--color-primary-hover-light); + --color-secondary-hover: var(--color-secondary-hover-light); + --color-primary-active: var(--color-primary-active-light); + --color-secondary-active: var(--color-secondary-active-light); + --color-primary-disabled: var(--color-primary-disabled-light); + --color-secondary-disabled: var(--color-secondary-disabled-light); + + --color-modal-background: var(--color-modal-background-light); + --color-modal-background-inverted: var(--color-modal-background-light-inverted); + --color-form-background: var(--color-form-background-light); + + --color-primary-font: var(--color-text); + --color-secondary-font: var(--color-text); + --color-background-font: var(--color-text); + --color-background-mute-font: var(--color-text); + --color-background-soft-font: var(--color-text); + --color-modal-background-font: var(--color-text); + --color-form-background-font: var(--color-text); + --color-modal-background-inverted-font: var(--color-text); + --color-nav-text-hover: var(--color-nav-text-light-hover); + --color-nav-text-active: var(--color-nav-text-light-active); + --color-heading: var(--color-nav-text); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; +} + +body { + min-height: 100vh; + color: var(--color-background-font); + background: var(--color-background); + transition: color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} \ No newline at end of file diff --git a/client/src/assets/css/style.css b/client/src/assets/css/style.css new file mode 100644 index 0000000..86919f4 --- /dev/null +++ b/client/src/assets/css/style.css @@ -0,0 +1,520 @@ +@import url('../../../node_modules/bootstrap/dist/css/bootstrap.min.css'); +@import url('https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100..900;1,100..900&display=swap'); +@import url('https://db.onlinewebfonts.com/c/89d64a5584094a2f17662a5765bbf93b?family=CCWhatchamacallit+W03+Regular'); +@import url('https://db.onlinewebfonts.com/c/d1c74f711e58ad0844c33d6af9c6e31a?family=CCWhatchamacallit+W01+Bold'); + + +body { + background-color: var(--color-background); + color: var(--color-background-font); + margin: 0; + font-family: 'CCWhatchamacallit W03 Regular',sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-size: 1rem; + font-weight: 500; + line-height: 1.5; + text-align: left; + overflow-x: hidden; + overflow-y: auto; + width: 100vw; + box-sizing: border-box; +} + +b, strong, .bold { + font-family: 'CCWhatchamacallit W01 Bold', sans-serif; +} + +.media-content { + overflow: hidden; + position: absolute; + left: 175px; + margin-top: 1rem; + margin-bottom: 1rem; +} +.title1{ + font-variation-settings: 'wght' 400, 'wdth' 50, 'ital' 0; +} + +input, +select, +textarea, +.border-top { + color: var(--color-background-font); + background-color: #86dfc3ff !important; + border-color: var(--color-border); +} + +.input-group-text { + background-color: #86dfc3ff; + padding: 0.5rem; + display: flex; + align-items: center; +} + +input:disabled { + background-color: var(--color-primary-disabled) !important; + color: #f0f0f0!important; /* Bootstrap's default disabled text color */ +} + +table { + color: var(--color-background-font); + background-color: var(--color-background-mute); + border: 1px solid var(--color-border-invert); + width: 100%; + border-collapse: collapse; + table-layout: fixed; +} + +tr { + background-color: var(--color-background) ; +} + +.table td, +.table th { + border-left: none !important; + border-right: none !important; +} + +th { + background-color: var(--color-background-soft); + color: var(--color-background-font); + border-left: none !important; + border-right: none !important; + user-select: none; +} + +td, +th { + border-top: 1px solid var(--color-border-invert); + border-bottom: 1px solid var(--color-border-invert) !important; + border-left: none !important; + border-right: none !important; + text-align: center !important; + padding: 8px; +} + +tr { + background-color: var(--color-background-mute); + color: var(--color-background-font); +} + +.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(0, 0, 0, 0.05); +} + +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 20px; +} + +.accordion-button, +.accordion-button:not(.collapsed) { + color: var(--color-background-mute-font); + background-color: var(--color-background-mute); +} + +.accordion-item { + border: 1px solid var(--color-modal-background-inverted); + background-color: var(--color-background); +} + +.dropdown-menu.show, +.dropdown-menu .dropdown-menu { + background-color: var(--color-background); + border: 1px solid var(--color-modal-background-inverted); +} + +.dropdown-item { + color: var(--color-nav-text); +} + +.dropdown-menu li a:hover, +.dropdown-item:hover, +.dropdown-submenu .dropdown-item:hover { + background-color: var(--color-background); + color: var(--color-background-font); +} + +.dropdown { + cursor: pointer; +} + +.form-check-label { + user-select: none; +} + +.modal-content { + color: var(--color-background-font); + background-color: var(--color-background) !important; + border: 1px solid var(--color-modal-background-inverted); +} + +.modal-header { + color: var(--color-background-font); + background-color: var(--color-background-soft); + border-bottom: 1px solid var(--color-modal-background-inverted); +} + +.modal-footer { + color: var(--color-background-font); + background-color: var(--color-background-soft); + border-top: 1px solid var(--color-modal-background-inverted); +} + +.modal-body .card-body, .card-body { + color: var(--color-background-font); + background-color: var(--color-background) !important; +} + +.modal-body .card, .card { + background-color: var(--color-background) !important; + color: var(--color-background-font); + border: 2px solid var(--color-modal-background-inverted); +} + +.tooltip-modal { + position: relative; + display: inline-block; + opacity: 1; +} + +.tooltip { + position: absolute; + transform: translateY(-50%); + margin-left: 3rem; + padding: 6px 10px; + border-radius: 4px; + color: rgb(0, 0, 0); + font-size: 15px; + white-space: nowrap; + opacity: 0.9; +} + +.tooltip-modal .tooltiptext { + visibility: hidden; + opacity: 0; + transition: opacity 0.2s linear, + visibility 0.2s linear 0.2s; + width: 200px; + background-color: var(--color-modal-background-inverted); + color: var(--color-background); + text-align: center; + border-radius: 6px; + padding: 5px 0; + position: absolute; + z-index: 10; + bottom: 125%; + left: 50%; + margin-left: -100px; +} + +.tooltip-modal .tooltiptext::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: var(--color-modal-background-inverted) transparent transparent transparent; +} + +.tooltip-modal:hover .tooltiptext { + visibility: visible; + opacity: 1; + transition: opacity 0.2s linear; +} + +.tooltip-modal .tooltiptext:hover { + visibility: hidden; + opacity: 0; +} + +.dp__input, +.dp__input:focus, +.dp__input:hover { + background-color: var(--color-background) !important; + color: var(--color-background-font) !important; + border-color: var(--color-modal-background-inverted) !important; +} + +.dp__theme_light { + background-color: transparent !important; + border-color: var(--color-modal-background-inverted) !important; + --dp-range-between-dates-background-color: var(--color-background) !important; + --dp-range-between-border-color: var(--color-background) !important; + --dp-hover-color: var(--color-form-background) !important; + --dp-background-color: var(--color-background-mute) !important; +} + +.dp__arrow_bottom { + background-color: var(--color-background-mute) !important; + color: var(--color-background-mute-font) !important; + border-color: var(--color-modal-background-inverted) !important; + --dp-range-between-dates-background-color: var(--color-background) !important; + --dp-range-between-border-color: var(--color-background) !important; + --dp-hover-color: var(--color-form-background) !important; + --dp-background-color: var(--color-background-mute) !important; +} + +.dp__input_icon, +.dp__clear_icon { + color: var(--color-background-font) !important; +} + +.page-item.disabled { + user-select: none; +} + +.btn { + user-select: none; +} + +.btn:hover { + cursor: pointer; +} + +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.5s; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +.fade-enter-to, +.fade-leave-from { + opacity: 1; +} + +.scrollable-filter { + height: 550px; + overflow-y: auto; + overflow-x: hidden; +} + +.page-of-pages { + text-align: center; +} + +.input-group:focus-within .input-group-text:not(:focus), +.form-check-input:focus, +.form-control:focus { + outline: none; + box-shadow: none; + border-color: var(--color-secondary-active); + transition: border-color 0.2s ease-in-out; +} + +.input-group .input-group-text, +.input-group-text:focus { + border-color: var(--color-modal-background-inverted); + transition: border-color 0.2s ease-in-out; +} +.form-control { + color: var(--color-background-font); + border-color: var(--color-border) +} +.form-control::placeholder { + color: #808080D0; +} + +select.form-control, +select#location { + appearance: none; + -webkit-appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,"); + background-repeat: no-repeat; + background-position: right 0.25rem center; + background-size: 1.25em; + padding-right: 2em; + transition: background 0.2s, border-color 0.2s; +} + +select.form-control:hover, +select#location:hover, +select.form-control:focus, +select#location:focus { + border-color: var(--color-secondary-active) +} + +select.form-control:focus, +select#location:focus { + box-shadow: 0 0 0 0.2rem rgba(134, 223, 195, 0.25); +} + +.btn-primary { + --bs-btn-color: var(--color-primary-font); + --bs-btn-bg: var(--color-primary); + --bs-btn-border-color: var(--color-primary); + --bs-btn-hover-color: var(--color-primary-font); + --bs-btn-hover-bg: var(--color-primary-hover); + --bs-btn-hover-border-color: var(--color-primary-hover); + --bs-btn-focus-shadow-rgb: 49, 132, 253; + --bs-btn-active-color: var(--color-primary-font); + --bs-btn-active-bg: var(--color-primary-active); + --bs-btn-active-border-color: var(--color-primary-active); + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: var(--color-primary-font); + --bs-btn-disabled-bg: var(--color-primary-disabled); + --bs-btn-disabled-border-color: var(--color-primary-disabled); +} + +.btn-secondary { + --bs-btn-color: var(--color-secondary-font); + --bs-btn-bg: var(--color-secondary); + --bs-btn-border-color: var(--color-secondary); + --bs-btn-hover-color: var(--color-secondary-font); + --bs-btn-hover-bg: var(--color-secondary-hover); + --bs-btn-hover-border-color: var(--color-secondary-hover); + --bs-btn-focus-shadow-rgb: 49, 132, 253; + --bs-btn-active-color: var(--color-secondary-font); + --bs-btn-active-bg: var(--color-secondary-active); + --bs-btn-active-border-color: var(--color-secondary-active); + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: var(--color-secondary-font); + --bs-btn-disabled-bg: var(--color-secondary-disabled); + --bs-btn-disabled-border-color: var(--color-secondary-disabled); +} + +.btn-danger { + --bs-btn-color: #fff; + --bs-btn-bg: #ad6060; + --bs-btn-border-color: #ad6060; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #935252; + --bs-btn-hover-border-color: #935252; + --bs-btn-focus-shadow-rgb: 225, 83, 97; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #794343; + --bs-btn-active-border-color: #794343; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #ad6060; + --bs-btn-disabled-border-color: #ad6060; +} + +.btn-link { + text-decoration: none !important; +} + +.btn-link, .routerLink { + color: var(--color-primary); +} + +.btn-link:hover, .routerLink:hover { + color: var(--color-primary-hover); +} + +.btn-link:active, .routerLink:active { + color: var(--color-primary-active); +} + +.btn-submit { + color: var(--color-primary-font); + border-color: var(--color-modal-background-inverted); + background-color: #86dfc3ff; +} + +.btn-submit:hover { + border-color: var(--color-modal-background-inverted); + background-color: #6ed1b0ff; +} + +.pagination { + --bs-pagination-padding-x: 0.75rem; + --bs-pagination-padding-y: 0.375rem; + --bs-pagination-font-size: 1rem; + --bs-pagination-color: var(--color-primary-font); + --bs-pagination-bg: var(--color-primary); + --bs-pagination-border-width: var(--bs-border-width); + --bs-pagination-border-color: var(--color-border); + --bs-pagination-border-radius: var(--bs-border-radius); + --bs-pagination-hover-color: var(--color-primary-font); + --bs-pagination-hover-bg: var(--color-primary-hover); + --bs-pagination-hover-border-color: var(--color-border); + --bs-pagination-focus-color: var(--color-primary-font); + --bs-pagination-focus-bg: var(--color-primary-hover); + --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.25); + --bs-pagination-active-color: var(--color-primary-font); + --bs-pagination-active-bg: var(--color-primary-active); + --bs-pagination-active-border-color: var(--color-border); + --bs-pagination-disabled-color: var(--color-background-font); + --bs-pagination-disabled-bg: var(--color-background-mute); + --bs-pagination-disabled-border-color: var(--color-border); + list-style: none; +} + +.progress { + --bs-progress-bar-bg: var(--color-primary, #7561a9); + --bs-progress-bg: var(--color-background-soft, #d8d8d8); + border: 1px solid var(--color-background-mute, #b9b9b9); +} + +.alert { + --bs-alert-border: 1px solid #ad6060; + --bs-alert-bg: #e4b6b6; +} + +.offcanvas-header { + background-color: var(--color-background); + color: var(--color-background-font); + box-shadow: var(--vt-c-black) 0, 0, 10px; +} + +.offcanvas-body { + background-color: var(--color-background); + color: var(--color-background-font); + position: relative; +} + +button:not(.btn-primary):not(.btn-secondary) i { + color: var(--color-nav-text-hover); +} + +button:not(.btn-primary):not(.btn-secondary):hover i { + color: var(--color-background-font); +} + +.ellipsis { + color: var(--color-background-font); +} + +.fade-tabs-enter-active, .fade-tabs-leave-active { + transition: opacity .5s; +} + +.fade-tabs-enter-from, .fade-tabs-leave-to { + opacity: 0; +} + +.fade-tabs-enter-to, .fade-tabs-leave-from { + opacity: 1; +} + +.modal { + position: relative; + max-width: 600px; + display: flex; + justify-content: center; + align-items: center; + z-index: 1050; +} + +.modal-fade { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + transition: background-color 1s ease; + z-index: 1000; +} \ No newline at end of file diff --git a/client/src/assets/img/scales-ph.jpg b/client/src/assets/img/scales-ph.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6103366923713c05a10372352f45a97b3f20461b GIT binary patch literal 37046 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 literal 0 HcmV?d00001 diff --git a/client/src/components/Navbar.vue b/client/src/components/Navbar.vue new file mode 100644 index 0000000..c81e665 --- /dev/null +++ b/client/src/components/Navbar.vue @@ -0,0 +1,186 @@ + + + + + \ No newline at end of file diff --git a/client/src/globals.ts b/client/src/globals.ts new file mode 100644 index 0000000..204320b --- /dev/null +++ b/client/src/globals.ts @@ -0,0 +1,19 @@ +import { ref } from "vue"; +import { useToast } from "vue-toast-notification"; + +const isMobile = ref(window.innerWidth <= 768); + +function updateIsMobile() {isMobile.value = window.innerWidth <= 768;} + +const routerTransitioning = ref(false); +const subTabTransitioning = ref(false); + +const toast = useToast({ + position: 'top-right', + duration: 5000, + dismissible: true, + pauseOnHover: true, + type: 'default', +}) + +export { isMobile, routerTransitioning, subTabTransitioning, updateIsMobile, toast }; diff --git a/client/src/main.ts b/client/src/main.ts new file mode 100644 index 0000000..449812e --- /dev/null +++ b/client/src/main.ts @@ -0,0 +1,28 @@ +import { createApp } from 'vue' +import '@css/base.css' +import '@css/style.css' +import App from '@/App.vue' +import router from "@/router"; +import { useToast } from "vue-toast-notification"; +import 'vue-toast-notification/dist/theme-bootstrap.css'; +import { session } from "@models/session.ts"; +import {jwtDecode} from 'jwt-decode'; +import type {SecureUser} from "@models/User.ts"; + +if (localStorage.getItem("token") && localStorage.getItem("username")) { + const decode: SecureUser = jwtDecode(localStorage.getItem("token") || ""); + session.user = { + username: localStorage.getItem("username") || "", + token: localStorage.getItem("token") || "", + role: decode?.role || "user" + }; + session.token = localStorage.getItem("token"); + +} + +createApp(App) + .use(router) + .use(useToast) + .mount('#app') + + diff --git a/client/src/models/TransferTypes.ts b/client/src/models/TransferTypes.ts new file mode 100644 index 0000000..c6e06e4 --- /dev/null +++ b/client/src/models/TransferTypes.ts @@ -0,0 +1,12 @@ +export interface DataEnvelope { + data: T; + message?: string; + error?: Error; +} +export interface DataListEnvelope extends DataEnvelope{ + data: T[]; + totalItems?: number; + pageLimit?: number; +} + +export type DynamicDataEnvelope = T extends (infer U)[] ? DataListEnvelope : DataEnvelope; \ No newline at end of file diff --git a/client/src/models/User.ts b/client/src/models/User.ts new file mode 100644 index 0000000..20b65c2 --- /dev/null +++ b/client/src/models/User.ts @@ -0,0 +1,6 @@ +export interface SecureUser { + username: string; + role?: string; + id?: number; + token?: string; +} \ No newline at end of file diff --git a/client/src/models/rest.ts b/client/src/models/rest.ts new file mode 100644 index 0000000..fcaf371 --- /dev/null +++ b/client/src/models/rest.ts @@ -0,0 +1,30 @@ +import type {DynamicDataEnvelope} from "@models/TransferTypes.ts"; + +export const API_ROOT = import.meta.env.VITE_API_ROOT; + +async function rest(url: string, body?: unknown, method?: string, headers?: HeadersInit) { + const isFormData = body instanceof FormData; + const options: RequestInit = { + method: method ?? (body ? "POST" : "GET"), + headers: { + ...headers + }, + body: isFormData ? body : JSON.stringify(body) + }; + + if (!isFormData) { + options.headers = options.headers || {}; + (options.headers as Record)['Content-Type'] = 'application/json'; + } + + return await fetch(url, options) + .then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err))) + .catch(err => Promise.reject(err)); +} + +export async function api(action: string, body?: unknown, method?: string, headers?: HeadersInit) { + return rest(`${API_ROOT}${action}`, body, method, headers).then(data => { + if (data && typeof data === 'object' && 'data' in data) return data as DynamicDataEnvelope; + else throw new Error("Invalid response format"); + }) as Promise>; +} \ No newline at end of file diff --git a/client/src/models/session.ts b/client/src/models/session.ts new file mode 100644 index 0000000..30a1e34 --- /dev/null +++ b/client/src/models/session.ts @@ -0,0 +1,65 @@ +import {reactive} from "vue"; +import {useRouter} from "vue-router"; +import {toast} from "@/globals.ts"; +import { type DataEnvelope } from "./TransferTypes"; +import {api} from "@models/rest.ts"; +import type { SecureUser } from "@models/User.ts"; + +export const session = reactive({ + user: null as SecureUser | null, + token: null as string | null, + redirectURL: null as string | null, + messages: [] as { + type: string, + message: string + }[], +}); + +export function useLogin() { + const router = useRouter(); + return { + async login(username: string, password: string): Promise { + return await api("/api/auth", {username, password}, "POST") + .then((response: DataEnvelope ) => { + session.user = response.data; + if (!session.user) throw new Error("Invalid login credentials. Please try again."); + session.token = response.data.token || null; + router.push(session.redirectURL ?? "/").then((r) => r); + session.redirectURL = null; + toast.success("Welcome " + session.user.username + "!\nYou are now logged in."); + localStorage.setItem("username", session.user.username); + localStorage.setItem("token", session.token ?? ""); + return session.user; + }) + .catch((err)=>{throw err}) as SecureUser; + }, + async logout(): Promise { + session.user = null; + session.token = null; + localStorage.removeItem("token"); + localStorage.removeItem("username"); + for(let i = 0; i < session.messages.length; i++) { + console.debug("Messages: "); + if(session.messages[i].type === "error") { + console.error(session.messages[i].message); + } else { + console.debug(session.messages[i].message); + } + } + router.push('/').then((r) => r); + } + } +} + +export function handleExpiredToken(err: Error): Promise { + if (err.message === 'jwt expired') { + session.token = null; + session.user = null; + localStorage.removeItem('token'); + localStorage.removeItem('username'); + toast.error("Your session has expired. Please log in again."); + const router = useRouter(); + router.push('/login').then((r) => r); + } + return Promise.reject(err) +} \ No newline at end of file diff --git a/client/src/router/index.ts b/client/src/router/index.ts new file mode 100644 index 0000000..63ec621 --- /dev/null +++ b/client/src/router/index.ts @@ -0,0 +1,69 @@ +import {createRouter, createWebHashHistory} from 'vue-router' +import MainPage from '@views/MainPage.vue' +import NotFoundPage from "@views/NotFoundPage.vue"; + +import {session} from '@models/session.ts'; +import { toast } from '@/globals.ts'; +import {jwtDecode} from 'jwt-decode'; + +const routes = [ + { + path: '/', + name: 'MainPage', + component: MainPage, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFoundPage + } +] + +const router = createRouter({ + history: createWebHashHistory(), + routes +}) + +router.beforeEach((to, from, next) => { + if (to.meta.requiresAuth) { + const token = session.token ?? localStorage.getItem('token'); + if (!token) { + session.redirectURL = to.fullPath; // Save the intended route + return next("Login"); + } + try { + const decoded: any = jwtDecode(token); + if( !decoded ) { + toast.error("Invalid token. Please log in again."); + session.token = null; + localStorage.removeItem('token'); + session.user = null; + localStorage.removeItem('username'); + return next("Login"); + } + if (decoded.exp * 1000 < Date.now()) { + toast.error("Token expired. Please log in again."); + session.token = null; + localStorage.removeItem('token'); + session.user = null; + localStorage.removeItem('username'); + return next("Login"); + } + if (decoded.role === 'admin') { + return next(); + } else if (decoded.role === 'user') { + toast.error("You do not have permission to access this page."); + return from.fullPath; + } + else { + return next({name: 'NotFound'}); + } + } catch (e) { + return next({name: 'NotFound'}); + } + } + next(); +}); + + +export default router \ No newline at end of file diff --git a/client/src/views/MainPage.vue b/client/src/views/MainPage.vue new file mode 100644 index 0000000..79ac4a9 --- /dev/null +++ b/client/src/views/MainPage.vue @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/client/src/views/NotFoundPage.vue b/client/src/views/NotFoundPage.vue new file mode 100644 index 0000000..96c0baf --- /dev/null +++ b/client/src/views/NotFoundPage.vue @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/client/src/vite-env.d.ts b/client/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/client/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json new file mode 100644 index 0000000..9da629d --- /dev/null +++ b/client/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + /* Aliases */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@assets/*": ["src/assets/*"], + "@css/*": ["src/assets/css/*"], + "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], + "@router/*": ["src/router/*"], + "@img/*": ["src/assets/img/*"], + "@models/*": ["src/models/*"], + "@stores/*": ["src/stores/*"], + "@views/*": ["src/views/*"] + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue" + ] +} diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/client/tsconfig.node.json b/client/tsconfig.node.json new file mode 100644 index 0000000..6a3f49a --- /dev/null +++ b/client/tsconfig.node.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": [ + "ES2023" + ], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + }, + "include": [ + "vite.config.ts" + ] +} diff --git a/client/vite.config.ts b/client/vite.config.ts new file mode 100644 index 0000000..ed93156 --- /dev/null +++ b/client/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vite.dev/config/ +export default defineConfig({ + resolve: { + alias: { + '@': '/src', + '@assets': '/src/assets', + '@css': '/src/assets/css', + '@components': '/src/components', + '@globals': '/src/globals', + '@img': '/src/assets/img', + '@layouts': '/src/layouts', + '@models': '/src/models', + '@router': '/src/router', + '@stores': '/src/stores', + '@views': '/src/views', + }, + }, + plugins: [vue()], +})