commit 15b2ecd1d23dc568bec4633d5bcb967dfc4779b3 Author: safavimohadeseh78 Date: Sat Aug 1 10:52:38 2026 +0200 Initial commit: Vue 3 Gold Land frontend Co-authored-by: Cursor diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..218c513 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Dependencies & build output +node_modules +dist +dist-ssr +coverage +*.local + +# Editor +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo +.eslintcache + +# Vite +*.timestamp-*-*.mjs +.vite + +# Env secrets +.env +.env.* +!.env.example diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7321e5 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Child Gold Land — Frontend + +رابط کاربری Vue 3 + Vite + Pinia. + +## راه‌اندازی + +```sh +npm install +npm run dev +``` + +## اسکریپت‌ها + +| دستور | توضیح | +|--------|--------| +| `npm run dev` | سرور توسعه | +| `npm run build` | بیلد production | +| `npm run preview` | پیش‌نمایش بیلد | +| `npm run type-check` | بررسی TypeScript | diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..d96c1cf --- /dev/null +++ b/env.d.ts @@ -0,0 +1,19 @@ +/// + +interface ImportMetaEnv { + readonly VITE_API_URL?: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} + +declare module '*.svg' { + const src: string + export default src +} + +declare module '*.png' { + const src: string + export default src +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..5a5ce4e --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + هوش مالی + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7904a9b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2854 @@ +{ + "name": "child-gold-land", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "child-gold-land", + "version": "0.0.0", + "dependencies": { + "@fontsource/vazirmatn": "^5.2.5", + "chart.js": "^4.4.9", + "lucide-vue-next": "^0.511.0", + "pinia": "^3.0.2", + "vue": "^3.5.40", + "vue-chartjs": "^5.3.2", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.4", + "@types/node": "^24.13.3", + "@vitejs/plugin-vue": "^6.0.8", + "@vue/tsconfig": "^0.9.1", + "npm-run-all2": "^9.0.2", + "typescript": "~6.0.0", + "vite": "^8.1.5", + "vite-plugin-vue-devtools": "^8.1.5", + "vue-tsc": "^3.3.7" + }, + "engines": { + "node": "^22.18.0 || >=24.12.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", + "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-decorators": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", + "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.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/@fontsource/vazirmatn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/vazirmatn/-/vazirmatn-5.3.0.tgz", + "integrity": "sha512-XC/2yN2r5gwhFT3klSuWaqncODX2DOfRYfNmbyzgtWYxHxMC+tcoaX+tgggrm6hSkEgpR1TuSDEf1PiI91G7qg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "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.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "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.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "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.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "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/@tsconfig/node24": { + "version": "24.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node24/-/node24-24.0.4.tgz", + "integrity": "sha512-2A933l5P5oCbv6qSxHs7ckKwobs8BDAe9SJ/Xr2Hy+nDlwmLE1GhFh/g/vXGRZWgxBg9nX/5piDtHR9Dkw/XuA==", + "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.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz", + "integrity": "sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.40.tgz", + "integrity": "sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.40", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.40.tgz", + "integrity": "sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.40", + "@vue/shared": "3.5.40" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.40.tgz", + "integrity": "sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.40", + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-ssr": "3.5.40", + "@vue/shared": "3.5.40", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.19", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.40.tgz", + "integrity": "sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.40", + "@vue/shared": "3.5.40" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", + "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.10" + } + }, + "node_modules/@vue/devtools-api/node_modules/@vue/devtools-kit": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz", + "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.10", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-api/node_modules/@vue/devtools-shared": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz", + "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/devtools-api/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/@vue/devtools-core": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.1.5.tgz", + "integrity": "sha512-5e5jQOEssCdZA1wlFEUkIDtb+cAOWuLNWJ52fm4PBWbF7e3oTnM2fneaL42E5lJoolAaUQ678tv/XEb3h4e86Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.1.5", + "@vue/devtools-shared": "^8.1.5" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.5.tgz", + "integrity": "sha512-FcSAxsi4eWuXLCB7Rv9lj0aIVHHPNVQ2BazGf4RJTc2JCqb4BQg0hk87ZFhminCfl+mD5OUI0rX2cgyu4kJOGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.1.5", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.5.tgz", + "integrity": "sha512-mhT4zcPFhF+Xk1O4BfhhrbXzpmfqY03fS6xGpcllbQG7lDjhQf8pQHcTIhqQIYx1hfwtHmk/6jM96ele0UxPqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.7.tgz", + "integrity": "sha512-LzmkKinXAMMoh8Jfi/jMUSDUjuPdv8mynH5WJGKfXyZtDw3hQ6GBaoI6Bcnl/Xqlu32q/0Z6i/trp4VXykzyLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.2.1", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.4" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.40.tgz", + "integrity": "sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.40" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.40.tgz", + "integrity": "sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.40", + "@vue/shared": "3.5.40" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.40.tgz", + "integrity": "sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.40", + "@vue/runtime-core": "3.5.40", + "@vue/shared": "3.5.40", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.40.tgz", + "integrity": "sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/shared": "3.5.40" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.40.tgz", + "integrity": "sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==", + "license": "MIT" + }, + "node_modules/@vue/tsconfig": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.9.1.tgz", + "integrity": "sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 5.8", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.0.tgz", + "integrity": "sha512-oCu2wfipvX3AePSgmOuKkIywOu+8n9psz7hXYmk56ghpu3+7KzNIBopaOs4c9BrtdnTtW30unG9GTfHo7EwERQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/electron-to-chromium": { + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=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.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/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-6.0.0.tgz", + "integrity": "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "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.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "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-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "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-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "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-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "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-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "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/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-vue-next": { + "version": "0.511.0", + "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.511.0.tgz", + "integrity": "sha512-VSv0F3pHniGN7JMMzDcLFNMQbl8381+shNnHwV8hi+El7xl2ZL8qdNuzPoiBViKk8mTKK5K3ZDfmE/wEcTZVIQ==", + "deprecated": "Package deprecated. Please use @lucide/vue instead.", + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "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.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "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/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-6.0.0.tgz", + "integrity": "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-9.0.2.tgz", + "integrity": "sha512-+dd4SO2jAlLE06OzmJKzIe6QvvjXezcbmobnh8usR0a8BzQCABTdqTXqVPji0ICOhSQpIIrkGd7IzNl5iDaRSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "picomatch": "^4.0.2", + "pidtree": "^1.0.0", + "read-package-json-fast": "^6.0.0", + "shell-quote": "^1.8.4", + "which": "^7.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0", + "npm": ">= 10" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "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.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-1.0.0.tgz", + "integrity": "sha512-avfAvjB9Dd0wdj3rjJX//yS+G79OO0KrS5pJHFJENjYGX6N4SMgEDBBI/yFy0lloOYSaC6XQxzpOAMPfSYFV/Q==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pinia": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", + "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^7.7.7" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.5.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.21.tgz", + "integrity": "sha512-v4sDNP3fdNiWMfabO7OwOQdOX8TiQSztKyT1Wj0w+j7LDallJThJRBBBmzVGyYj0crMh7jlV4zepPkiNu9UwDQ==", + "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.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-package-json-fast": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-6.0.0.tgz", + "integrity": "sha512-PNaGjoCnw9DBA2Kl8D+8po957z778q/HOPuY2u3Bkw/JO3eC8MDx7jn/PgMtSgpcBbs+6UOjDbwReGpXmRvs0g==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^6.0.0", + "npm-normalize-package-bin": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.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.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "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/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "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/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "devOptional": 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/unplugin-utils": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.2.tgz", + "integrity": "sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "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 + } + } + }, + "node_modules/vite-dev-rpc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz", + "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==", + "dev": true, + "license": "MIT", + "dependencies": { + "birpc": "^4.0.0", + "vite-hot-client": "^2.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-dev-rpc/node_modules/birpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz", + "integrity": "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vite-hot-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.2.0.tgz", + "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz", + "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.3.0", + "error-stack-parser-es": "^1.0.5", + "obug": "^2.1.1", + "ohash": "^2.0.11", + "open": "^11.0.0", + "perfect-debounce": "^2.1.0", + "sirv": "^3.0.2", + "unplugin-utils": "^0.3.1", + "vite-dev-rpc": "^2.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-vue-devtools": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.1.5.tgz", + "integrity": "sha512-QSVntSN0sbVV08CZntMWOfF8McyPyYyYd19sChLjxYyFCC7Fcpey74ztw1uCCU23wTmR2yWPb92uaxVD4Lw0Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-core": "^8.1.5", + "@vue/devtools-kit": "^8.1.5", + "@vue/devtools-shared": "^8.1.5", + "sirv": "^3.0.2", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-vue-inspector": "^6.0.0" + }, + "engines": { + "node": ">=v14.21.3" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/vite-plugin-vue-inspector": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-6.0.0.tgz", + "integrity": "sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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.40", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.40.tgz", + "integrity": "sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-sfc": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/server-renderer": "3.5.40", + "@vue/shared": "3.5.40" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-chartjs": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.4.tgz", + "integrity": "sha512-x3Fqob8RQvrTdssfi9ecsCzEkFOd8JPmNwSkSQzdfKj/uBsRJs/Y88cZcZIEcPsTVfMGwMo4MOoihoDG2DoE/g==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "vue": "^3.0.0-0 || ^2.7.0" + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-router/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-tsc": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.7.tgz", + "integrity": "sha512-+C+rgD49wAQ5bUTl2sp5a8Bzg4YoldMNXM+g7CFe604MYcQ8PrZPMQhIjJSzKXtPBCa+C5ayMipqjbA7splekQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.7" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/which": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-7.0.0.tgz", + "integrity": "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..12d7f84 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "child-gold-land", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build" + }, + "dependencies": { + "@fontsource/vazirmatn": "^5.2.5", + "chart.js": "^4.4.9", + "lucide-vue-next": "^0.511.0", + "pinia": "^3.0.2", + "vue": "^3.5.40", + "vue-chartjs": "^5.3.2", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.4", + "@types/node": "^24.13.3", + "@vitejs/plugin-vue": "^6.0.8", + "@vue/tsconfig": "^0.9.1", + "npm-run-all2": "^9.0.2", + "typescript": "~6.0.0", + "vite": "^8.1.5", + "vite-plugin-vue-devtools": "^8.1.5", + "vue-tsc": "^3.3.7" + }, + "engines": { + "node": "^22.18.0 || >=24.12.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/public/favicon.ico differ diff --git a/scripts/remove-avatar-bg.mjs b/scripts/remove-avatar-bg.mjs new file mode 100644 index 0000000..3fcff10 --- /dev/null +++ b/scripts/remove-avatar-bg.mjs @@ -0,0 +1,36 @@ +import sharp from 'sharp' +import { writeFileSync } from 'fs' +import { fileURLToPath } from 'url' +import { dirname, join } from 'path' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const input = join(__dirname, '../src/assets/profile/avatar.png') + +const { data, info } = await sharp(input) + .ensureAlpha() + .raw() + .toBuffer({ resolveWithObject: true }) + +for (let i = 0; i < data.length; i += 4) { + const r = data[i] + const g = data[i + 1] + const b = data[i + 2] + const sum = r + g + b + + const isBlack = sum < 55 + const isNavy = b > r + 8 && b > g + 2 && sum < 140 + const isDarkBlueBg = b > 15 && r < 35 && g < 45 && b < 90 && sum < 100 + + if (isBlack || isNavy || isDarkBlueBg) { + data[i + 3] = 0 + } +} + +const output = await sharp(data, { + raw: { width: info.width, height: info.height, channels: 4 }, +}) + .png() + .toBuffer() + +writeFileSync(input, output) +console.log('Done:', info.width, 'x', info.height) diff --git a/scripts/remove-castle-bg.mjs b/scripts/remove-castle-bg.mjs new file mode 100644 index 0000000..be47f0e --- /dev/null +++ b/scripts/remove-castle-bg.mjs @@ -0,0 +1,113 @@ +import sharp from "sharp"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const target = join(__dirname, "..", "src", "assets", "icons", "castle-gold-land.png"); + +/** Near-black threshold: R+G+B <= this counts as background candidate */ +const NEAR_BLACK = 40; +/** Soften: fade alpha within this distance (px) of flood-filled region */ +const SOFT_RADIUS = 2; + +const { data, info } = await sharp(target) + .ensureAlpha() + .raw() + .toBuffer({ resolveWithObject: true }); + +const { width: w, height: h } = info; +const n = w * h; +const out = Buffer.from(data); +const bg = new Uint8Array(n); // 1 = background to remove + +const isNearBlack = (i) => { + const o = i * 4; + return out[o] + out[o + 1] + out[o + 2] <= NEAR_BLACK; +}; + +const queue = []; +const push = (x, y) => { + const i = y * w + x; + if (bg[i]) return; + if (!isNearBlack(i)) return; + bg[i] = 1; + queue.push(i); +}; + +// Seed BFS from all border pixels that are near-black +for (let x = 0; x < w; x++) { + push(x, 0); + push(x, h - 1); +} +for (let y = 0; y < h; y++) { + push(0, y); + push(w - 1, y); +} + +// Flood-fill only connected near-black from edges (internal dark windows stay) +const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], +]; +let qh = 0; +while (qh < queue.length) { + const i = queue[qh++]; + const x = i % w; + const y = (i / w) | 0; + for (const [dx, dy] of dirs) { + const nx = x + dx; + const ny = y + dy; + if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue; + push(nx, ny); + } +} + +// Soften edges: for non-bg pixels near bg, reduce alpha by proximity +const soft = new Float32Array(n); +for (let i = 0; i < n; i++) { + if (bg[i]) { + soft[i] = 0; + continue; + } + const x = i % w; + const y = (i / w) | 0; + let minD = SOFT_RADIUS + 1; + for (let dy = -SOFT_RADIUS; dy <= SOFT_RADIUS; dy++) { + for (let dx = -SOFT_RADIUS; dx <= SOFT_RADIUS; dx++) { + const nx = x + dx; + const ny = y + dy; + if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue; + const j = ny * w + nx; + if (!bg[j]) continue; + const d = Math.hypot(dx, dy); + if (d < minD) minD = d; + } + } + if (minD <= SOFT_RADIUS) { + soft[i] = minD / (SOFT_RADIUS + 0.001); + } else { + soft[i] = 1; + } +} + +let removed = 0; +for (let i = 0; i < n; i++) { + const a = i * 4 + 3; + if (bg[i]) { + out[a] = 0; + removed++; + } else if (soft[i] < 1) { + out[a] = Math.round(out[a] * soft[i]); + } +} + +await sharp(out, { + raw: { width: w, height: h, channels: 4 }, +}) + .png() + .toFile(target); + +console.log(`Wrote ${target}`); +console.log(`Removed ${removed} background pixels (edge flood-fill); soft radius=${SOFT_RADIUS}`); diff --git a/scripts/remove-treasure-bg.mjs b/scripts/remove-treasure-bg.mjs new file mode 100644 index 0000000..9d78bd9 --- /dev/null +++ b/scripts/remove-treasure-bg.mjs @@ -0,0 +1,131 @@ +import sharp from "sharp"; +import { spawnSync } from "node:child_process"; +import { dirname, join } from "node:path"; +import { tmpdir } from "node:os"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const target = join(__dirname, "..", "src", "assets", "illustrations", "treasure-chest.png"); +const tempOut = join(tmpdir(), "treasure-chest-out.png"); + +/** Near-black threshold: R+G+B <= this counts as background candidate */ +const NEAR_BLACK = 40; +/** Soften: fade alpha within this distance (px) of flood-filled region */ +const SOFT_RADIUS = 2; + +const { data, info } = await sharp(target) + .ensureAlpha() + .raw() + .toBuffer({ resolveWithObject: true }); + +const { width: w, height: h } = info; +const n = w * h; +const out = Buffer.from(data); +const bg = new Uint8Array(n); // 1 = background to remove + +const isNearBlack = (i) => { + const o = i * 4; + return out[o] + out[o + 1] + out[o + 2] <= NEAR_BLACK; +}; + +const queue = []; +const push = (x, y) => { + const i = y * w + x; + if (bg[i]) return; + if (!isNearBlack(i)) return; + bg[i] = 1; + queue.push(i); +}; + +// Seed BFS from all border pixels that are near-black +for (let x = 0; x < w; x++) { + push(x, 0); + push(x, h - 1); +} +for (let y = 0; y < h; y++) { + push(0, y); + push(w - 1, y); +} + +// Flood-fill only connected near-black from edges (internal dark chest parts stay) +const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], +]; +let qh = 0; +while (qh < queue.length) { + const i = queue[qh++]; + const x = i % w; + const y = (i / w) | 0; + for (const [dx, dy] of dirs) { + const nx = x + dx; + const ny = y + dy; + if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue; + push(nx, ny); + } +} + +// Soften edges: for non-bg pixels near bg, reduce alpha by proximity +const soft = new Float32Array(n); +for (let i = 0; i < n; i++) { + if (bg[i]) { + soft[i] = 0; + continue; + } + const x = i % w; + const y = (i / w) | 0; + let minD = SOFT_RADIUS + 1; + for (let dy = -SOFT_RADIUS; dy <= SOFT_RADIUS; dy++) { + for (let dx = -SOFT_RADIUS; dx <= SOFT_RADIUS; dx++) { + const nx = x + dx; + const ny = y + dy; + if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue; + const j = ny * w + nx; + if (!bg[j]) continue; + const d = Math.hypot(dx, dy); + if (d < minD) minD = d; + } + } + if (minD <= SOFT_RADIUS) { + soft[i] = minD / (SOFT_RADIUS + 0.001); + } else { + soft[i] = 1; + } +} + +let removed = 0; +for (let i = 0; i < n; i++) { + const a = i * 4 + 3; + if (bg[i]) { + out[a] = 0; + removed++; + } else if (soft[i] < 1) { + out[a] = Math.round(out[a] * soft[i]); + } +} + +// Write via ASCII temp path — Node/libvips can fail writing Unicode apostrophe paths on Windows +await sharp(out, { + raw: { width: w, height: h, channels: 4 }, +}) + .png() + .toFile(tempOut); + +const ps = spawnSync( + "powershell.exe", + [ + "-NoProfile", + "-Command", + `Copy-Item -LiteralPath '${tempOut.replace(/'/g, "''")}' -Destination '${target.replace(/'/g, "''")}' -Force`, + ], + { encoding: "utf8" }, +); +if (ps.status !== 0) { + console.error(ps.stderr || ps.stdout); + process.exit(ps.status ?? 1); +} + +console.log(`Wrote ${target}`); +console.log(`Removed ${removed} background pixels (edge flood-fill); soft radius=${SOFT_RADIUS}`); diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..4bf5099 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/api/bootstrapState.ts b/src/api/bootstrapState.ts new file mode 100644 index 0000000..7ce8529 --- /dev/null +++ b/src/api/bootstrapState.ts @@ -0,0 +1,13 @@ +let bootstrapped = false + +export function isAppBootstrapped() { + return bootstrapped +} + +export function markAppBootstrapped() { + bootstrapped = true +} + +export function resetAppBootstrap() { + bootstrapped = false +} diff --git a/src/api/client.ts b/src/api/client.ts new file mode 100644 index 0000000..3f34f35 --- /dev/null +++ b/src/api/client.ts @@ -0,0 +1,204 @@ +const TOKEN_KEY = 'gold-land-auth-token' + +let authToken: string | null = null + +export function getAuthToken(): string | null { + if (authToken) return authToken + try { + return localStorage.getItem(TOKEN_KEY) + } catch { + return null + } +} + +export function setAuthToken(token: string | null) { + authToken = token + try { + if (token) localStorage.setItem(TOKEN_KEY, token) + else localStorage.removeItem(TOKEN_KEY) + } catch { + // ignore + } +} + +export interface AuthResponse { + token: string + user: { + id: string + name: string + username: string + } + me: import('./client').MeResponse +} + +export interface MeResponse { + user: { + id: string + name: string + level: number + xp: number + maxXp: number + coins: number + missionProgress: number + missionTarget: number + } + wallet: { + cash: number + goldGrams: number + } + progress: { + completedChallenges: string[] + completedLessons: string[] + completedGames: string[] + claimedRewards: string[] + ownedItems: string[] + mapLevels: Array<{ + id: number + title: string + stars: number + maxStars: number + status: 'completed' | 'current' | 'unlocked' | 'locked' + lessonRoute?: string + x: number + y: number + }> + totalStars: number + maxStars: number + } + achievements: Array<{ + id: string + title: string + description: string + icon: string + unlocked: boolean + }> + transactions: Array<{ + id: string + type: 'income' | 'expense' + title: string + amount: number + unit: 'تومان' | 'سکه' | 'گرم' + date: string + }> + market: { + selectedRange: '1d' | '7d' | '30d' | '90d' | '1y' + } +} + +export interface MarketGoldResponse { + currentPrice: number + dailyChangePercent: number + range: string + history: number[] + updatedAt: string +} + +export interface DailyChallengeResponse { + id: string + question: string + coinReward: number + xpReward: number + completed: boolean + options: Array<{ id: string; label: string; icon: string; color: string }> +} + +export interface DailyChallengeCompleteResponse extends MeResponse { + feedback: string + alreadyCompleted: boolean +} + +const API_BASE = import.meta.env.VITE_API_URL ?? '/api' + +async function request(path: string, init?: RequestInit): Promise { + const headers: Record = { + 'Content-Type': 'application/json', + ...(init?.headers as Record | undefined), + } + + const token = getAuthToken() + if (token) headers.Authorization = `Bearer ${token}` + + let response: Response + try { + response = await fetch(`${API_BASE}${path}`, { + ...init, + headers, + }) + } catch { + throw new Error('اتصال به سرور برقرار نشد. لطفاً backend را اجرا کنید.') + } + + if (!response.ok) { + const body = await response.json().catch(() => ({ error: 'خطای سرور' })) + throw new Error(body.error ?? 'خطای سرور') + } + + return response.json() as Promise +} + +export const api = { + login: (username: string, password: string) => + request('/auth/login', { + method: 'POST', + body: JSON.stringify({ username, password }), + }), + register: (username: string, password: string, name?: string) => + request('/auth/register', { + method: 'POST', + body: JSON.stringify({ username, password, name }), + }), + getMe: () => request('/me'), + updateProfile: (name: string) => + request('/me/profile', { method: 'PATCH', body: JSON.stringify({ name }) }), + updatePassword: (currentPassword: string, newPassword: string) => + request<{ ok: true }>('/me/password', { + method: 'PATCH', + body: JSON.stringify({ currentPassword, newPassword }), + }), + buyGold: (grams: number) => + request('/wallet/gold/buy', { method: 'POST', body: JSON.stringify({ grams }) }), + sellGold: (grams: number) => + request('/wallet/gold/sell', { method: 'POST', body: JSON.stringify({ grams }) }), + getMarketGold: (range: string) => request(`/market/gold?range=${range}`), + setMarketRange: (range: MeResponse['market']['selectedRange']) => + request('/market/preferences', { method: 'PATCH', body: JSON.stringify({ range }) }), + getDailyChallenge: () => request('/challenges/daily'), + completeDailyChallenge: (optionId: string) => + request('/challenges/daily/complete', { + method: 'POST', + body: JSON.stringify({ optionId }), + }), + completeGame: (gameId: string) => + request(`/games/${gameId}/complete`, { method: 'POST', body: '{}' }), + purchaseProduct: (productId: string) => + request('/store/purchases', { method: 'POST', body: JSON.stringify({ productId }) }), + completeLesson: (lessonId: string) => + request(`/lessons/${lessonId}/complete`, { method: 'POST', body: '{}' }), + completeMapLevel: (levelId: number, stars: number) => + request(`/map/levels/${levelId}/complete`, { + method: 'POST', + body: JSON.stringify({ stars }), + }), + getGoldLandProgress: () => request('/gold-land/progress'), + getGoldLandLevel: (levelId: number) => + request( + `/gold-land/levels/${levelId}`, + ), + startGoldLandLevel: (levelId: number) => + request<{ levelId: number; status: string }>(`/gold-land/levels/${levelId}/start`, { + method: 'POST', + body: '{}', + }), + completeGoldLandLevel: ( + levelId: number, + answers: import('@/modules/gold-land/types/goldLand.types').LessonSubmissionAnswer[], + durationMs?: number, + ) => + request( + `/gold-land/levels/${levelId}/complete`, + { + method: 'POST', + body: JSON.stringify({ answers, durationMs }), + }, + ), +} diff --git a/src/api/sync.ts b/src/api/sync.ts new file mode 100644 index 0000000..6cd060a --- /dev/null +++ b/src/api/sync.ts @@ -0,0 +1,63 @@ +import { api, type MeResponse } from '@/api/client' +import { useGamesStore } from '@/stores/games' +import { useMarketStore } from '@/stores/market' +import { useUserStore } from '@/stores/user' +import { useWalletStore } from '@/stores/wallet' + +export function applyMeResponse(data: MeResponse) { + const userStore = useUserStore() + const walletStore = useWalletStore() + const gamesStore = useGamesStore() + const marketStore = useMarketStore() + + userStore.$patch({ + name: data.user.name, + level: data.user.level, + xp: data.user.xp, + maxXp: data.user.maxXp, + coins: data.user.coins, + missionProgress: data.user.missionProgress, + missionTarget: data.user.missionTarget, + completedChallenges: [...data.progress.completedChallenges], + completedLessons: [...data.progress.completedLessons], + achievements: data.achievements.map((a) => ({ ...a })), + }) + + walletStore.$patch({ + cash: data.wallet.cash, + goldGrams: data.wallet.goldGrams, + transactions: data.transactions.map((t) => ({ ...t })), + }) + + gamesStore.$patch({ + completedGames: [...data.progress.completedGames], + claimedRewards: [...data.progress.claimedRewards], + ownedItems: [...data.progress.ownedItems], + mapLevels: data.progress.mapLevels.map((l) => ({ ...l })), + totalStars: data.progress.totalStars, + maxStars: data.progress.maxStars, + }) + + marketStore.$patch({ + selectedRange: data.market.selectedRange, + }) +} + +export async function bootstrapFromServer() { + const data = await api.getMe() + applyMeResponse(data) + return data +} + +export async function syncMarketQuote(range: string) { + const marketStore = useMarketStore() + const quote = await api.getMarketGold(range) + marketStore.$patch({ + currentPrice: quote.currentPrice, + dailyChange: quote.dailyChangePercent, + priceHistoryCache: { + ...marketStore.priceHistoryCache, + [quote.range]: quote.history, + }, + }) +} diff --git a/src/assets/icons/castle-gold-land.png b/src/assets/icons/castle-gold-land.png new file mode 100644 index 0000000..09b2703 Binary files /dev/null and b/src/assets/icons/castle-gold-land.png differ diff --git a/src/assets/icons/castle-nav.svg b/src/assets/icons/castle-nav.svg new file mode 100644 index 0000000..6036eb0 --- /dev/null +++ b/src/assets/icons/castle-nav.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/profile/index.ts b/src/assets/icons/profile/index.ts new file mode 100644 index 0000000..f73510d --- /dev/null +++ b/src/assets/icons/profile/index.ts @@ -0,0 +1,11 @@ +import menuTrophy from './menu-trophy.svg' +import menuFriends from './menu-friends.svg' +import menuSettings from './menu-settings.svg' +import menuLogout from './menu-logout.svg' + +export const profileMenuIcons = { + achievements: menuTrophy, + friends: menuFriends, + settings: menuSettings, + logout: menuLogout, +} as const diff --git a/src/assets/icons/profile/menu-friends.svg b/src/assets/icons/profile/menu-friends.svg new file mode 100644 index 0000000..ff616ed --- /dev/null +++ b/src/assets/icons/profile/menu-friends.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/profile/menu-logout.svg b/src/assets/icons/profile/menu-logout.svg new file mode 100644 index 0000000..cda4e52 --- /dev/null +++ b/src/assets/icons/profile/menu-logout.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/icons/profile/menu-settings.svg b/src/assets/icons/profile/menu-settings.svg new file mode 100644 index 0000000..440599c --- /dev/null +++ b/src/assets/icons/profile/menu-settings.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/profile/menu-trophy.svg b/src/assets/icons/profile/menu-trophy.svg new file mode 100644 index 0000000..e8aa4e0 --- /dev/null +++ b/src/assets/icons/profile/menu-trophy.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/illustrations/bank-building.png b/src/assets/illustrations/bank-building.png new file mode 100644 index 0000000..ee9d0af Binary files /dev/null and b/src/assets/illustrations/bank-building.png differ diff --git a/src/assets/illustrations/bank-building.svg b/src/assets/illustrations/bank-building.svg new file mode 100644 index 0000000..a0e741a --- /dev/null +++ b/src/assets/illustrations/bank-building.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/illustrations/cart-icon.png b/src/assets/illustrations/cart-icon.png new file mode 100644 index 0000000..67e93f1 Binary files /dev/null and b/src/assets/illustrations/cart-icon.png differ diff --git a/src/assets/illustrations/cash-bundle.png b/src/assets/illustrations/cash-bundle.png new file mode 100644 index 0000000..7b413f8 Binary files /dev/null and b/src/assets/illustrations/cash-bundle.png differ diff --git a/src/assets/illustrations/cash-bundle.svg b/src/assets/illustrations/cash-bundle.svg new file mode 100644 index 0000000..2edd051 --- /dev/null +++ b/src/assets/illustrations/cash-bundle.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/illustrations/challenge-banner.png b/src/assets/illustrations/challenge-banner.png new file mode 100644 index 0000000..32b4b6b Binary files /dev/null and b/src/assets/illustrations/challenge-banner.png differ diff --git a/src/assets/illustrations/coin-large.png b/src/assets/illustrations/coin-large.png new file mode 100644 index 0000000..d13d459 Binary files /dev/null and b/src/assets/illustrations/coin-large.png differ diff --git a/src/assets/illustrations/coin-large.svg b/src/assets/illustrations/coin-large.svg new file mode 100644 index 0000000..89f6116 --- /dev/null +++ b/src/assets/illustrations/coin-large.svg @@ -0,0 +1,12 @@ + + + + + + + + + + $ + + diff --git a/src/assets/illustrations/coins-stack.png b/src/assets/illustrations/coins-stack.png new file mode 100644 index 0000000..41886ac Binary files /dev/null and b/src/assets/illustrations/coins-stack.png differ diff --git a/src/assets/illustrations/friends-icon.png b/src/assets/illustrations/friends-icon.png new file mode 100644 index 0000000..be04eed Binary files /dev/null and b/src/assets/illustrations/friends-icon.png differ diff --git a/src/assets/illustrations/game-gold-chart.png b/src/assets/illustrations/game-gold-chart.png new file mode 100644 index 0000000..5f52390 Binary files /dev/null and b/src/assets/illustrations/game-gold-chart.png differ diff --git a/src/assets/illustrations/game-gold-chart.svg b/src/assets/illustrations/game-gold-chart.svg new file mode 100644 index 0000000..14811f7 --- /dev/null +++ b/src/assets/illustrations/game-gold-chart.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/illustrations/game-inflation.png b/src/assets/illustrations/game-inflation.png new file mode 100644 index 0000000..a55dd60 Binary files /dev/null and b/src/assets/illustrations/game-inflation.png differ diff --git a/src/assets/illustrations/game-inflation.svg b/src/assets/illustrations/game-inflation.svg new file mode 100644 index 0000000..268269f --- /dev/null +++ b/src/assets/illustrations/game-inflation.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/illustrations/game-investor.png b/src/assets/illustrations/game-investor.png new file mode 100644 index 0000000..4d01354 Binary files /dev/null and b/src/assets/illustrations/game-investor.png differ diff --git a/src/assets/illustrations/game-investor.svg b/src/assets/illustrations/game-investor.svg new file mode 100644 index 0000000..5801b60 --- /dev/null +++ b/src/assets/illustrations/game-investor.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/illustrations/game-piggy.png b/src/assets/illustrations/game-piggy.png new file mode 100644 index 0000000..7e22905 Binary files /dev/null and b/src/assets/illustrations/game-piggy.png differ diff --git a/src/assets/illustrations/game-piggy.svg b/src/assets/illustrations/game-piggy.svg new file mode 100644 index 0000000..5fa53a9 --- /dev/null +++ b/src/assets/illustrations/game-piggy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/illustrations/game-portfolio.png b/src/assets/illustrations/game-portfolio.png new file mode 100644 index 0000000..49e4f02 Binary files /dev/null and b/src/assets/illustrations/game-portfolio.png differ diff --git a/src/assets/illustrations/game-portfolio.svg b/src/assets/illustrations/game-portfolio.svg new file mode 100644 index 0000000..861993b --- /dev/null +++ b/src/assets/illustrations/game-portfolio.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/illustrations/game-shopping.png b/src/assets/illustrations/game-shopping.png new file mode 100644 index 0000000..d517911 Binary files /dev/null and b/src/assets/illustrations/game-shopping.png differ diff --git a/src/assets/illustrations/game-shopping.svg b/src/assets/illustrations/game-shopping.svg new file mode 100644 index 0000000..56218e1 --- /dev/null +++ b/src/assets/illustrations/game-shopping.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/illustrations/gamepad-icon.png b/src/assets/illustrations/gamepad-icon.png new file mode 100644 index 0000000..f40c90b Binary files /dev/null and b/src/assets/illustrations/gamepad-icon.png differ diff --git a/src/assets/illustrations/gold-bar.svg b/src/assets/illustrations/gold-bar.svg new file mode 100644 index 0000000..c20ab6e --- /dev/null +++ b/src/assets/illustrations/gold-bar.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/illustrations/gold-bars-stack.png b/src/assets/illustrations/gold-bars-stack.png new file mode 100644 index 0000000..a0be174 Binary files /dev/null and b/src/assets/illustrations/gold-bars-stack.png differ diff --git a/src/assets/illustrations/hero-explorer.svg b/src/assets/illustrations/hero-explorer.svg new file mode 100644 index 0000000..3e14875 --- /dev/null +++ b/src/assets/illustrations/hero-explorer.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/illustrations/home-hero-bg.png b/src/assets/illustrations/home-hero-bg.png new file mode 100644 index 0000000..019a82e Binary files /dev/null and b/src/assets/illustrations/home-hero-bg.png differ diff --git a/src/assets/illustrations/index.ts b/src/assets/illustrations/index.ts new file mode 100644 index 0000000..9e19ecc --- /dev/null +++ b/src/assets/illustrations/index.ts @@ -0,0 +1,85 @@ +import heroExplorer from './hero-explorer.svg' +import treasureChest from './treasure-chest.png' +import professor from './professor.png' +import bankBuilding from './bank-building.png' +import phoneIcon from './phone-icon.png' +import shoppingCart from './shopping-cart.svg' +import mapScene from './map-scene.png' +import mapNodeOrb from './map-node-orb.png' +import goldBar from './gold-bar.svg' +import goldBarsStack from './gold-bars-stack.png' +import coinLarge from './coin-large.png' +import coinsStack from './coins-stack.png' +import cashBundle from './cash-bundle.png' +import homeHeroBg from './home-hero-bg.png' +import gamepadIcon from './gamepad-icon.png' +import targetIcon from './target-icon.png' +import cartIcon from './cart-icon.png' +import friendsIcon from './friends-icon.png' +import challengeBanner from './challenge-banner.png' +import gameGoldChart from './game-gold-chart.png' +import gameInflation from './game-inflation.png' +import gamePortfolio from './game-portfolio.png' +import gameShopping from './game-shopping.png' +import gamePiggy from './game-piggy.png' +import gameInvestor from './game-investor.png' +import productCastle from './product-castle.png' +import productCrown from './product-crown.png' +import productSuit from './product-suit.png' +import productPet from './product-pet.png' +import productSea from './product-sea.png' +import schoolBackpack from './school-backpack.svg' + +export const illustrations = { + heroExplorer, + treasureChest, + professor, + bankBuilding, + phoneIcon, + shoppingCart, + mapScene, + mapNodeOrb, + goldBar, + goldBarsStack, + coinLarge, + coinsStack, + cashBundle, + homeHeroBg, + gamepadIcon, + targetIcon, + cartIcon, + friendsIcon, + challengeBanner, + gameGoldChart, + gameInflation, + gamePortfolio, + gameShopping, + gamePiggy, + gameInvestor, + productCastle, + productCrown, + productSuit, + productPet, + productSea, + schoolBackpack, +} as const + +export type IllustrationKey = keyof typeof illustrations + +export const gameIllustrations: Record = { + 'gold-guess': gameGoldChart, + inflation: gameInflation, + portfolio: gamePortfolio, + 'smart-shop': gameShopping, + savings: gamePiggy, + investor: gameInvestor, +} + +export const productIllustrations: Record = { + castle: productCastle, + suit: productSuit, + pet: productPet, + 'sea-bg': productSea, + crown: productCrown, + 'boost-xp': coinLarge, +} diff --git a/src/assets/illustrations/map-node-orb.png b/src/assets/illustrations/map-node-orb.png new file mode 100644 index 0000000..03aa870 Binary files /dev/null and b/src/assets/illustrations/map-node-orb.png differ diff --git a/src/assets/illustrations/map-scene.png b/src/assets/illustrations/map-scene.png new file mode 100644 index 0000000..a35777f Binary files /dev/null and b/src/assets/illustrations/map-scene.png differ diff --git a/src/assets/illustrations/map-scene.svg b/src/assets/illustrations/map-scene.svg new file mode 100644 index 0000000..d8e7aa1 --- /dev/null +++ b/src/assets/illustrations/map-scene.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/illustrations/phone-icon.png b/src/assets/illustrations/phone-icon.png new file mode 100644 index 0000000..a4d82b5 Binary files /dev/null and b/src/assets/illustrations/phone-icon.png differ diff --git a/src/assets/illustrations/phone-icon.svg b/src/assets/illustrations/phone-icon.svg new file mode 100644 index 0000000..bebc8a5 --- /dev/null +++ b/src/assets/illustrations/phone-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/illustrations/phone-icon.tmp.png b/src/assets/illustrations/phone-icon.tmp.png new file mode 100644 index 0000000..a4d82b5 Binary files /dev/null and b/src/assets/illustrations/phone-icon.tmp.png differ diff --git a/src/assets/illustrations/product-castle.png b/src/assets/illustrations/product-castle.png new file mode 100644 index 0000000..322d0ce Binary files /dev/null and b/src/assets/illustrations/product-castle.png differ diff --git a/src/assets/illustrations/product-castle.svg b/src/assets/illustrations/product-castle.svg new file mode 100644 index 0000000..bb89d6a --- /dev/null +++ b/src/assets/illustrations/product-castle.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/illustrations/product-crown.png b/src/assets/illustrations/product-crown.png new file mode 100644 index 0000000..b4a92fb Binary files /dev/null and b/src/assets/illustrations/product-crown.png differ diff --git a/src/assets/illustrations/product-pet.png b/src/assets/illustrations/product-pet.png new file mode 100644 index 0000000..30ac8cf Binary files /dev/null and b/src/assets/illustrations/product-pet.png differ diff --git a/src/assets/illustrations/product-pet.svg b/src/assets/illustrations/product-pet.svg new file mode 100644 index 0000000..ce0d961 --- /dev/null +++ b/src/assets/illustrations/product-pet.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/illustrations/product-sea.png b/src/assets/illustrations/product-sea.png new file mode 100644 index 0000000..10ffab6 Binary files /dev/null and b/src/assets/illustrations/product-sea.png differ diff --git a/src/assets/illustrations/product-sea.svg b/src/assets/illustrations/product-sea.svg new file mode 100644 index 0000000..718c6cc --- /dev/null +++ b/src/assets/illustrations/product-sea.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/illustrations/product-suit.png b/src/assets/illustrations/product-suit.png new file mode 100644 index 0000000..6c26979 Binary files /dev/null and b/src/assets/illustrations/product-suit.png differ diff --git a/src/assets/illustrations/product-suit.svg b/src/assets/illustrations/product-suit.svg new file mode 100644 index 0000000..12eca4e --- /dev/null +++ b/src/assets/illustrations/product-suit.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/illustrations/professor.png b/src/assets/illustrations/professor.png new file mode 100644 index 0000000..fc225cb Binary files /dev/null and b/src/assets/illustrations/professor.png differ diff --git a/src/assets/illustrations/professor.svg b/src/assets/illustrations/professor.svg new file mode 100644 index 0000000..9ad0935 --- /dev/null +++ b/src/assets/illustrations/professor.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/illustrations/school-backpack.svg b/src/assets/illustrations/school-backpack.svg new file mode 100644 index 0000000..9696d4d --- /dev/null +++ b/src/assets/illustrations/school-backpack.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/illustrations/shopping-cart.svg b/src/assets/illustrations/shopping-cart.svg new file mode 100644 index 0000000..4c25fa3 --- /dev/null +++ b/src/assets/illustrations/shopping-cart.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + 112,000 + + 100,000 + diff --git a/src/assets/illustrations/target-icon.png b/src/assets/illustrations/target-icon.png new file mode 100644 index 0000000..fe236f7 Binary files /dev/null and b/src/assets/illustrations/target-icon.png differ diff --git a/src/assets/illustrations/treasure-chest.png b/src/assets/illustrations/treasure-chest.png new file mode 100644 index 0000000..475cb3d Binary files /dev/null and b/src/assets/illustrations/treasure-chest.png differ diff --git a/src/assets/illustrations/treasure-chest.svg b/src/assets/illustrations/treasure-chest.svg new file mode 100644 index 0000000..58d032c --- /dev/null +++ b/src/assets/illustrations/treasure-chest.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/profile/avatar.png b/src/assets/profile/avatar.png new file mode 100644 index 0000000..2eb7f8b Binary files /dev/null and b/src/assets/profile/avatar.png differ diff --git a/src/assets/profile/index.ts b/src/assets/profile/index.ts new file mode 100644 index 0000000..0efe91e --- /dev/null +++ b/src/assets/profile/index.ts @@ -0,0 +1,9 @@ +import avatar from './avatar.png' +import shieldBadge from './shield-badge.png' +import schoolBanner from './school-banner.png' + +export const profileAssets = { + avatar, + shieldBadge, + schoolBanner, +} as const diff --git a/src/assets/profile/school-banner.png b/src/assets/profile/school-banner.png new file mode 100644 index 0000000..85ff567 Binary files /dev/null and b/src/assets/profile/school-banner.png differ diff --git a/src/assets/profile/shield-badge.png b/src/assets/profile/shield-badge.png new file mode 100644 index 0000000..7565bf1 Binary files /dev/null and b/src/assets/profile/shield-badge.png differ diff --git a/src/components/common/AppHeader.vue b/src/components/common/AppHeader.vue new file mode 100644 index 0000000..dfc75d9 --- /dev/null +++ b/src/components/common/AppHeader.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/src/components/common/AppModal.vue b/src/components/common/AppModal.vue new file mode 100644 index 0000000..ca96031 --- /dev/null +++ b/src/components/common/AppModal.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/components/common/BottomNavigation.vue b/src/components/common/BottomNavigation.vue new file mode 100644 index 0000000..fc0588c --- /dev/null +++ b/src/components/common/BottomNavigation.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/src/components/common/CoinBadge.vue b/src/components/common/CoinBadge.vue new file mode 100644 index 0000000..1b10fe8 --- /dev/null +++ b/src/components/common/CoinBadge.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/components/common/FinancialStatCard.vue b/src/components/common/FinancialStatCard.vue new file mode 100644 index 0000000..e72b708 --- /dev/null +++ b/src/components/common/FinancialStatCard.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/components/common/GameCard.vue b/src/components/common/GameCard.vue new file mode 100644 index 0000000..98d56c0 --- /dev/null +++ b/src/components/common/GameCard.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/components/common/GoldBadge.vue b/src/components/common/GoldBadge.vue new file mode 100644 index 0000000..2416a39 --- /dev/null +++ b/src/components/common/GoldBadge.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/components/common/OptionCard.vue b/src/components/common/OptionCard.vue new file mode 100644 index 0000000..f76ff10 --- /dev/null +++ b/src/components/common/OptionCard.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/components/common/PageBackButton.vue b/src/components/common/PageBackButton.vue new file mode 100644 index 0000000..fa405d6 --- /dev/null +++ b/src/components/common/PageBackButton.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/components/common/PageTitle.vue b/src/components/common/PageTitle.vue new file mode 100644 index 0000000..89847c9 --- /dev/null +++ b/src/components/common/PageTitle.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/components/common/PrimaryButton.vue b/src/components/common/PrimaryButton.vue new file mode 100644 index 0000000..b0415ee --- /dev/null +++ b/src/components/common/PrimaryButton.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/src/components/common/ProgressBar.vue b/src/components/common/ProgressBar.vue new file mode 100644 index 0000000..4f65617 --- /dev/null +++ b/src/components/common/ProgressBar.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/components/common/SectionCard.vue b/src/components/common/SectionCard.vue new file mode 100644 index 0000000..50f2302 --- /dev/null +++ b/src/components/common/SectionCard.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/components/common/StatCard.vue b/src/components/common/StatCard.vue new file mode 100644 index 0000000..944244b --- /dev/null +++ b/src/components/common/StatCard.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/components/common/ToastContainer.vue b/src/components/common/ToastContainer.vue new file mode 100644 index 0000000..cb0b0be --- /dev/null +++ b/src/components/common/ToastContainer.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/home/HomeHeader.vue b/src/components/home/HomeHeader.vue new file mode 100644 index 0000000..247881e --- /dev/null +++ b/src/components/home/HomeHeader.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/src/components/map/MapNode.vue b/src/components/map/MapNode.vue new file mode 100644 index 0000000..2f696b4 --- /dev/null +++ b/src/components/map/MapNode.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/src/components/market/MarketChart.vue b/src/components/market/MarketChart.vue new file mode 100644 index 0000000..4cac795 --- /dev/null +++ b/src/components/market/MarketChart.vue @@ -0,0 +1,247 @@ + + + + + diff --git a/src/components/store/ProductCard.vue b/src/components/store/ProductCard.vue new file mode 100644 index 0000000..c794706 --- /dev/null +++ b/src/components/store/ProductCard.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/components/wallet/TransactionItem.vue b/src/components/wallet/TransactionItem.vue new file mode 100644 index 0000000..d7c9dca --- /dev/null +++ b/src/components/wallet/TransactionItem.vue @@ -0,0 +1,207 @@ + + + + + diff --git a/src/composables/useToast.ts b/src/composables/useToast.ts new file mode 100644 index 0000000..685356d --- /dev/null +++ b/src/composables/useToast.ts @@ -0,0 +1,30 @@ +import { ref } from 'vue' + +export interface ToastMessage { + id: number + message: string + type: 'success' | 'error' | 'info' +} + +const toasts = ref([]) +let nextId = 0 + +export function useToast() { + function show(message: string, type: ToastMessage['type'] = 'info', duration = 3000) { + const id = nextId++ + toasts.value.push({ id, message, type }) + setTimeout(() => { + toasts.value = toasts.value.filter((t) => t.id !== id) + }, duration) + } + + function success(message: string) { + show(message, 'success') + } + + function error(message: string) { + show(message, 'error') + } + + return { toasts, show, success, error } +} diff --git a/src/data/mockData.ts b/src/data/mockData.ts new file mode 100644 index 0000000..4c933cf --- /dev/null +++ b/src/data/mockData.ts @@ -0,0 +1,130 @@ +export interface GameItem { + id: string + title: string + description: string + icon: string + route?: string + color: string +} + +export interface StoreProduct { + id: string + title: string + price: number + category: 'all' | 'special' | 'visual' | 'boost' + emoji: string +} + +export interface MapLevel { + id: number + title: string + stars: number + maxStars: number + status: 'completed' | 'current' | 'unlocked' | 'locked' + lessonRoute?: string + x: number + y: number +} + +export interface Achievement { + id: string + title: string + description: string + icon: string + unlocked: boolean +} + +export interface ChallengeOption { + id: string + label: string + icon: string + color: string + isCorrect: boolean + feedback: string +} + +export const INITIAL_TRANSACTIONS = [ + { id: '1', type: 'expense' as const, title: 'خرید طلا', amount: 1600000, unit: 'تومان' as const, date: '۱۴۰۴/۰۴/۱۲' }, + { id: '2', type: 'income' as const, title: 'ماموریت روزانه', amount: 50, unit: 'سکه' as const, date: '۱۴۰۴/۰۴/۱۱' }, + { id: '3', type: 'income' as const, title: 'پاداش بازی', amount: 20, unit: 'سکه' as const, date: '۱۴۰۴/۰۴/۱۰' }, +] + +export const GAMES: GameItem[] = [ + { id: 'gold-guess', title: 'حدس قیمت طلا', description: 'قیمت فردا رو حدس بزن', icon: '📈', route: '/games/gold-guess', color: '#7438c9' }, + { id: 'inflation', title: 'تورم رو شکست بده', description: 'ارزش پولت رو حفظ کن', icon: '👾', route: '/lessons/inflation', color: '#e73343' }, + { id: 'portfolio', title: 'ساخت سبد سرمایه‌گذاری', description: 'بهترین ترکیب رو انتخاب کن', icon: '📊', color: '#1987d4' }, + { id: 'smart-shop', title: 'خرید هوشمند', description: 'بهترین خرید رو انجام بده', icon: '🛒', color: '#20b94b' }, + { id: 'savings', title: 'چالش پس‌انداز', description: 'پس‌انداز کن و پیشرفت کن', icon: '🐷', color: '#f5b62d' }, + { id: 'investor', title: 'شاگرد سرمایه‌گذار', description: 'تصمیم بگیر و سود ببر', icon: '🎓', color: '#f07a2a' }, +] + +export const STORE_PRODUCTS: StoreProduct[] = [ + { id: 'castle', title: 'قلعه طلایی', price: 5000, category: 'special', emoji: '🏰' }, + { id: 'suit', title: 'لباس ماجراجو', price: 2500, category: 'visual', emoji: '🧥' }, + { id: 'pet', title: 'حیوان همراه', price: 3000, category: 'special', emoji: '🦊' }, + { id: 'sea-bg', title: 'پس‌زمینه دریایی', price: 1500, category: 'visual', emoji: '🌊' }, + { id: 'crown', title: 'تاج طلایی', price: 4000, category: 'special', emoji: '👑' }, + { id: 'boost-xp', title: 'تقویت XP', price: 800, category: 'boost', emoji: '⚡' }, +] + +export const CHALLENGE_OPTIONS: ChallengeOption[] = [ + { id: 'gold', label: 'طلا', icon: '🥇', color: '#f5b62d', isCorrect: true, feedback: 'عالی! طلا در بلندمدت می‌تونه ارزش پولت رو حفظ کنه.' }, + { id: 'dollar', label: 'دلار', icon: '💵', color: '#20b94b', isCorrect: false, feedback: 'دلار گزینه‌ایه، ولی طلا برای حفظ ارزش در تورم بهتره.' }, + { id: 'bank', label: 'بانک', icon: '🏦', color: '#1987d4', isCorrect: false, feedback: 'پس‌انداز بانکی امنه، ولی سودش معمولاً از تورم کمتره.' }, + { id: 'phone', label: 'خرید گوشی', icon: '📱', color: '#7438c9', isCorrect: false, feedback: 'گوشی ارزش مالی نگه نمی‌داره. بهتره سرمایه‌گذاری کنی!' }, +] + +export const ACHIEVEMENTS: Achievement[] = [ + { id: 'first-gold', title: 'اولین خرید طلا', description: 'اولین خرید طلای خودت رو انجام دادی', icon: '🥇', unlocked: true }, + { id: 'saver', title: 'پس‌اندازگر کوچک', description: '۱۰۰ هزار تومان پس‌انداز کردی', icon: '💰', unlocked: true }, + { id: 'market', title: 'شاگرد بازار', description: '۵ بار در بازار معامله کردی', icon: '📊', unlocked: false }, + { id: 'inflation', title: 'شکست‌دهنده تورم', description: 'درس تورم رو کامل کردی', icon: '👾', unlocked: false }, +] + +function generatePriceHistory(basePrice: number, points: number): number[] { + const history: number[] = [] + let price = basePrice * 0.92 + for (let i = 0; i < points; i++) { + const change = (Math.sin(i * 0.4) * 0.015 + Math.random() * 0.008) * price + price += change + history.push(Math.round(price)) + } + history[history.length - 1] = basePrice + return history +} + +export const GOLD_PRICE = 1830000 +export const PRICE_HISTORY = { + '1d': generatePriceHistory(GOLD_PRICE, 24), + '7d': generatePriceHistory(GOLD_PRICE, 28), + '30d': generatePriceHistory(GOLD_PRICE, 30), + '90d': generatePriceHistory(GOLD_PRICE, 30), + '1y': generatePriceHistory(GOLD_PRICE, 52), +} + +export const MAP_LEVELS: MapLevel[] = [ + { id: 1, title: 'پول چیه؟', stars: 0, maxStars: 3, status: 'current', x: 24, y: 79 }, + { id: 2, title: 'پس‌انداز', stars: 0, maxStars: 3, status: 'locked', x: 59, y: 63 }, + { id: 3, title: 'نیاز و خواسته', stars: 0, maxStars: 3, status: 'locked', x: 32, y: 47 }, + { id: 4, title: 'طلا چیه؟', stars: 0, maxStars: 3, status: 'locked', x: 22, y: 36 }, + { id: 5, title: 'بازار طلا', stars: 0, maxStars: 3, status: 'locked', x: 42, y: 34 }, + { id: 6, title: 'تورم', stars: 0, maxStars: 3, status: 'locked', lessonRoute: '/lessons/inflation', x: 54, y: 66 }, + { id: 7, title: 'سرمایه‌گذاری', stars: 0, maxStars: 3, status: 'locked', x: 40, y: 61 }, + { id: 8, title: 'سبد دارایی', stars: 0, maxStars: 3, status: 'locked', x: 28, y: 77 }, + { id: 9, title: 'ریسک و پاداش', stars: 0, maxStars: 3, status: 'locked', x: 47, y: 63 }, + { id: 10, title: 'پس‌انداز هوشمند', stars: 0, maxStars: 3, status: 'locked', x: 33, y: 52 }, + { id: 11, title: 'اقتصاد خانواده', stars: 0, maxStars: 3, status: 'locked', x: 47, y: 41 }, + { id: 12, title: 'کارآفرینی', stars: 0, maxStars: 3, status: 'locked', x: 48, y: 30 }, + { id: 13, title: 'سرزمین طلا', stars: 0, maxStars: 3, status: 'locked', x: 54, y: 18 }, +] + +export const ILLUSTRATIONS = { + heroExplorer: '/src/assets/illustrations/hero-explorer.svg', + treasureChest: '/src/assets/illustrations/treasure-chest.svg', + professor: '/src/assets/illustrations/professor.svg', + shoppingCart: '/src/assets/illustrations/shopping-cart.svg', + goldBar: '/src/assets/illustrations/gold-bar.svg', + coin: '/src/assets/illustrations/coin.svg', + castle: '/src/assets/illustrations/castle.svg', + mapBackground: '/src/assets/illustrations/map-scene.svg', +} as const diff --git a/src/layouts/MobileAppLayout.vue b/src/layouts/MobileAppLayout.vue new file mode 100644 index 0000000..b5003ca --- /dev/null +++ b/src/layouts/MobileAppLayout.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..6eb6d64 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,14 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import '@fontsource/vazirmatn/400.css' +import '@fontsource/vazirmatn/500.css' +import '@fontsource/vazirmatn/700.css' +import '@fontsource/vazirmatn/800.css' +import App from './App.vue' +import router from './router' +import './styles/global.css' + +const app = createApp(App) +app.use(createPinia()) +app.use(router) +app.mount('#app') diff --git a/src/modules/gold-land/components/lesson/LessonHeader.vue b/src/modules/gold-land/components/lesson/LessonHeader.vue new file mode 100644 index 0000000..191c73c --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonHeader.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonPlayer.vue b/src/modules/gold-land/components/lesson/LessonPlayer.vue new file mode 100644 index 0000000..e6d5a35 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonPlayer.vue @@ -0,0 +1,315 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonProgress.vue b/src/modules/gold-land/components/lesson/LessonProgress.vue new file mode 100644 index 0000000..c565c84 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonProgress.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonResult.vue b/src/modules/gold-land/components/lesson/LessonResult.vue new file mode 100644 index 0000000..7649a3a --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonResult.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonSingleChoiceStep.vue b/src/modules/gold-land/components/lesson/LessonSingleChoiceStep.vue new file mode 100644 index 0000000..b0bd506 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonSingleChoiceStep.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonSortStep.vue b/src/modules/gold-land/components/lesson/LessonSortStep.vue new file mode 100644 index 0000000..0618054 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonSortStep.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonStepRenderer.vue b/src/modules/gold-land/components/lesson/LessonStepRenderer.vue new file mode 100644 index 0000000..3f895a6 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonStepRenderer.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/modules/gold-land/components/lesson/LessonStoryStep.vue b/src/modules/gold-land/components/lesson/LessonStoryStep.vue new file mode 100644 index 0000000..9fcba65 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonStoryStep.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonSummaryStep.vue b/src/modules/gold-land/components/lesson/LessonSummaryStep.vue new file mode 100644 index 0000000..71dbaae --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonSummaryStep.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/LessonTrueFalseStep.vue b/src/modules/gold-land/components/lesson/LessonTrueFalseStep.vue new file mode 100644 index 0000000..6eb4e63 --- /dev/null +++ b/src/modules/gold-land/components/lesson/LessonTrueFalseStep.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/modules/gold-land/components/lesson/lessonImages.ts b/src/modules/gold-land/components/lesson/lessonImages.ts new file mode 100644 index 0000000..401c970 --- /dev/null +++ b/src/modules/gold-land/components/lesson/lessonImages.ts @@ -0,0 +1,18 @@ +import { illustrations, type IllustrationKey } from '@/assets/illustrations' + +const IMAGE_MAP: Record = { + 'shopping-cart': illustrations.shoppingCart, + cart: illustrations.cartIcon, + coins: illustrations.coinsStack, + 'gold-bar': illustrations.goldBar, + piggy: illustrations.gamePiggy, + market: illustrations.gameGoldChart, +} + +export function resolveLessonImage(imageKey?: string): string | undefined { + if (!imageKey) return undefined + if (imageKey in illustrations) { + return illustrations[imageKey as IllustrationKey] + } + return IMAGE_MAP[imageKey] +} diff --git a/src/modules/gold-land/config/mapLayout.ts b/src/modules/gold-land/config/mapLayout.ts new file mode 100644 index 0000000..0245ff9 --- /dev/null +++ b/src/modules/gold-land/config/mapLayout.ts @@ -0,0 +1 @@ +export { mapLayout, treasureChestLayout } from './mapPath' diff --git a/src/modules/gold-land/config/mapPath.ts b/src/modules/gold-land/config/mapPath.ts new file mode 100644 index 0000000..b24893c --- /dev/null +++ b/src/modules/gold-land/config/mapPath.ts @@ -0,0 +1,99 @@ +/** نقاط میانی خط مرکزی جاده — از map-scene.png */ +const ROAD_WAYPOINTS: ReadonlyArray = [ + [58, 94], + [52, 90], + [44, 86], + [34, 82], + [25, 78], + [26, 72], + [36, 67], + [50, 62], + [61, 57], + [56, 52], + [44, 47], + [32, 42], + [34, 37], + [48, 33], + [62, 30], + [72, 29], +] + +const LEVEL_COUNT = 13 +const CHEST_COUNT = 4 + +function segmentLength(a: readonly [number, number], b: readonly [number, number]) { + return Math.hypot(b[0] - a[0], b[1] - a[1]) +} + +function sampleAtDistance(distance: number): { x: number; y: number } { + let remaining = distance + + for (let i = 0; i < ROAD_WAYPOINTS.length - 1; i++) { + const from = ROAD_WAYPOINTS[i]! + const to = ROAD_WAYPOINTS[i + 1]! + const len = segmentLength(from, to) + + if (remaining <= len || i === ROAD_WAYPOINTS.length - 2) { + const t = len === 0 ? 0 : remaining / len + return { + x: Math.round(from[0] + (to[0] - from[0]) * t), + y: Math.round(from[1] + (to[1] - from[1]) * t), + } + } + + remaining -= len + } + + const last = ROAD_WAYPOINTS[ROAD_WAYPOINTS.length - 1]! + return { x: last[0], y: last[1] } +} + +function totalPathLength() { + let total = 0 + for (let i = 0; i < ROAD_WAYPOINTS.length - 1; i++) { + total += segmentLength(ROAD_WAYPOINTS[i]!, ROAD_WAYPOINTS[i + 1]!) + } + return total +} + +function sampleAlongPath(fraction: number) { + const total = totalPathLength() + return sampleAtDistance(total * Math.min(1, Math.max(0, fraction))) +} + +/** آفست عمود بر جاده برای صندوق‌ها (چمن کنار مسیر) */ +function offsetFromPath( + point: { x: number; y: number }, + side: 'left' | 'right', + amount = 8, +) { + const delta = side === 'left' ? -amount : amount + return { + x: Math.min(88, Math.max(8, point.x + delta)), + y: point.y, + } +} + +export function buildMapLayout() { + const layout: Record = {} + + for (let i = 0; i < LEVEL_COUNT; i++) { + const fraction = i / (LEVEL_COUNT - 1) + layout[i + 1] = sampleAlongPath(fraction) + } + + return layout +} + +export function buildTreasureChestLayout() { + const fractions = [0.06, 0.28, 0.58, 0.88] + const sides: Array<'left' | 'right'> = ['right', 'left', 'right', 'left'] + + return fractions.slice(0, CHEST_COUNT).map((fraction, index) => { + const onPath = sampleAlongPath(fraction) + return offsetFromPath(onPath, sides[index] ?? 'right', 10) + }) +} + +export const mapLayout = buildMapLayout() +export const treasureChestLayout = buildTreasureChestLayout() diff --git a/src/modules/gold-land/services/goldLand.api.ts b/src/modules/gold-land/services/goldLand.api.ts new file mode 100644 index 0000000..3800f64 --- /dev/null +++ b/src/modules/gold-land/services/goldLand.api.ts @@ -0,0 +1,24 @@ +import { api } from '@/api/client' +import type { + CompleteLevelResponse, + GoldLandProgressResponse, + LevelDetailResponse, + LevelItem, + LessonSubmissionAnswer, +} from '../types/goldLand.types' + +export const goldLandApi = { + getProgress: () => api.getGoldLandProgress(), + getLevel: (levelId: number) => api.getGoldLandLevel(levelId), + startLevel: (levelId: number) => api.startGoldLandLevel(levelId), + completeLevel: (levelId: number, answers: LessonSubmissionAnswer[], durationMs?: number) => + api.completeGoldLandLevel(levelId, answers, durationMs), +} + +export type { + LevelItem, + GoldLandProgressResponse, + CompleteLevelResponse, + LevelDetailResponse, + LessonSubmissionAnswer, +} diff --git a/src/modules/gold-land/types/goldLand.types.ts b/src/modules/gold-land/types/goldLand.types.ts new file mode 100644 index 0000000..89f000a --- /dev/null +++ b/src/modules/gold-land/types/goldLand.types.ts @@ -0,0 +1,140 @@ +export type LevelStatus = + | 'locked' + | 'available' + | 'in_progress' + | 'completed' + | 'coming_soon' + +export interface LevelItem { + id: number + order: number + slug: string + title: string + description: string + status: LevelStatus + stars: 0 | 1 | 2 | 3 + bestScore: number + activityType: string + activityKey: string + activityRoute?: string + rewardXp: number + rewardCoins: number +} + +export type LessonStepType = 'story' | 'single_choice' | 'true_false' | 'sort' | 'summary' + +export interface LessonOption { + id: string + label: string +} + +export interface StoryStep { + id: string + type: 'story' + title?: string + body: string + imageKey?: string +} + +export interface SingleChoiceStep { + id: string + type: 'single_choice' + title?: string + question: string + options: LessonOption[] +} + +export interface TrueFalseStep { + id: string + type: 'true_false' + title?: string + question: string +} + +export interface SortStep { + id: string + type: 'sort' + title?: string + question: string + items: LessonOption[] +} + +export interface SummaryStep { + id: string + type: 'summary' + title?: string + body: string + highlight?: string +} + +export type SanitizedLessonStep = + | StoryStep + | SingleChoiceStep + | TrueFalseStep + | SortStep + | SummaryStep + +export interface SanitizedLesson { + id: string + version: number + title: string + steps: SanitizedLessonStep[] +} + +export interface LevelDetailResponse { + level: Pick< + LevelItem, + | 'id' + | 'order' + | 'slug' + | 'title' + | 'description' + | 'status' + | 'stars' + | 'bestScore' + | 'activityType' + | 'activityKey' + | 'activityRoute' + > + activity: { + type: string + lesson?: SanitizedLesson + } | null +} + +export interface GoldLandProgressResponse { + levels: LevelItem[] + totalStars: number + maxStars: number + currentLevelId: number | null +} + +export interface CompleteLevelResponse { + levelId: number + score: number + stars: 0 | 1 | 2 | 3 + previousStars: 0 | 1 | 2 | 3 + isFirstCompletion: boolean + bestScoreImproved: boolean + reward: { xp: number; coins: number } + unlockedLevelId: number | null + me: import('@/api/client').MeResponse +} + +export interface ChoiceLessonAnswer { + questionId: string + answerId: string +} + +export interface SortLessonAnswer { + questionId: string + orderedItemIds: string[] +} + +export type LessonSubmissionAnswer = ChoiceLessonAnswer | SortLessonAnswer + +/** @deprecated Use LessonSubmissionAnswer */ +export interface LessonAnswer { + questionId: string + answerId: string +} diff --git a/src/pages/DailyChallengePage.vue b/src/pages/DailyChallengePage.vue new file mode 100644 index 0000000..07bf80a --- /dev/null +++ b/src/pages/DailyChallengePage.vue @@ -0,0 +1,338 @@ + + + + + diff --git a/src/pages/FriendsPage.vue b/src/pages/FriendsPage.vue new file mode 100644 index 0000000..c72d221 --- /dev/null +++ b/src/pages/FriendsPage.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/src/pages/GamesPage.vue b/src/pages/GamesPage.vue new file mode 100644 index 0000000..6971966 --- /dev/null +++ b/src/pages/GamesPage.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/pages/GoldPredictionGamePage.vue b/src/pages/GoldPredictionGamePage.vue new file mode 100644 index 0000000..1a03c43 --- /dev/null +++ b/src/pages/GoldPredictionGamePage.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/src/pages/HomePage.vue b/src/pages/HomePage.vue new file mode 100644 index 0000000..92da9be --- /dev/null +++ b/src/pages/HomePage.vue @@ -0,0 +1,329 @@ + + + + + diff --git a/src/pages/InflationLessonPage.vue b/src/pages/InflationLessonPage.vue new file mode 100644 index 0000000..0545949 --- /dev/null +++ b/src/pages/InflationLessonPage.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/pages/LearningMapPage.vue b/src/pages/LearningMapPage.vue new file mode 100644 index 0000000..36fd938 --- /dev/null +++ b/src/pages/LearningMapPage.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/src/pages/LevelActivityPage.vue b/src/pages/LevelActivityPage.vue new file mode 100644 index 0000000..2af775d --- /dev/null +++ b/src/pages/LevelActivityPage.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/pages/LoginPage.vue b/src/pages/LoginPage.vue new file mode 100644 index 0000000..e686030 --- /dev/null +++ b/src/pages/LoginPage.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/src/pages/MarketPage.vue b/src/pages/MarketPage.vue new file mode 100644 index 0000000..23f747d --- /dev/null +++ b/src/pages/MarketPage.vue @@ -0,0 +1,486 @@ + + + + + diff --git a/src/pages/ProfilePage.vue b/src/pages/ProfilePage.vue new file mode 100644 index 0000000..f8f9269 --- /dev/null +++ b/src/pages/ProfilePage.vue @@ -0,0 +1,421 @@ + + + + + diff --git a/src/pages/SettingsPage.vue b/src/pages/SettingsPage.vue new file mode 100644 index 0000000..21d5e9f --- /dev/null +++ b/src/pages/SettingsPage.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/src/pages/StorePage.vue b/src/pages/StorePage.vue new file mode 100644 index 0000000..2d0e5f0 --- /dev/null +++ b/src/pages/StorePage.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/src/pages/WalletPage.vue b/src/pages/WalletPage.vue new file mode 100644 index 0000000..1364bb7 --- /dev/null +++ b/src/pages/WalletPage.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..945d6b8 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,112 @@ +import { createRouter, createWebHistory } from 'vue-router' +import MobileAppLayout from '@/layouts/MobileAppLayout.vue' +import { useAuthStore } from '@/stores/auth' +import { bootstrapFromServer } from '@/api/sync' +import { isAppBootstrapped, markAppBootstrapped, resetAppBootstrap } from '@/api/bootstrapState' +import { useMarketStore } from '@/stores/market' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/login', + name: 'login', + component: () => import('@/pages/LoginPage.vue'), + meta: { guest: true }, + }, + { + path: '/', + component: MobileAppLayout, + meta: { requiresAuth: true }, + children: [ + { path: '', name: 'home', component: () => import('@/pages/HomePage.vue'), meta: { title: 'خانه', nav: true } }, + { path: 'market', name: 'market', component: () => import('@/pages/MarketPage.vue'), meta: { title: 'بازار طلا', nav: true } }, + { path: 'map', name: 'map', component: () => import('@/pages/LearningMapPage.vue'), meta: { title: 'سرزمین طلا', nav: true } }, + { path: 'wallet', name: 'wallet', component: () => import('@/pages/WalletPage.vue'), meta: { title: 'کیف پول', nav: true } }, + { path: 'profile', name: 'profile', component: () => import('@/pages/ProfilePage.vue'), meta: { title: 'پروفایل', nav: true } }, + ], + }, + { + path: '/friends', + name: 'friends', + component: () => import('@/pages/FriendsPage.vue'), + meta: { title: 'دوستان', nav: false, requiresAuth: true }, + }, + { + path: '/challenge', + name: 'challenge', + component: () => import('@/pages/DailyChallengePage.vue'), + meta: { title: 'چالش روزانه', nav: false, requiresAuth: true }, + }, + { + path: '/games', + name: 'games', + component: () => import('@/pages/GamesPage.vue'), + meta: { title: 'بازی‌ها', nav: false, requiresAuth: true }, + }, + { + path: '/store', + name: 'store', + component: () => import('@/pages/StorePage.vue'), + meta: { title: 'فروشگاه جوایز', nav: false, requiresAuth: true }, + }, + { + path: '/games/gold-guess', + name: 'gold-guess', + component: () => import('@/pages/GoldPredictionGamePage.vue'), + meta: { title: 'حدس قیمت طلا', nav: false, requiresAuth: true }, + }, + { + path: '/settings', + name: 'settings', + component: () => import('@/pages/SettingsPage.vue'), + meta: { title: 'تنظیمات', nav: false, requiresAuth: true }, + }, + { + path: '/gold-land/levels/:levelId', + name: 'gold-land-level', + component: () => import('@/pages/LevelActivityPage.vue'), + meta: { title: 'مرحله', nav: false, requiresAuth: true }, + }, + { + path: '/lessons/inflation', + name: 'inflation', + component: () => import('@/pages/InflationLessonPage.vue'), + meta: { title: 'درس: تورم', nav: false, requiresAuth: true }, + }, + ], + scrollBehavior(_to, _from, savedPosition) { + if (savedPosition) return savedPosition + return { top: 0 } + }, +}) + +router.beforeEach(async (to) => { + const authStore = useAuthStore() + authStore.initFromStorage() + + if (to.meta.guest) { + if (authStore.isAuthenticated) return { name: 'home' } + return true + } + + if (!authStore.isAuthenticated) { + return { name: 'login', query: { redirect: to.fullPath } } + } + + if (!isAppBootstrapped()) { + try { + await bootstrapFromServer() + await useMarketStore().loadQuote('1d') + markAppBootstrapped() + } catch { + authStore.logout() + resetAppBootstrap() + return { name: 'login' } + } + } + + return true +}) + +export default router diff --git a/src/stores/auth.ts b/src/stores/auth.ts new file mode 100644 index 0000000..8525670 --- /dev/null +++ b/src/stores/auth.ts @@ -0,0 +1,56 @@ +import { defineStore } from 'pinia' +import { api, setAuthToken, getAuthToken } from '@/api/client' +import { applyMeResponse } from '@/api/sync' +import { resetAppBootstrap } from '@/api/bootstrapState' + +interface AuthState { + token: string | null + username: string | null + displayName: string | null +} + +export const useAuthStore = defineStore('auth', { + state: (): AuthState => ({ + token: getAuthToken(), + username: null, + displayName: null, + }), + + getters: { + isAuthenticated: (state) => !!state.token, + }, + + actions: { + initFromStorage() { + this.token = getAuthToken() + }, + + async login(username: string, password: string) { + const data = await api.login(username, password) + this.token = data.token + this.username = data.user.username + this.displayName = data.user.name + setAuthToken(data.token) + applyMeResponse(data.me) + return data + }, + + async register(username: string, password: string, name?: string) { + const data = await api.register(username, password, name) + this.token = data.token + this.username = data.user.username + this.displayName = data.user.name + setAuthToken(data.token) + applyMeResponse(data.me) + return data + }, + + logout() { + this.token = null + this.username = null + this.displayName = null + setAuthToken(null) + resetAppBootstrap() + }, + }, +}) diff --git a/src/stores/games.ts b/src/stores/games.ts new file mode 100644 index 0000000..e550805 --- /dev/null +++ b/src/stores/games.ts @@ -0,0 +1,57 @@ +import { defineStore } from 'pinia' +import { MAP_LEVELS } from '@/data/mockData' +import { api } from '@/api/client' +import { applyMeResponse } from '@/api/sync' + +interface GamesState { + completedGames: string[] + claimedRewards: string[] + ownedItems: string[] + mapLevels: typeof MAP_LEVELS + totalStars: number + maxStars: number +} + +export const useGamesStore = defineStore('games', { + state: (): GamesState => ({ + completedGames: [], + claimedRewards: [], + ownedItems: [], + mapLevels: MAP_LEVELS.map((l) => ({ ...l })), + totalStars: 0, + maxStars: 39, + }), + + getters: { + mapProgress: (state) => (state.totalStars / state.maxStars) * 100, + }, + + actions: { + isRewardClaimed(gameId: string): boolean { + return this.claimedRewards.includes(gameId) + }, + + isOwned(itemId: string): boolean { + return this.ownedItems.includes(itemId) + }, + + async claimReward(gameId: string): Promise { + if (this.claimedRewards.includes(gameId)) return false + const data = await api.completeGame(gameId) + applyMeResponse(data) + return true + }, + + async purchaseItem(itemId: string): Promise { + if (this.ownedItems.includes(itemId)) return false + const data = await api.purchaseProduct(itemId) + applyMeResponse(data) + return true + }, + + async completeLevel(levelId: number, stars: number) { + const data = await api.completeMapLevel(levelId, stars) + applyMeResponse(data) + }, + }, +}) diff --git a/src/stores/market.ts b/src/stores/market.ts new file mode 100644 index 0000000..9c0f9c5 --- /dev/null +++ b/src/stores/market.ts @@ -0,0 +1,52 @@ +import { defineStore } from 'pinia' +import { GOLD_PRICE, PRICE_HISTORY } from '@/data/mockData' +import { api } from '@/api/client' +import { applyMeResponse } from '@/api/sync' + +export type TimeRange = '1d' | '7d' | '30d' | '90d' | '1y' + +interface MarketState { + currentPrice: number + dailyChange: number + selectedRange: TimeRange + priceHistoryCache: Partial> +} + +export const useMarketStore = defineStore('market', { + state: (): MarketState => ({ + currentPrice: GOLD_PRICE, + dailyChange: 2.4, + selectedRange: '1d', + priceHistoryCache: {}, + }), + + getters: { + priceHistory: (state) => + state.priceHistoryCache[state.selectedRange] ?? PRICE_HISTORY[state.selectedRange], + labels(state): string[] { + const history = state.priceHistoryCache[state.selectedRange] ?? PRICE_HISTORY[state.selectedRange] + return history.map((_, i) => { + if (state.selectedRange === '1d') return `${i}:۰۰` + return `${i + 1}` + }) + }, + }, + + actions: { + async loadQuote(range?: TimeRange) { + const selected = range ?? this.selectedRange + const quote = await api.getMarketGold(selected) + this.currentPrice = quote.currentPrice + this.dailyChange = quote.dailyChangePercent + this.priceHistoryCache[selected] = quote.history + }, + + async setRange(range: TimeRange) { + this.selectedRange = range + await Promise.all([ + this.loadQuote(range), + api.setMarketRange(range).then(applyMeResponse), + ]) + }, + }, +}) diff --git a/src/stores/user.ts b/src/stores/user.ts new file mode 100644 index 0000000..30ba6de --- /dev/null +++ b/src/stores/user.ts @@ -0,0 +1,35 @@ +import { defineStore } from 'pinia' +import { ACHIEVEMENTS } from '@/data/mockData' + +interface UserState { + name: string + level: number + xp: number + maxXp: number + coins: number + completedChallenges: string[] + completedLessons: string[] + achievements: typeof ACHIEVEMENTS + missionProgress: number + missionTarget: number +} + +export const useUserStore = defineStore('user', { + state: (): UserState => ({ + name: 'علی', + level: 12, + xp: 850, + maxXp: 1200, + coins: 1350, + completedChallenges: [], + completedLessons: [], + achievements: ACHIEVEMENTS.map((a) => ({ ...a })), + missionProgress: 12, + missionTarget: 20, + }), + + getters: { + xpProgress: (state) => (state.xp / state.maxXp) * 100, + missionPercent: (state) => (state.missionProgress / state.missionTarget) * 100, + }, +}) diff --git a/src/stores/wallet.ts b/src/stores/wallet.ts new file mode 100644 index 0000000..28340b6 --- /dev/null +++ b/src/stores/wallet.ts @@ -0,0 +1,53 @@ +import { defineStore } from 'pinia' +import { api } from '@/api/client' +import { applyMeResponse } from '@/api/sync' + +export interface Transaction { + id: string + type: 'income' | 'expense' + title: string + amount: number + unit: 'تومان' | 'سکه' | 'گرم' + date: string +} + +interface WalletState { + cash: number + goldGrams: number + transactions: Transaction[] +} + +export const useWalletStore = defineStore('wallet', { + state: (): WalletState => ({ + cash: 100_000, + goldGrams: 42.5, + transactions: [], + }), + + getters: { + goldValue: (state) => state.goldGrams * 1_830_000, + totalWealth: (state) => state.cash + state.goldGrams * 1_830_000, + }, + + actions: { + async buyGold(grams: number, _pricePerGram?: number) { + try { + const data = await api.buyGold(grams) + applyMeResponse(data) + return { success: true, message: 'خرید با موفقیت انجام شد!' } + } catch (error) { + return { success: false, message: error instanceof Error ? error.message : 'خطا در خرید' } + } + }, + + async sellGold(grams: number, _pricePerGram?: number) { + try { + const data = await api.sellGold(grams) + applyMeResponse(data) + return { success: true, message: 'فروش با موفقیت انجام شد!' } + } catch (error) { + return { success: false, message: error instanceof Error ? error.message : 'خطا در فروش' } + } + }, + }, +}) diff --git a/src/styles/global.css b/src/styles/global.css new file mode 100644 index 0000000..0ed4664 --- /dev/null +++ b/src/styles/global.css @@ -0,0 +1,223 @@ +@import './tokens.css'; + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + direction: ltr; + font-size: 16px; + font-family: Vazirmatn, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + scrollbar-gutter: stable; + overflow-y: scroll; + scrollbar-width: thin; + scrollbar-color: rgba(174, 185, 210, 0.28) #040817; +} + +body { + margin: 0; + min-height: 100vh; + min-height: 100dvh; + direction: rtl; + background: #040817; + color: var(--text-main); + overflow-x: hidden; + overscroll-behavior-y: none; +} + +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: #040817; +} + +::-webkit-scrollbar-thumb { + background: rgba(174, 185, 210, 0.28); + border-radius: 999px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(174, 185, 210, 0.42); +} + +#app { + min-height: 100vh; + min-height: 100dvh; + display: flex; + justify-content: center; + position: relative; + z-index: 1; + background: #040817; +} + +.app-shell { + width: 100%; + max-width: var(--app-max-width); + min-height: 100dvh; + background: #040817; + position: relative; + overflow-x: hidden; + box-shadow: none; +} + +.page-content { + padding: var(--page-padding); + padding-bottom: calc(var(--nav-height) + var(--nav-bottom-offset) + env(safe-area-inset-bottom, 0px) + 20px); + min-height: 100dvh; +} + +.page-content--no-nav { + padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 20px); +} + +.page-content--flush-top { + padding-top: 0; +} + +/* Page transitions — opacity only to prevent scroll overflow flash */ +.page-enter-active, +.page-leave-active { + transition: opacity var(--transition-normal); +} + +.page-enter-from, +.page-leave-to { + opacity: 0; +} + +@media (prefers-reduced-motion: reduce) { + .page-enter-active, + .page-leave-active { + transition: opacity 0.15s ease; + } + + .page-enter-from, + .page-leave-to { + transform: none; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} + +button { + font-family: inherit; + cursor: pointer; + border: none; + background: none; +} + +a { + color: inherit; + text-decoration: none; +} + +img, +svg { + display: block; + max-width: 100%; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +:focus-visible { + outline: 2px solid var(--gold); + outline-offset: 2px; +} + +/* Shared game card base */ +.game-card-base { + background: var(--card-bg); + border: var(--card-border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-card); +} + +/* Typography utilities */ +.text-number-lg { + font-size: clamp(1.5rem, 6vw, 2rem); + font-weight: 800; + line-height: 1.2; +} + +.text-number-md { + font-size: clamp(1.125rem, 4.5vw, 1.375rem); + font-weight: 800; + line-height: 1.2; +} + +.text-label { + font-size: 0.75rem; + color: var(--text-muted); + font-weight: 600; +} + +.text-page-title { + font-size: 1.1875rem; + font-weight: 800; +} + +/* Animations */ +.card-enter { + animation: cardEnter 0.4s ease backwards; +} + +@keyframes cardEnter { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes pulseGlow { + 0%, 100% { + box-shadow: 0 0 14px rgba(244, 174, 33, 0.35), 0 0 28px rgba(118, 55, 201, 0.2); + } + 50% { + box-shadow: 0 0 22px rgba(244, 174, 33, 0.6), 0 0 40px rgba(118, 55, 201, 0.35); + } +} + +@keyframes floatSparkle { + 0%, 100% { opacity: 0.4; transform: translateY(0) scale(1); } + 50% { opacity: 1; transform: translateY(-4px) scale(1.1); } +} + +@keyframes coinPop { + 0% { transform: scale(1); } + 50% { transform: scale(1.12); } + 100% { transform: scale(1); } +} + +.coin-animate { + animation: coinPop 0.4s ease; +} + +.sparkle { + animation: floatSparkle 2.5s ease-in-out infinite; +} diff --git a/src/styles/tokens.css b/src/styles/tokens.css new file mode 100644 index 0000000..9896dc5 --- /dev/null +++ b/src/styles/tokens.css @@ -0,0 +1,61 @@ +:root { + /* Core palette */ + --background-deep: #050b1d; + --background-main: #08142b; + --background-card: #101d3a; + --background-card-light: #19284b; + --background-purple: #251b4d; + --border-purple: #55358e; + --border-purple-light: #8654d2; + --purple: #7637c9; + --purple-light: #9c50e9; + --gold: #f4ae21; + --gold-light: #ffd55e; + --orange: #f18c16; + --green: #22b54b; + --green-dark: #138d36; + --red: #e63443; + --red-dark: #b8172d; + --blue: #1682cb; + --text-main: #ffffff; + --text-muted: #aeb9d2; + + /* Legacy aliases */ + --app-bg: var(--background-main); + --app-bg-secondary: var(--background-deep); + --surface: var(--background-card); + --surface-light: var(--background-card-light); + --surface-purple: var(--background-purple); + --primary-purple: var(--purple); + --primary-purple-light: var(--purple-light); + --text-primary: var(--text-main); + --text-secondary: var(--text-muted); + + /* Layout */ + --radius-sm: 12px; + --radius-md: 17px; + --radius-lg: 20px; + --radius-xl: 24px; + --nav-height: 62px; + --nav-bottom-offset: 8px; + --header-height: 58px; + --app-max-width: 420px; + --page-padding: 16px; + --gap-sm: 8px; + --gap-md: 12px; + --gap-lg: 20px; + --transition-fast: 150ms ease; + --transition-normal: 280ms ease; + + /* Shadows */ + --shadow-card: + inset 0 1px 0 rgba(255, 255, 255, 0.05), + 0 8px 20px rgba(0, 0, 0, 0.28), + 0 0 16px rgba(104, 52, 190, 0.08); + --shadow-purple: 0 0 24px rgba(118, 55, 201, 0.35); + --shadow-gold: 0 0 20px rgba(244, 174, 33, 0.25); + + /* Card gradient */ + --card-bg: linear-gradient(145deg, rgba(29, 42, 78, 0.98), rgba(12, 23, 50, 0.98)); + --card-border: 1px solid rgba(118, 75, 190, 0.55); +} diff --git a/src/utils/mapDepth.ts b/src/utils/mapDepth.ts new file mode 100644 index 0000000..fb49388 --- /dev/null +++ b/src/utils/mapDepth.ts @@ -0,0 +1,23 @@ +const MIN_SCALE = 0.5 +const MAX_SCALE = 1.05 + +export function getMapDepthScale(yPercent: number): number { + const t = Math.min(100, Math.max(0, yPercent)) / 100 + return MIN_SCALE + t * (MAX_SCALE - MIN_SCALE) +} + +export function getMapElementStyle( + xPercent: number, + yPercent: number, + options?: { zBoost?: number; scaleBoost?: number }, +) { + const scale = getMapDepthScale(yPercent) * (options?.scaleBoost ?? 1) + + return { + left: `${xPercent}%`, + top: `${yPercent}%`, + transform: `translate(-50%, -50%) scale(${scale})`, + zIndex: Math.round(yPercent) + (options?.zBoost ?? 0), + '--depth-scale': scale, + } as Record +} diff --git a/src/utils/storage.ts b/src/utils/storage.ts new file mode 100644 index 0000000..5943c8a --- /dev/null +++ b/src/utils/storage.ts @@ -0,0 +1,39 @@ +const STORAGE_PREFIX = 'gold-land-' + +export function loadFromStorage(key: string, fallback: T): T { + try { + const raw = localStorage.getItem(STORAGE_PREFIX + key) + if (!raw) return fallback + return JSON.parse(raw) as T + } catch { + return fallback + } +} + +export function saveToStorage(key: string, value: T): void { + try { + localStorage.setItem(STORAGE_PREFIX + key, JSON.stringify(value)) + } catch { + // ignore quota errors + } +} + +export function formatNumber(value: number): string { + return new Intl.NumberFormat('fa-IR').format(Math.round(value)) +} + +export function formatDecimal(value: number, digits = 1): string { + return new Intl.NumberFormat('fa-IR', { + minimumFractionDigits: digits, + maximumFractionDigits: digits, + }).format(value) +} + +export function formatCurrency(value: number): string { + return `${formatNumber(value)} تومان` +} + +export function formatPercent(value: number): string { + const sign = value >= 0 ? '+' : '' + return `${sign}${formatDecimal(value, 2)}%` +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..c0f2d86 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + // Extra safety for array and object lookups, but may have false positives. + "noUncheckedIndexedAccess": true, + + // Path mapping for cleaner imports. + "paths": { + "@/*": ["./src/*"] + }, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..c9b2bad --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,27 @@ +// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping. +{ + "extends": "@tsconfig/node24/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + // Most tools use transpilation instead of Node.js's native type-stripping. + // Bundler mode provides a smoother developer experience. + "module": "preserve", + "moduleResolution": "bundler", + + // Include Node.js types and avoid accidentally including other `@types/*` packages. + "types": ["node"], + + // Disable emitting output during `vue-tsc --build`, which is used for type-checking only. + "noEmit": true, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..9fa7469 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,26 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + proxy: { + '/api': { + target: 'http://127.0.0.1:3000', + changeOrigin: true, + }, + }, + }, +})