commit 18b29f5b62478760f8da77984545da2bc673757c
Author: Alireza Hassani
Date: Mon Sep 7 20:50:24 2026 +0330
Initial commit: Mana Collection dashboards (Next.js).
Co-authored-by: Cursor
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..bf07f5b
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,3 @@
+NEXT_PUBLIC_API_URL=http://api.mana-collection.com:3002/api/v1
+NEXT_PUBLIC_STORE_URL=http://store.mana-collection.com:3000
+NEXT_PUBLIC_SITE_URL=http://mana-collection.com:3000
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..11aa0a5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+# dependencies
+node_modules/
+
+# next
+.next/
+out/
+build/
+dist/
+
+# env
+.env
+.env*.local
+!.env.example
+
+# debug / ide
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.DS_Store
+.idea/
+.vscode/
+*.pem
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..643577d
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,9 @@
+
+
+# This is NOT the Next.js you know
+
+This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
+
+This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
+
+
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..43c994c
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+@AGENTS.md
diff --git a/Fonts/Cailyne/Cailyne.otf b/Fonts/Cailyne/Cailyne.otf
new file mode 100644
index 0000000..94665c2
Binary files /dev/null and b/Fonts/Cailyne/Cailyne.otf differ
diff --git a/Fonts/Cailyne/Cailyne.ttf b/Fonts/Cailyne/Cailyne.ttf
new file mode 100644
index 0000000..a61ccd9
Binary files /dev/null and b/Fonts/Cailyne/Cailyne.ttf differ
diff --git a/Fonts/Doran/Doran-Bold.woff b/Fonts/Doran/Doran-Bold.woff
new file mode 100644
index 0000000..08506e0
Binary files /dev/null and b/Fonts/Doran/Doran-Bold.woff differ
diff --git a/Fonts/Doran/Doran-Medium.woff b/Fonts/Doran/Doran-Medium.woff
new file mode 100644
index 0000000..6d7817a
Binary files /dev/null and b/Fonts/Doran/Doran-Medium.woff differ
diff --git a/Fonts/Doran/Doran-Regular.woff b/Fonts/Doran/Doran-Regular.woff
new file mode 100644
index 0000000..dc4a563
Binary files /dev/null and b/Fonts/Doran/Doran-Regular.woff differ
diff --git a/Fonts/Doran/Doran-Thin.woff b/Fonts/Doran/Doran-Thin.woff
new file mode 100644
index 0000000..44fbba7
Binary files /dev/null and b/Fonts/Doran/Doran-Thin.woff differ
diff --git a/Images/Mana-Logo.png b/Images/Mana-Logo.png
new file mode 100644
index 0000000..24bc9ed
Binary files /dev/null and b/Images/Mana-Logo.png differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3264764
--- /dev/null
+++ b/README.md
@@ -0,0 +1,26 @@
+# Mana Collection — Dashboards
+
+Shared Next.js app for **store admin** and **customer** account UI.
+
+## Local domains
+
+```bash
+# once (needs admin password)
+../scripts/setup-hosts.sh
+```
+
+| URL | App |
+|-----|-----|
+| http://store.mana-collection.com:3000 | Store dashboard |
+| http://customer.mana-collection.com:3000 | Customer (same app) |
+| http://api.mana-collection.com:3002/api/v1 | Backend API |
+
+```bash
+cp .env.example .env.local
+npm install
+npm run dev
+```
+
+API: `NEXT_PUBLIC_API_URL` → `http://api.mana-collection.com:3002/api/v1`
+
+Store staff login: phone + password or OTP. Customer registration uses OTP; store panel requires `STORE_ADMIN` / `SUPER_ADMIN`.
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..05e726d
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,18 @@
+import { defineConfig, globalIgnores } from "eslint/config";
+import nextVitals from "eslint-config-next/core-web-vitals";
+import nextTs from "eslint-config-next/typescript";
+
+const eslintConfig = defineConfig([
+ ...nextVitals,
+ ...nextTs,
+ // Override default ignores of eslint-config-next.
+ globalIgnores([
+ // Default ignores of eslint-config-next:
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ ]),
+]);
+
+export default eslintConfig;
diff --git a/next.config.ts b/next.config.ts
new file mode 100644
index 0000000..f69e93c
--- /dev/null
+++ b/next.config.ts
@@ -0,0 +1,27 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ allowedDevOrigins: [
+ "mana-collection.com",
+ "*.mana-collection.com",
+ "store.mana-collection.com",
+ "customer.mana-collection.com",
+ "admin.mana-collection.com",
+ "www.mana-collection.com",
+ ],
+ images: {
+ localPatterns: [
+ {
+ pathname: "/images/**",
+ },
+ ],
+ remotePatterns: [
+ {
+ protocol: "https",
+ hostname: "c804387.parspack.net",
+ },
+ ],
+ },
+};
+
+export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f34647f
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6782 @@
+{
+ "name": "mana-web",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "mana-web",
+ "version": "0.1.0",
+ "dependencies": {
+ "next": "16.3.4",
+ "react": "19.2.8",
+ "react-dom": "19.2.8"
+ },
+ "devDependencies": {
+ "@tailwindcss/postcss": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "eslint": "^9",
+ "eslint-config-next": "16.3.4",
+ "tailwindcss": "^4",
+ "typescript": "^5"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.3.0.tgz",
+ "integrity": "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@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-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-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-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-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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.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.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
+ "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "dev": true,
+ "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.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
+ "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz",
+ "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
+ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.5"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz",
+ "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.14.0",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.3.2",
+ "minimatch": "^3.1.5",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.5",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz",
+ "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz",
+ "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz",
+ "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-freebsd-wasm32": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz",
+ "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.4"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz",
+ "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz",
+ "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz",
+ "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz",
+ "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz",
+ "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz",
+ "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz",
+ "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz",
+ "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz",
+ "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz",
+ "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz",
+ "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz",
+ "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz",
+ "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz",
+ "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz",
+ "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz",
+ "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz",
+ "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz",
+ "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.3"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz",
+ "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==",
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.11.3"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-webcontainers-wasm32": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz",
+ "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.4"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz",
+ "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz",
+ "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz",
+ "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "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.6.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
+ "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
+ "dev": true,
+ "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/@napi-rs/wasm-runtime": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz",
+ "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@tybys/wasm-util": "^0.10.3"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=23.5.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4",
+ "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.4.tgz",
+ "integrity": "sha512-cjWZnUUa6jZq2kFaNe/ZyJdZonOZ/QoN0Zka2nz/FLOrfx14pQuM9c5RaSVkWMqgdt4ksgPAMWPyHSs/CyV48Q==",
+ "license": "MIT"
+ },
+ "node_modules/@next/eslint-plugin-next": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.3.4.tgz",
+ "integrity": "sha512-szW9y2Aumu4z88YXfTzcFsgUAg2k64uzbtcO5L9f1AKS4w/GUKJcbFllRflROVyNPgJtGOnvNxiyp3v6b+prIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "4.9.1",
+ "fast-glob": "3.3.1"
+ }
+ },
+ "node_modules/@next/eslint-plugin-next/node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@next/eslint-plugin-next/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.4.tgz",
+ "integrity": "sha512-iBr3I5LZNk5/bgl5//iTgD2tcym14MX0Xo7fD//u9dYAEgGzza1y9oywluPtf74YnOswVdH1908aK9xVz7zQTw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.4.tgz",
+ "integrity": "sha512-2dpiSyl2Jw/NrBPaU2MAKGSa+2MR82pJIn4Sm5Rjr+gxAeuh0z158Su3Z2O8zn7UNNq+ej4bToed6RcRN/Lydg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.4.tgz",
+ "integrity": "sha512-+t+U8HZT+fApePCS5h89CSH3datz29MkzyfCn+6fpsZBG/oiEOhINcb9rtkv6sdpToLGFn2e6146NzaKCXkqrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.4.tgz",
+ "integrity": "sha512-mx03GNs1ocQA5JQ4FxDMmIsNkdrZh8cuezKCrId28e5/gIPU/l7Kcy2+vmCCzdjnnmXJy+iOAu+7K0QppO6Urg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.4.tgz",
+ "integrity": "sha512-YIhGY6fSMfha52bnVxnzc9zaVBzJg+cqQTOD8tXIBSx4fuv0pVMxQTE0PaS59YhnMOiYiG09IMwxJAf/CFm/Dw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.4.tgz",
+ "integrity": "sha512-+eaaX6axpDb0yF1GCpiERe6njplvdC+nks/fKfcHu3XPGRrald8P3/X7yv7QLdjA51knnxwl9pxdIJsg+w1L+Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.4.tgz",
+ "integrity": "sha512-0jcXW7Xs/uzICrmgV3MhDYDeRy++1CqnpDIerlPIqYO4bhzB4WNbX/aRnQclustsAyTkFKB0z6rbcjmNg5tR8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.4.tgz",
+ "integrity": "sha512-vvBzwu1pYQCp92maZCFCIw/XgOTMR5tur9GjakwIo2cmwRTMKajRZZDS9+e4KsUZWKu1E007WUeAFXRRjZeuzw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nolyfill/is-core-module": {
+ "version": "1.0.39",
+ "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
+ "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.4.0"
+ }
+ },
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.23",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
+ "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
+ "jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz",
+ "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "postcss": "^8.5.16",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "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/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.18",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
+ "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.7.tgz",
+ "integrity": "sha512-I8bPpDLcHBv1qiIiXDCy71Rt8eQDKJP0sMSWJphDdAcdqiJ1sGpZamavoEIRZmYzjia9LuEb2HlYdDpmoENpvQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz",
+ "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.69.0",
+ "@typescript-eslint/type-utils": "8.69.0",
+ "@typescript-eslint/utils": "8.69.0",
+ "@typescript-eslint/visitor-keys": "8.69.0",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.69.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz",
+ "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz",
+ "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.69.0",
+ "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/typescript-estree": "8.69.0",
+ "@typescript-eslint/visitor-keys": "8.69.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz",
+ "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.69.0",
+ "@typescript-eslint/types": "^8.69.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz",
+ "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/visitor-keys": "8.69.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz",
+ "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz",
+ "integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/typescript-estree": "8.69.0",
+ "@typescript-eslint/utils": "8.69.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz",
+ "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz",
+ "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.69.0",
+ "@typescript-eslint/tsconfig-utils": "8.69.0",
+ "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/visitor-keys": "8.69.0",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.8"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz",
+ "integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.69.0",
+ "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/typescript-estree": "8.69.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz",
+ "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.69.0",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz",
+ "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-android-arm64": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz",
+ "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-arm64": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz",
+ "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-x64": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz",
+ "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-freebsd-x64": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz",
+ "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz",
+ "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz",
+ "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz",
+ "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz",
+ "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-loong64-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz",
+ "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-loong64-musl": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz",
+ "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz",
+ "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz",
+ "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz",
+ "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz",
+ "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz",
+ "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-musl": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz",
+ "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-openharmony-arm64": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz",
+ "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-wasm32-wasi": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz",
+ "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "1.10.0",
+ "@emnapi/runtime": "1.10.0",
+ "@napi-rs/wasm-runtime": "^1.1.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz",
+ "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz",
+ "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz",
+ "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/acorn": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
+ "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.0",
+ "es-object-atoms": "^1.1.1",
+ "get-intrinsic": "^1.3.0",
+ "is-string": "^1.1.1",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlast": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+ "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-shim-unscopables": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.tosorted": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+ "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ast-types-flow": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
+ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/async-function": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/axe-core": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz",
+ "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.21",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz",
+ "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.9",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz",
+ "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==",
+ "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.11.20",
+ "caniuse-lite": "^1.0.30001810",
+ "electron-to-chromium": "^1.5.420",
+ "node-releases": "^2.0.54",
+ "update-browserslist-db": "^1.3.2"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
+ "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "get-intrinsic": "^1.3.0",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001810",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
+ "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==",
+ "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/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/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/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/damerau-levenshtein": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/inspect-js"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.422",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz",
+ "integrity": "sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.24.5",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
+ "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.24.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
+ "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "data-view-buffer": "^1.0.2",
+ "data-view-byte-length": "^1.0.2",
+ "data-view-byte-offset": "^1.0.1",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-set-tostringtag": "^2.1.0",
+ "es-to-primitive": "^1.3.0",
+ "function.prototype.name": "^1.1.8",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "get-symbol-description": "^1.1.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.2",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.2.1",
+ "is-set": "^2.0.3",
+ "is-shared-array-buffer": "^1.0.4",
+ "is-string": "^1.1.1",
+ "is-typed-array": "^1.1.15",
+ "is-weakref": "^1.1.1",
+ "math-intrinsics": "^1.1.0",
+ "object-inspect": "^1.13.4",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.7",
+ "own-keys": "^1.0.1",
+ "regexp.prototype.flags": "^1.5.4",
+ "safe-array-concat": "^1.1.3",
+ "safe-push-apply": "^1.0.0",
+ "safe-regex-test": "^1.1.0",
+ "set-proto": "^1.0.0",
+ "stop-iteration-iterator": "^1.1.0",
+ "string.prototype.trim": "^1.2.10",
+ "string.prototype.trimend": "^1.0.9",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-length": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4",
+ "typed-array-length": "^1.0.7",
+ "unbox-primitive": "^1.1.0",
+ "which-typed-array": "^1.1.19"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-abstract-get": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz",
+ "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.2",
+ "is-callable": "^1.2.7",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-iterator-helpers": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz",
+ "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.2",
+ "es-errors": "^1.3.0",
+ "es-set-tostringtag": "^2.1.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.3.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "iterator.prototype": "^1.1.5",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz",
+ "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-abstract-get": "^1.0.0",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.1.0",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.5",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz",
+ "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.2",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.6",
+ "@eslint/js": "9.39.5",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-next": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.3.4.tgz",
+ "integrity": "sha512-35/8RM10huEL9vlr8hUZMERMENHBrnyHN3ZZkF9efSgzGaqK34jIqry44A956//zriUhUAUW0XSkcolhrryqAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@next/eslint-plugin-next": "16.3.4",
+ "eslint-import-resolver-node": "^0.3.6",
+ "eslint-import-resolver-typescript": "^3.5.2",
+ "eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-jsx-a11y": "^6.10.0",
+ "eslint-plugin-react": "^7.37.0",
+ "eslint-plugin-react-hooks": "^7.0.0",
+ "globals": "16.4.0",
+ "typescript-eslint": "^8.46.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=9.0.0",
+ "typescript": ">=3.3.1"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-next/node_modules/globals": {
+ "version": "16.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz",
+ "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.10",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz",
+ "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7",
+ "is-core-module": "^2.16.1",
+ "resolve": "^2.0.0-next.6"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-import-resolver-typescript": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
+ "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@nolyfill/is-core-module": "1.0.39",
+ "debug": "^4.4.0",
+ "get-tsconfig": "^4.10.0",
+ "is-bun-module": "^2.0.0",
+ "stable-hash": "^0.0.5",
+ "tinyglobby": "^0.2.13",
+ "unrs-resolver": "^1.6.2"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-import-resolver-typescript"
+ },
+ "peerDependencies": {
+ "eslint": "*",
+ "eslint-plugin-import": "*",
+ "eslint-plugin-import-x": "*"
+ },
+ "peerDependenciesMeta": {
+ "eslint-plugin-import": {
+ "optional": true
+ },
+ "eslint-plugin-import-x": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz",
+ "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.9",
+ "array.prototype.findlastindex": "^1.2.6",
+ "array.prototype.flat": "^1.3.3",
+ "array.prototype.flatmap": "^1.3.3",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.12.1",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.16.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.1",
+ "semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.9",
+ "tsconfig-paths": "^3.15.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-jsx-a11y": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
+ "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "aria-query": "^5.3.2",
+ "array-includes": "^3.1.8",
+ "array.prototype.flatmap": "^1.3.2",
+ "ast-types-flow": "^0.0.8",
+ "axe-core": "^4.10.0",
+ "axobject-query": "^4.1.0",
+ "damerau-levenshtein": "^1.0.8",
+ "emoji-regex": "^9.2.2",
+ "hasown": "^2.0.2",
+ "jsx-ast-utils": "^3.3.5",
+ "language-tags": "^1.0.9",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.includes": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
+ }
+ },
+ "node_modules/eslint-plugin-react": {
+ "version": "7.37.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.8",
+ "array.prototype.findlast": "^1.2.5",
+ "array.prototype.flatmap": "^1.3.3",
+ "array.prototype.tosorted": "^1.1.4",
+ "doctrine": "^2.1.0",
+ "es-iterator-helpers": "^1.2.1",
+ "estraverse": "^5.3.0",
+ "hasown": "^2.0.2",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "minimatch": "^3.1.2",
+ "object.entries": "^1.1.9",
+ "object.fromentries": "^2.0.8",
+ "object.values": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "resolve": "^2.0.0-next.5",
+ "semver": "^6.3.1",
+ "string.prototype.matchall": "^4.0.12",
+ "string.prototype.repeat": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz",
+ "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+ "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz",
+ "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
+ "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz",
+ "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2",
+ "hasown": "^2.0.4",
+ "is-callable": "^1.2.7",
+ "is-document.all": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.14.3",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz",
+ "integrity": "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-bigints": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/internal-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-async-function": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async-function": "^1.0.0",
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bun-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
+ "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.7.1"
+ }
+ },
+ "node_modules/is-bun-module/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-document.all": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz",
+ "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finalizationregistry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/iterator.prototype": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+ "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "get-proto": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "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/js-yaml": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "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-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/jsx-ast-utils": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+ "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "object.assign": "^4.1.4",
+ "object.values": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/language-subtag-registry": {
+ "version": "0.3.23",
+ "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+ "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/language-tags": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+ "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "language-subtag-registry": "^0.3.20"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "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/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/nanoid": {
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+ "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/napi-postinstall": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
+ "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "napi-postinstall": "lib/cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/napi-postinstall"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/next": {
+ "version": "16.3.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.3.4.tgz",
+ "integrity": "sha512-/Ztf6CeRH+ejEXUrYtqI4gkS66eFIHuSwqi60RgcpWKodxFZx2/dqVCMKBwILfAHXQ+F1b1vAudgj3mnxqtoIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "16.3.4",
+ "@swc/helpers": "0.5.23",
+ "baseline-browser-mapping": "^2.9.19",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.5.23",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "16.3.4",
+ "@next/swc-darwin-x64": "16.3.4",
+ "@next/swc-linux-arm64-gnu": "16.3.4",
+ "@next/swc-linux-arm64-musl": "16.3.4",
+ "@next/swc-linux-x64-gnu": "16.3.4",
+ "@next/swc-linux-x64-musl": "16.3.4",
+ "@next/swc-win32-arm64-msvc": "16.3.4",
+ "@next/swc-win32-x64-msvc": "16.3.4",
+ "sharp": "^0.35.4"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.51.1",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@playwright/test": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/next/node_modules/postcss": {
+ "version": "8.5.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
+ "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
+ "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/node-exports-info": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz",
+ "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array.prototype.flatmap": "^1.3.3",
+ "es-errors": "^1.3.0",
+ "object.entries": "^1.1.9",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.54",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz",
+ "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+ "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/own-keys": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz",
+ "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "get-intrinsic": "^1.3.0",
+ "object-keys": "^1.1.1",
+ "safe-push-apply": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "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": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.28",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
+ "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.18",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/react": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
+ "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
+ "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.8"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.1",
+ "which-builtin-type": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "2.0.0-next.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz",
+ "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.2",
+ "node-exports-info": "^1.6.0",
+ "object-keys": "^1.1.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
+ "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "get-intrinsic": "^1.3.0",
+ "has-symbols": "^1.1.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-push-apply": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/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/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-proto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.35.4",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz",
+ "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/colour": "^1.1.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.8.5"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.35.4",
+ "@img/sharp-darwin-x64": "0.35.4",
+ "@img/sharp-freebsd-wasm32": "0.35.4",
+ "@img/sharp-libvips-darwin-arm64": "1.3.3",
+ "@img/sharp-libvips-darwin-x64": "1.3.3",
+ "@img/sharp-libvips-linux-arm": "1.3.3",
+ "@img/sharp-libvips-linux-arm64": "1.3.3",
+ "@img/sharp-libvips-linux-ppc64": "1.3.3",
+ "@img/sharp-libvips-linux-riscv64": "1.3.3",
+ "@img/sharp-libvips-linux-s390x": "1.3.3",
+ "@img/sharp-libvips-linux-x64": "1.3.3",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.3",
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.3",
+ "@img/sharp-linux-arm": "0.35.4",
+ "@img/sharp-linux-arm64": "0.35.4",
+ "@img/sharp-linux-ppc64": "0.35.4",
+ "@img/sharp-linux-riscv64": "0.35.4",
+ "@img/sharp-linux-s390x": "0.35.4",
+ "@img/sharp-linux-x64": "0.35.4",
+ "@img/sharp-linuxmusl-arm64": "0.35.4",
+ "@img/sharp-linuxmusl-x64": "0.35.4",
+ "@img/sharp-webcontainers-wasm32": "0.35.4",
+ "@img/sharp-win32-arm64": "0.35.4",
+ "@img/sharp-win32-ia32": "0.35.4",
+ "@img/sharp-win32-x64": "0.35.4"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sharp/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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/side-channel": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
+ "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4",
+ "side-channel-list": "^1.0.1",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/stable-hash": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
+ "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/stop-iteration-iterator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+ "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "internal-slot": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.includes": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
+ "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.matchall": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz",
+ "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.2",
+ "get-intrinsic": "^1.3.0",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "regexp.prototype.flags": "^1.5.4",
+ "set-function-name": "^2.0.2",
+ "side-channel": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.repeat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+ "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.11",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz",
+ "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-data-property": "^1.1.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.2",
+ "es-object-atoms": "^1.1.2",
+ "has-property-descriptors": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz",
+ "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/styled-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "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/tinyglobby/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/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+ "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths/node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "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==",
+ "license": "0BSD"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz",
+ "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "for-each": "^0.3.5",
+ "gopd": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "possible-typed-array-names": "^1.1.0",
+ "reflect.getprototypeof": "^1.0.10"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.69.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz",
+ "integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.69.0",
+ "@typescript-eslint/parser": "8.69.0",
+ "@typescript-eslint/typescript-estree": "8.69.0",
+ "@typescript-eslint/utils": "8.69.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "which-boxed-primitive": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unrs-resolver": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz",
+ "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "napi-postinstall": "^0.3.4"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unrs-resolver"
+ },
+ "optionalDependencies": {
+ "@unrs/resolver-binding-android-arm-eabi": "1.12.2",
+ "@unrs/resolver-binding-android-arm64": "1.12.2",
+ "@unrs/resolver-binding-darwin-arm64": "1.12.2",
+ "@unrs/resolver-binding-darwin-x64": "1.12.2",
+ "@unrs/resolver-binding-freebsd-x64": "1.12.2",
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2",
+ "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2",
+ "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-arm64-musl": "1.12.2",
+ "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-loong64-musl": "1.12.2",
+ "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2",
+ "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-x64-gnu": "1.12.2",
+ "@unrs/resolver-binding-linux-x64-musl": "1.12.2",
+ "@unrs/resolver-binding-openharmony-arm64": "1.12.2",
+ "@unrs/resolver-binding-wasm32-wasi": "1.12.2",
+ "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2",
+ "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2",
+ "@unrs/resolver-binding-win32-x64-msvc": "1.12.2"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
+ "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
+ "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/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "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/which-boxed-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.1.0",
+ "is-boolean-object": "^1.2.1",
+ "is-number-object": "^1.1.1",
+ "is-string": "^1.1.1",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.2.1",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.22",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz",
+ "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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"
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz",
+ "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b52eafa
--- /dev/null
+++ b/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "mana-collection-dashboards",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev -H 0.0.0.0 -p 3000",
+ "build": "next build",
+ "start": "next start -H 0.0.0.0 -p 3000",
+ "lint": "eslint"
+ },
+ "dependencies": {
+ "next": "16.3.4",
+ "react": "19.2.8",
+ "react-dom": "19.2.8"
+ },
+ "devDependencies": {
+ "@tailwindcss/postcss": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "eslint": "^9",
+ "eslint-config-next": "16.3.4",
+ "tailwindcss": "^4",
+ "typescript": "^5"
+ }
+}
\ No newline at end of file
diff --git a/postcss.config.mjs b/postcss.config.mjs
new file mode 100644
index 0000000..61e3684
--- /dev/null
+++ b/postcss.config.mjs
@@ -0,0 +1,7 @@
+const config = {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
+};
+
+export default config;
diff --git a/public/file.svg b/public/file.svg
new file mode 100644
index 0000000..004145c
--- /dev/null
+++ b/public/file.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/fonts/Cailyne.otf b/public/fonts/Cailyne.otf
new file mode 100644
index 0000000..94665c2
Binary files /dev/null and b/public/fonts/Cailyne.otf differ
diff --git a/public/fonts/Cailyne.ttf b/public/fonts/Cailyne.ttf
new file mode 100644
index 0000000..a61ccd9
Binary files /dev/null and b/public/fonts/Cailyne.ttf differ
diff --git a/public/fonts/doran/Doran-Bold.woff b/public/fonts/doran/Doran-Bold.woff
new file mode 100644
index 0000000..08506e0
Binary files /dev/null and b/public/fonts/doran/Doran-Bold.woff differ
diff --git a/public/fonts/doran/Doran-Medium.woff b/public/fonts/doran/Doran-Medium.woff
new file mode 100644
index 0000000..6d7817a
Binary files /dev/null and b/public/fonts/doran/Doran-Medium.woff differ
diff --git a/public/fonts/doran/Doran-Regular.woff b/public/fonts/doran/Doran-Regular.woff
new file mode 100644
index 0000000..dc4a563
Binary files /dev/null and b/public/fonts/doran/Doran-Regular.woff differ
diff --git a/public/fonts/doran/Doran-Thin.woff b/public/fonts/doran/Doran-Thin.woff
new file mode 100644
index 0000000..44fbba7
Binary files /dev/null and b/public/fonts/doran/Doran-Thin.woff differ
diff --git a/public/globe.svg b/public/globe.svg
new file mode 100644
index 0000000..567f17b
--- /dev/null
+++ b/public/globe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/Mana-Logo.png b/public/images/Mana-Logo.png
new file mode 100644
index 0000000..0f2ac39
Binary files /dev/null and b/public/images/Mana-Logo.png differ
diff --git a/public/images/ManaLogo.png b/public/images/ManaLogo.png
new file mode 100644
index 0000000..0f2ac39
Binary files /dev/null and b/public/images/ManaLogo.png differ
diff --git a/public/images/ahmad-ebadi-ot28ybNQ-Is-unsplash.jpg b/public/images/ahmad-ebadi-ot28ybNQ-Is-unsplash.jpg
new file mode 100644
index 0000000..926405b
Binary files /dev/null and b/public/images/ahmad-ebadi-ot28ybNQ-Is-unsplash.jpg differ
diff --git a/public/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg b/public/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg
new file mode 100644
index 0000000..caf695c
Binary files /dev/null and b/public/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg differ
diff --git a/public/images/aiony-haust-owp8uQgoK8U-unsplash.jpg b/public/images/aiony-haust-owp8uQgoK8U-unsplash.jpg
new file mode 100644
index 0000000..51cb37c
Binary files /dev/null and b/public/images/aiony-haust-owp8uQgoK8U-unsplash.jpg differ
diff --git a/public/images/amir-asghari-IK3YwAy-nag-unsplash.jpg b/public/images/amir-asghari-IK3YwAy-nag-unsplash.jpg
new file mode 100644
index 0000000..24a235e
Binary files /dev/null and b/public/images/amir-asghari-IK3YwAy-nag-unsplash.jpg differ
diff --git a/public/images/amir-asghari-xoEb3kS_YoM-unsplash.jpg b/public/images/amir-asghari-xoEb3kS_YoM-unsplash.jpg
new file mode 100644
index 0000000..7533b40
Binary files /dev/null and b/public/images/amir-asghari-xoEb3kS_YoM-unsplash.jpg differ
diff --git a/public/images/brand/Mana-Logo-Black.png b/public/images/brand/Mana-Logo-Black.png
new file mode 100644
index 0000000..b6c6709
Binary files /dev/null and b/public/images/brand/Mana-Logo-Black.png differ
diff --git a/public/images/brand/Mana-Logo-White.png b/public/images/brand/Mana-Logo-White.png
new file mode 100644
index 0000000..54433d0
Binary files /dev/null and b/public/images/brand/Mana-Logo-White.png differ
diff --git a/public/images/brand/Mana-Logo.png b/public/images/brand/Mana-Logo.png
new file mode 100644
index 0000000..0f2ac39
Binary files /dev/null and b/public/images/brand/Mana-Logo.png differ
diff --git a/public/images/chyntia-juls-HlVjI5WmoQY-unsplash.jpg b/public/images/chyntia-juls-HlVjI5WmoQY-unsplash.jpg
new file mode 100644
index 0000000..a4938a9
Binary files /dev/null and b/public/images/chyntia-juls-HlVjI5WmoQY-unsplash.jpg differ
diff --git a/public/images/eve-maier-u1OuYQa0WtQ-unsplash.jpg b/public/images/eve-maier-u1OuYQa0WtQ-unsplash.jpg
new file mode 100644
index 0000000..c3c7421
Binary files /dev/null and b/public/images/eve-maier-u1OuYQa0WtQ-unsplash.jpg differ
diff --git a/public/images/image1.jpg b/public/images/image1.jpg
new file mode 100644
index 0000000..926405b
Binary files /dev/null and b/public/images/image1.jpg differ
diff --git a/public/images/image4.jpg b/public/images/image4.jpg
new file mode 100644
index 0000000..4680808
Binary files /dev/null and b/public/images/image4.jpg differ
diff --git a/public/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg b/public/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg
new file mode 100644
index 0000000..4680808
Binary files /dev/null and b/public/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg differ
diff --git a/public/images/mahdi-chaghari-hlyTktLLDvw-unsplash.jpg b/public/images/mahdi-chaghari-hlyTktLLDvw-unsplash.jpg
new file mode 100644
index 0000000..b508d57
Binary files /dev/null and b/public/images/mahdi-chaghari-hlyTktLLDvw-unsplash.jpg differ
diff --git a/public/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg b/public/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg
new file mode 100644
index 0000000..018ef88
Binary files /dev/null and b/public/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg differ
diff --git a/public/images/ryanwar-hanif-98XENwtPMCc-unsplash.jpg b/public/images/ryanwar-hanif-98XENwtPMCc-unsplash.jpg
new file mode 100644
index 0000000..c3486ff
Binary files /dev/null and b/public/images/ryanwar-hanif-98XENwtPMCc-unsplash.jpg differ
diff --git a/public/images/valerie-elash-T5tIoXFJfSk-unsplash.jpg b/public/images/valerie-elash-T5tIoXFJfSk-unsplash.jpg
new file mode 100644
index 0000000..b8cfcbc
Binary files /dev/null and b/public/images/valerie-elash-T5tIoXFJfSk-unsplash.jpg differ
diff --git a/public/next.svg b/public/next.svg
new file mode 100644
index 0000000..5174b28
--- /dev/null
+++ b/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/vercel.svg b/public/vercel.svg
new file mode 100644
index 0000000..7705396
--- /dev/null
+++ b/public/vercel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/window.svg b/public/window.svg
new file mode 100644
index 0000000..b2b2a44
--- /dev/null
+++ b/public/window.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/app/blog/new/page.tsx b/src/app/blog/new/page.tsx
new file mode 100644
index 0000000..7b4397d
--- /dev/null
+++ b/src/app/blog/new/page.tsx
@@ -0,0 +1,374 @@
+"use client";
+
+import Link from "next/link";
+import { useRouter, useSearchParams } from "next/navigation";
+import { ChangeEvent, FormEvent, Suspense, useEffect, useRef, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import ImageCropper from "@/components/ui/ImageCropper";
+import { FormModal } from "@/components/ui/Modal";
+import RichTextArea from "@/components/ui/RichTextArea";
+import { ApiError, uploadMedia } from "@/lib/api";
+import { createBlog, fetchBlog, updateBlog } from "@/lib/blog-api";
+
+const DEFAULT_IMAGE = "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg";
+
+function NewBlogPostForm() {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+ const editId = searchParams.get("edit");
+ const fileRef = useRef(null);
+
+ const [title, setTitle] = useState("");
+ const [date, setDate] = useState(() => new Date().toISOString().slice(0, 10));
+ const [author, setAuthor] = useState("");
+ const [abstract, setAbstract] = useState("");
+ const [body, setBody] = useState("");
+ const [imagePreview, setImagePreview] = useState(DEFAULT_IMAGE);
+ const [imageFile, setImageFile] = useState(null);
+ const [tags, setTags] = useState([]);
+ const [tagInput, setTagInput] = useState("");
+ const [metaOpen, setMetaOpen] = useState(false);
+ const [metaTitle, setMetaTitle] = useState("");
+ const [metaDescription, setMetaDescription] = useState("");
+ const [metaKeywords, setMetaKeywords] = useState("");
+ const [saving, setSaving] = useState(false);
+ const [loading, setLoading] = useState(Boolean(editId));
+ const [error, setError] = useState(null);
+
+ const hasMeta = Boolean(
+ metaTitle.trim() || metaDescription.trim() || metaKeywords.trim(),
+ );
+
+ useEffect(() => {
+ if (!editId) return;
+ let cancelled = false;
+ (async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const post = await fetchBlog(editId);
+ if (cancelled) return;
+ setTitle(post.title);
+ setDate(post.date);
+ setAuthor(post.author);
+ setAbstract(post.abstract);
+ setBody(post.body);
+ setImagePreview(post.image);
+ setTags(post.tags);
+ setMetaTitle(post.metaTitle);
+ setMetaDescription(post.metaDescription);
+ setMetaKeywords(post.metaKeywords);
+ } catch (err) {
+ if (!cancelled) {
+ setError(
+ err instanceof ApiError
+ ? err.message
+ : "بارگذاری مطلب ناموفق بود.",
+ );
+ }
+ } finally {
+ if (!cancelled) setLoading(false);
+ }
+ })();
+ return () => {
+ cancelled = true;
+ };
+ }, [editId]);
+
+ function handleImageChange(event: ChangeEvent) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ setImageFile(file);
+ setImagePreview(URL.createObjectURL(file));
+ }
+
+ function addTag() {
+ const next = tagInput.trim();
+ if (!next || tags.includes(next)) return;
+ setTags((prev) => [...prev, next]);
+ setTagInput("");
+ }
+
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault();
+ if (!title.trim()) {
+ setError("عنوان الزامی است.");
+ return;
+ }
+
+ setSaving(true);
+ setError(null);
+ try {
+ let imageUrl: string | undefined;
+ let imageKey: string | undefined;
+ if (imageFile) {
+ const uploaded = await uploadMedia(imageFile, "blog");
+ imageUrl = uploaded.url;
+ imageKey = uploaded.storageKey;
+ }
+
+ const payload = {
+ title: title.trim(),
+ summary: abstract.trim() || undefined,
+ body: body || undefined,
+ author: author.trim() || undefined,
+ metaTitle: metaTitle.trim() || undefined,
+ metaDescription: metaDescription.trim() || undefined,
+ published: true,
+ ...(imageUrl ? { imageUrl, imageKey } : {}),
+ };
+
+ if (editId) {
+ await updateBlog(editId, payload);
+ } else {
+ await createBlog(payload);
+ }
+
+ router.push("/blog");
+ router.refresh();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ثبت مطلب ناموفق بود.",
+ );
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ function saveMeta(event: FormEvent) {
+ event.preventDefault();
+ setMetaOpen(false);
+ }
+
+ return (
+ <>
+
+ {loading ? (
+ در حال بارگذاری...
+ ) : (
+
+ )}
+
+
+ setMetaOpen(false)}
+ onSubmit={saveMeta}
+ submitLabel="ذخیره متا"
+ >
+
+
+ setMetaTitle(e.target.value)}
+ placeholder="SEO title"
+ />
+
+
+
+
+
+
+ setMetaKeywords(e.target.value)}
+ placeholder="keyword, keyword"
+ />
+
+
+ >
+ );
+}
+
+export default function NewBlogPostPage() {
+ return (
+ در حال بارگذاری...
}>
+
+
+ );
+}
diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx
new file mode 100644
index 0000000..47d3d99
--- /dev/null
+++ b/src/app/blog/page.tsx
@@ -0,0 +1,354 @@
+"use client";
+
+import Image from "next/image";
+import { useRouter } from "next/navigation";
+import { FormEvent, useCallback, useEffect, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import IconButton, {
+ ClearFilterIcon,
+ EditIcon,
+ FilterIcon,
+ MetaTagsIcon,
+ TrashIcon,
+} from "@/components/ui/IconButton";
+import { FormModal } from "@/components/ui/Modal";
+import Pagination, { usePagination } from "@/components/ui/Pagination";
+import { BlogPost, formatBlogDate } from "@/data/blog";
+import { ApiError } from "@/lib/api";
+import { deleteBlog, fetchBlogs, updateBlog } from "@/lib/blog-api";
+import { useConfirm } from "@/components/ui/ConfirmDialog";
+
+const PAGE_SIZE = 3;
+
+type Filters = {
+ name: string;
+ dateFrom: string;
+ dateTo: string;
+};
+
+const emptyFilters: Filters = {
+ name: "",
+ dateFrom: "",
+ dateTo: "",
+};
+
+export default function BlogListPage() {
+ const router = useRouter();
+ const confirmDialog = useConfirm();
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [draft, setDraft] = useState(emptyFilters);
+ const [applied, setApplied] = useState(emptyFilters);
+ const [metaPost, setMetaPost] = useState(null);
+ const [metaTitle, setMetaTitle] = useState("");
+ const [metaDescription, setMetaDescription] = useState("");
+ const [metaKeywords, setMetaKeywords] = useState("");
+ const [savingMeta, setSavingMeta] = useState(false);
+
+ const reload = useCallback(async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ setItems(await fetchBlogs());
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "بارگذاری بلاگ ناموفق بود.",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ void reload();
+ }, [reload]);
+
+ const list = items.filter((post) => {
+ const q = applied.name.trim();
+ const matchesName =
+ !q ||
+ post.title.includes(q) ||
+ post.author.includes(q) ||
+ post.abstract.includes(q);
+
+ const fromOk = !applied.dateFrom || post.date >= applied.dateFrom;
+ const toOk = !applied.dateTo || post.date <= applied.dateTo;
+
+ return matchesName && fromOk && toOk;
+ });
+
+ const { page, setPage, pageItems, totalPages, totalItems, pageSize } =
+ usePagination(list, PAGE_SIZE, JSON.stringify(applied));
+
+ function openMeta(post: BlogPost) {
+ setMetaPost(post);
+ setMetaTitle(post.metaTitle);
+ setMetaDescription(post.metaDescription);
+ setMetaKeywords(post.metaKeywords);
+ }
+
+ function closeMeta() {
+ setMetaPost(null);
+ }
+
+ async function saveMeta(event: FormEvent) {
+ event.preventDefault();
+ if (!metaPost) return;
+ setSavingMeta(true);
+ setError(null);
+ try {
+ const updated = await updateBlog(metaPost.id, {
+ metaTitle: metaTitle.trim() || null,
+ metaDescription: metaDescription.trim() || null,
+ });
+ setItems((prev) =>
+ prev.map((post) =>
+ post.id === metaPost.id
+ ? { ...updated, metaKeywords: metaKeywords.trim() }
+ : post,
+ ),
+ );
+ closeMeta();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ذخیره متا ناموفق بود.",
+ );
+ } finally {
+ setSavingMeta(false);
+ }
+ }
+
+ async function removePost(id: string) {
+ if (!(await confirmDialog("این مطلب حذف شود؟"))) return;
+ setError(null);
+ try {
+ await deleteBlog(id);
+ setItems((prev) => prev.filter((post) => post.id !== id));
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "حذف مطلب ناموفق بود.",
+ );
+ }
+ }
+
+ return (
+ <>
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+
+
+ {loading ? (
+ در حال بارگذاری...
+ ) : (
+ <>
+
+ {pageItems.map((post, i) => (
+
+
+
+
+
+
+
+
+ {post.title}
+
+
+
+
{post.author}
+
+ {post.abstract}
+
+ {post.tags.length ? (
+
+ {post.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+ ) : null}
+
+
+
+ router.push(`/blog/new?edit=${post.id}`)}
+ >
+
+
+ openMeta(post)}
+ >
+
+
+ void removePost(post.id)}
+ >
+
+
+
+
+ ))}
+
+ {list.length === 0 ? (
+
+ مطلبی با این فیلترها پیدا نشد.
+
+ ) : null}
+
+
+ {list.length > 0 ? (
+
+ ) : null}
+ >
+ )}
+
+
+
+
+
+ setMetaTitle(e.target.value)}
+ placeholder="SEO title"
+ />
+
+
+
+
+
+
+ setMetaKeywords(e.target.value)}
+ placeholder="keyword, keyword"
+ />
+
+
+ >
+ );
+}
diff --git a/src/app/clothes/brands/page.tsx b/src/app/clothes/brands/page.tsx
new file mode 100644
index 0000000..a52da2e
--- /dev/null
+++ b/src/app/clothes/brands/page.tsx
@@ -0,0 +1,298 @@
+"use client";
+
+import { ChangeEvent, FormEvent, useCallback, useEffect, useRef, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import IconButton, {
+ EditIcon,
+ TrashIcon,
+} from "@/components/ui/IconButton";
+import ImageCropper from "@/components/ui/ImageCropper";
+import { FormModal } from "@/components/ui/Modal";
+import type { Brand } from "@/data/clothes";
+import { ApiError, uploadMedia } from "@/lib/api";
+import {
+ createBrand,
+ deleteBrand,
+ fetchBrands,
+ updateBrand,
+} from "@/lib/clothes-api";
+import { useConfirm } from "@/components/ui/ConfirmDialog";
+
+type AspectRatio = "1:1" | "3:2";
+
+const DEFAULT_IMAGE = "/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg";
+
+export default function BrandsPage() {
+ const confirmDialog = useConfirm();
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [saving, setSaving] = useState(false);
+ const [modalOpen, setModalOpen] = useState(false);
+ const [editingId, setEditingId] = useState(null);
+ const [nameFa, setNameFa] = useState("");
+ const [nameEn, setNameEn] = useState("");
+ const [aspect, setAspect] = useState("1:1");
+ const [imagePreview, setImagePreview] = useState(DEFAULT_IMAGE);
+ const [imageFile, setImageFile] = useState(null);
+ const fileInputRef = useRef(null);
+
+ const reload = useCallback(async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ setItems(await fetchBrands());
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "بارگذاری برندها ناموفق بود.",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ void reload();
+ }, [reload]);
+
+ function resetForm() {
+ setEditingId(null);
+ setNameFa("");
+ setNameEn("");
+ setAspect("1:1");
+ setImagePreview(DEFAULT_IMAGE);
+ setImageFile(null);
+ if (fileInputRef.current) fileInputRef.current.value = "";
+ }
+
+ function closeModal() {
+ setModalOpen(false);
+ resetForm();
+ }
+
+ function openCreate() {
+ resetForm();
+ setModalOpen(true);
+ }
+
+ function openEdit(brand: Brand) {
+ setEditingId(brand.id);
+ setNameFa(brand.nameFa);
+ setNameEn(brand.nameEn);
+ setImagePreview(brand.image || DEFAULT_IMAGE);
+ setImageFile(null);
+ setModalOpen(true);
+ }
+
+ function handleImageChange(event: ChangeEvent) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ setImageFile(file);
+ setImagePreview(URL.createObjectURL(file));
+ }
+
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault();
+ if (!nameFa.trim()) return;
+ setSaving(true);
+ setError(null);
+ try {
+ let imageUrl: string | undefined;
+ let imageKey: string | undefined;
+ if (imageFile) {
+ const uploaded = await uploadMedia(imageFile, "brand");
+ imageUrl = uploaded.url;
+ imageKey = uploaded.storageKey;
+ }
+
+ if (editingId) {
+ await updateBrand(editingId, {
+ nameFa: nameFa.trim(),
+ nameEn: nameEn.trim() || undefined,
+ ...(imageUrl ? { imageUrl, imageKey } : {}),
+ });
+ } else {
+ await createBrand({
+ nameFa: nameFa.trim(),
+ nameEn: nameEn.trim() || undefined,
+ imageUrl,
+ imageKey,
+ });
+ }
+ await reload();
+ closeModal();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ذخیره برند ناموفق بود.",
+ );
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ async function handleDelete(id: string) {
+ if (!(await confirmDialog("این برند حذف شود؟"))) return;
+ setError(null);
+ try {
+ await deleteBrand(id);
+ setItems((prev) => prev.filter((item) => item.id !== id));
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "حذف برند ناموفق بود.",
+ );
+ }
+ }
+
+ return (
+ <>
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+ {loading ? (
+ در حال بارگذاری...
+ ) : (
+
+ {items.length === 0 ? (
+
+ هنوز برندی ثبت نشده است.
+
+ ) : null}
+ {items.map((brand, i) => (
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+

+
+
+
+
{brand.nameFa}
+
+ {brand.nameEn}
+
+
+
+
+ openEdit(brand)}
+ >
+
+
+ void handleDelete(brand.id)}
+ >
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+
+
+ تصویر برند
+
+
+
+
+
+
+
+ setNameFa(e.target.value)}
+ placeholder="مثلاً مانا"
+ required
+ />
+
+
+
+ setNameEn(e.target.value)}
+ placeholder="Mana"
+ />
+
+
+ >
+ );
+}
diff --git a/src/app/clothes/categories/page.tsx b/src/app/clothes/categories/page.tsx
new file mode 100644
index 0000000..a0ded29
--- /dev/null
+++ b/src/app/clothes/categories/page.tsx
@@ -0,0 +1,627 @@
+"use client";
+
+import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import IconButton, {
+ AddChildIcon,
+ EditIcon,
+ TrashIcon,
+ VariantIcon,
+} from "@/components/ui/IconButton";
+import { FormModal } from "@/components/ui/Modal";
+import {
+ CategoryNode,
+ CategoryVariants,
+ colorCatalog,
+ emptyVariants,
+ flattenCategories,
+ packageCatalog,
+ sizeCatalog,
+} from "@/data/clothes";
+import { ApiError } from "@/lib/api";
+import {
+ createCategory,
+ deleteCategory,
+ fetchCategoriesTree,
+ updateCategory,
+} from "@/lib/clothes-api";
+import { useConfirm } from "@/components/ui/ConfirmDialog";
+
+export default function CategoriesPage() {
+ const confirmDialog = useConfirm();
+ const [tree, setTree] = useState([]);
+ const [open, setOpen] = useState>({});
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [saving, setSaving] = useState(false);
+
+ const [modalOpen, setModalOpen] = useState(false);
+ const [editingId, setEditingId] = useState(null);
+ const [nameFa, setNameFa] = useState("");
+ const [nameEn, setNameEn] = useState("");
+ const [parentId, setParentId] = useState("");
+
+ const [variantTarget, setVariantTarget] = useState(null);
+ const [draftVariants, setDraftVariants] = useState(
+ emptyVariants(),
+ );
+ const [enabledTypes, setEnabledTypes] = useState({
+ color: false,
+ size: false,
+ package: false,
+ });
+
+ const parentOptions = useMemo(() => flattenCategories(tree), [tree]);
+
+ const reload = useCallback(async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const cats = await fetchCategoriesTree();
+ setTree(cats);
+ setOpen((prev) => {
+ const next = { ...prev };
+ for (const opt of flattenCategories(cats)) {
+ if (next[opt.id] === undefined) next[opt.id] = true;
+ }
+ return next;
+ });
+ } catch (err) {
+ setError(
+ err instanceof ApiError
+ ? err.message
+ : "بارگذاری دستهها ناموفق بود.",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ void reload();
+ }, [reload]);
+
+ function toggle(id: string) {
+ setOpen((prev) => ({ ...prev, [id]: !prev[id] }));
+ }
+
+ function resetForm() {
+ setEditingId(null);
+ setNameFa("");
+ setNameEn("");
+ setParentId("");
+ }
+
+ function closeModal() {
+ setModalOpen(false);
+ resetForm();
+ }
+
+ function openCreate(parent?: string) {
+ resetForm();
+ setParentId(parent ?? "");
+ setModalOpen(true);
+ }
+
+ function openEdit(node: CategoryNode) {
+ setEditingId(node.id);
+ setNameFa(node.nameFa);
+ setNameEn(node.nameEn);
+ setParentId("");
+ setModalOpen(true);
+ }
+
+ function openVariants(node: CategoryNode) {
+ const current = node.variants ?? emptyVariants();
+ setVariantTarget(node);
+ setDraftVariants(current);
+ setEnabledTypes({
+ color: current.colors.length > 0,
+ size: current.sizes.length > 0,
+ package: current.packages.length > 0,
+ });
+ }
+
+ function closeVariants() {
+ setVariantTarget(null);
+ }
+
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault();
+ if (!nameFa.trim()) return;
+ setSaving(true);
+ setError(null);
+ try {
+ if (editingId) {
+ const next = await updateCategory(editingId, {
+ nameFa: nameFa.trim(),
+ nameEn: nameEn.trim() || undefined,
+ });
+ setTree(next);
+ } else {
+ const next = await createCategory({
+ nameFa: nameFa.trim(),
+ nameEn: nameEn.trim() || undefined,
+ parentId: parentId || undefined,
+ });
+ setTree(next);
+ if (parentId) setOpen((prev) => ({ ...prev, [parentId]: true }));
+ }
+ closeModal();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ذخیره دسته ناموفق بود.",
+ );
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ async function handleDelete(id: string) {
+ if (!(await confirmDialog("این دسته حذف شود؟"))) return;
+ setError(null);
+ try {
+ const next = await deleteCategory(id);
+ setTree(next);
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "حذف دسته ناموفق بود.",
+ );
+ }
+ }
+
+ function toggleValue(
+ field: "colors" | "sizes" | "packages",
+ value: string,
+ ) {
+ setDraftVariants((prev) => {
+ const list = prev[field] as string[];
+ const next = list.includes(value)
+ ? list.filter((item) => item !== value)
+ : [...list, value];
+ return { ...prev, [field]: next };
+ });
+ }
+
+ const allColorsSelected =
+ colorCatalog.length > 0 &&
+ colorCatalog.every((color) => draftVariants.colors.includes(color.id));
+ const allSizesSelected =
+ sizeCatalog.length > 0 &&
+ sizeCatalog.every((size) => draftVariants.sizes.includes(size.id));
+
+ function toggleAllColors() {
+ setDraftVariants((prev) => ({
+ ...prev,
+ colors: allColorsSelected ? [] : colorCatalog.map((color) => color.id),
+ }));
+ }
+
+ function toggleAllSizes() {
+ setDraftVariants((prev) => ({
+ ...prev,
+ sizes: allSizesSelected ? [] : sizeCatalog.map((size) => size.id),
+ }));
+ }
+
+ async function handleVariantsSubmit(event: FormEvent) {
+ event.preventDefault();
+ if (!variantTarget) return;
+ setSaving(true);
+ setError(null);
+ try {
+ const nextTree = await updateCategory(variantTarget.id, {
+ colors: enabledTypes.color ? draftVariants.colors : [],
+ sizes: enabledTypes.size ? draftVariants.sizes : [],
+ packages: enabledTypes.package ? draftVariants.packages : [],
+ });
+ setTree(nextTree);
+ closeVariants();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ذخیره تنوع ناموفق بود.",
+ );
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ return (
+ <>
+ openCreate()}
+ plusLabel="دسته جدید"
+ >
+ {error ? (
+
+ {error}
+
+ ) : null}
+ {loading ? (
+ در حال بارگذاری...
+ ) : (
+
+ {tree.length === 0 ? (
+
+ هنوز دستهای ثبت نشده است.
+
+ ) : null}
+ {tree.map((node, i) => (
+
openCreate(id)}
+ onVariants={openVariants}
+ onDelete={handleDelete}
+ delay={80 + i * 60}
+ />
+ ))}
+
+ )}
+
+
+
+ {!editingId ? (
+
+
+
+
+ ) : null}
+
+
+ setNameFa(e.target.value)}
+ placeholder="مثلاً مانتو"
+ required
+ />
+
+
+
+ setNameEn(e.target.value)}
+ placeholder="Manteau"
+ />
+
+
+
+
+
+ مشخص کنید این دسته کدام تنوعها را دارد.
+
+
+
+
+
+
+
+
+ >
+ );
+}
+
+function CategoryBranch({
+ node,
+ depth,
+ number,
+ open,
+ onToggle,
+ onEdit,
+ onAddChild,
+ onVariants,
+ onDelete,
+ delay,
+}: {
+ node: CategoryNode;
+ depth: number;
+ number: string;
+ open: Record;
+ onToggle: (id: string) => void;
+ onEdit: (node: CategoryNode) => void;
+ onAddChild: (id: string) => void;
+ onVariants: (node: CategoryNode) => void;
+ onDelete: (id: string) => void;
+ delay: number;
+}) {
+ const hasChildren = Boolean(node.children?.length);
+ const isOpen = open[node.id] ?? false;
+ const variantCount =
+ (node.variants?.colors.length ? 1 : 0) +
+ (node.variants?.sizes.length ? 1 : 0) +
+ (node.variants?.packages.length ? 1 : 0);
+
+ return (
+
+
+
+ {hasChildren ? (
+
+ ) : (
+
+ )}
+
+ {number}
+
+
+
{node.nameFa}
+
+ {node.nameEn}
+
+
+
+
+
+
onEdit(node)}>
+
+
+
onAddChild(node.id)}
+ >
+
+
+
onVariants(node)}
+ >
+
+
+
onDelete(node.id)}
+ >
+
+
+
+
+
+ {hasChildren && isOpen
+ ? node.children!.map((child, i) => (
+
+ ))
+ : null}
+
+ );
+}
+
+function ChevronDownIcon() {
+ return (
+
+ );
+}
+
+function ChevronLeftIcon() {
+ return (
+
+ );
+}
diff --git a/src/app/clothes/list/page.tsx b/src/app/clothes/list/page.tsx
new file mode 100644
index 0000000..7ffe933
--- /dev/null
+++ b/src/app/clothes/list/page.tsx
@@ -0,0 +1,886 @@
+"use client";
+
+import Image from "next/image";
+import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import IconButton, {
+ ClearFilterIcon,
+ DiscountIcon,
+ EditIcon,
+ FilterIcon,
+ TrashIcon,
+ VariantIcon,
+} from "@/components/ui/IconButton";
+import Modal, { FormModal } from "@/components/ui/Modal";
+import Pagination, { usePagination } from "@/components/ui/Pagination";
+import {
+ Brand,
+ CategoryNode,
+ discountPercent,
+ findCategoryNode,
+ flattenCategories,
+ formatPrice,
+ getCategoryVariantGroups,
+ getVariantLabel,
+ Product,
+ ProductVariantPrice,
+} from "@/data/clothes";
+import {
+ deleteProduct,
+ fetchBrands,
+ fetchCategoriesTree,
+ fetchProducts,
+ toVariantPayload,
+ updateProduct,
+} from "@/lib/clothes-api";
+import { ApiError } from "@/lib/api";
+import { useConfirm } from "@/components/ui/ConfirmDialog";
+
+const PAGE_SIZE = 4;
+
+type Filters = {
+ name: string;
+ categoryId: string;
+ priceMin: string;
+ priceMax: string;
+};
+
+const emptyFilters: Filters = {
+ name: "",
+ categoryId: "",
+ priceMin: "",
+ priceMax: "",
+};
+
+function emptyVariantRow(price = ""): ProductVariantPrice {
+ return {
+ id: `vp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
+ colorId: "",
+ sizeId: "",
+ packageId: "",
+ price,
+ discountPrice: "",
+ };
+}
+
+function isBaseRow(row: ProductVariantPrice) {
+ return !row.colorId && !row.sizeId && !row.packageId;
+}
+
+export default function ProductListPage() {
+ const confirmDialog = useConfirm();
+ const [categoryTree, setCategoryTree] = useState([]);
+ const [brands, setBrands] = useState([]);
+ const categoryOptions = useMemo(
+ () => flattenCategories(categoryTree),
+ [categoryTree],
+ );
+ const brandById = useMemo(
+ () => new Map(brands.map((b) => [b.id, b])),
+ [brands],
+ );
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [loadError, setLoadError] = useState(null);
+ const [draft, setDraft] = useState(emptyFilters);
+ const [applied, setApplied] = useState(emptyFilters);
+ const [detailProduct, setDetailProduct] = useState(null);
+
+ const [variantProduct, setVariantProduct] = useState(null);
+ const [variantRows, setVariantRows] = useState([
+ emptyVariantRow(),
+ ]);
+
+ const [discountProduct, setDiscountProduct] = useState(null);
+ const [discountRows, setDiscountRows] = useState([]);
+
+ const reload = useCallback(async () => {
+ setLoading(true);
+ setLoadError(null);
+ try {
+ const [products, cats, brandRows] = await Promise.all([
+ fetchProducts({
+ name: applied.name.trim() || undefined,
+ categoryId: applied.categoryId || undefined,
+ minPrice: applied.priceMin ? Number(applied.priceMin) : undefined,
+ maxPrice: applied.priceMax ? Number(applied.priceMax) : undefined,
+ }),
+ fetchCategoriesTree(),
+ fetchBrands(),
+ ]);
+ setItems(products);
+ setCategoryTree(cats);
+ setBrands(brandRows);
+ } catch (err) {
+ setLoadError(
+ err instanceof ApiError
+ ? err.message
+ : "بارگذاری محصولات ناموفق بود. آیا API روشن است؟",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, [applied]);
+
+ useEffect(() => {
+ void reload();
+ }, [reload]);
+
+ const list = items;
+
+ const { page, setPage, pageItems, totalPages, totalItems, pageSize } =
+ usePagination(list, PAGE_SIZE, JSON.stringify(applied));
+
+ const variantGroups = useMemo(
+ () =>
+ variantProduct
+ ? getCategoryVariantGroups(variantProduct.categoryId, categoryTree)
+ : { colors: [], sizes: [], packages: [] },
+ [variantProduct, categoryTree],
+ );
+
+ const hasAnyVariantOption =
+ variantGroups.colors.length > 0 ||
+ variantGroups.sizes.length > 0 ||
+ variantGroups.packages.length > 0;
+
+ function openVariants(product: Product) {
+ setVariantProduct(product);
+ setVariantRows(
+ product.variantPrices?.length
+ ? product.variantPrices.map((row) => ({ ...row }))
+ : [emptyVariantRow(String(product.price))],
+ );
+ }
+
+ function closeVariants() {
+ setVariantProduct(null);
+ }
+
+ function openDiscount(product: Product) {
+ setDiscountProduct(product);
+ if (product.variantPrices?.length) {
+ setDiscountRows(product.variantPrices.map((row) => ({ ...row })));
+ } else {
+ setDiscountRows([
+ {
+ ...emptyVariantRow(String(product.price)),
+ discountPrice:
+ typeof product.discountPrice === "number"
+ ? String(product.discountPrice)
+ : "",
+ },
+ ]);
+ }
+ }
+
+ function closeDiscount() {
+ setDiscountProduct(null);
+ }
+
+ function updateRow(
+ id: string,
+ field: keyof Omit,
+ value: string,
+ ) {
+ setVariantRows((prev) =>
+ prev.map((row) => (row.id === id ? { ...row, [field]: value } : row)),
+ );
+ }
+
+ function updateDiscountPrice(id: string, value: string) {
+ setDiscountRows((prev) =>
+ prev.map((row) =>
+ row.id === id ? { ...row, discountPrice: value } : row,
+ ),
+ );
+ }
+
+ function addRow() {
+ setVariantRows((prev) => [
+ ...prev,
+ emptyVariantRow(variantProduct ? String(variantProduct.price) : ""),
+ ]);
+ }
+
+ function removeRow(id: string) {
+ setVariantRows((prev) =>
+ prev.length <= 1 ? prev : prev.filter((row) => row.id !== id),
+ );
+ }
+
+ async function saveVariants(event: FormEvent) {
+ event.preventDefault();
+ if (!variantProduct) return;
+ try {
+ const updated = await updateProduct(variantProduct.id, {
+ variants: toVariantPayload(variantRows),
+ });
+ setItems((prev) =>
+ prev.map((product) =>
+ product.id === updated.id ? updated : product,
+ ),
+ );
+ closeVariants();
+ } catch (err) {
+ alert(err instanceof ApiError ? err.message : "ذخیره تنوع ناموفق بود");
+ }
+ }
+
+ async function saveDiscount(event: FormEvent) {
+ event.preventDefault();
+ if (!discountProduct) return;
+
+ const nextRows = discountRows.map((row) => ({ ...row }));
+ const discounted = nextRows
+ .map((row) => Number(row.discountPrice))
+ .filter((n) => !Number.isNaN(n) && n > 0);
+ const hadVariants = Boolean(discountProduct.variantPrices?.length);
+ const baseDiscount = nextRows.find((row) => isBaseRow(row))?.discountPrice;
+ const nextProductDiscount = baseDiscount
+ ? Number(baseDiscount) || null
+ : discounted.length
+ ? Math.min(...discounted)
+ : null;
+
+ try {
+ const updated = await updateProduct(discountProduct.id, {
+ discountPrice: nextProductDiscount,
+ ...(hadVariants
+ ? { variants: toVariantPayload(nextRows) }
+ : {}),
+ });
+ setItems((prev) =>
+ prev.map((product) =>
+ product.id === updated.id ? updated : product,
+ ),
+ );
+ closeDiscount();
+ } catch (err) {
+ alert(err instanceof ApiError ? err.message : "ذخیره تخفیف ناموفق بود");
+ }
+ }
+
+ async function handleDelete(productId: string) {
+ if (!(await confirmDialog("این محصول حذف شود؟"))) return;
+ try {
+ await deleteProduct(productId);
+ setItems((prev) => prev.filter((p) => p.id !== productId));
+ } catch (err) {
+ alert(err instanceof ApiError ? err.message : "حذف ناموفق بود");
+ }
+ }
+
+ return (
+ <>
+
+
+
+ {loadError ? (
+ {loadError}
+ ) : null}
+ {loading ? (
+ در حال بارگذاری محصولات…
+ ) : null}
+
+
+ {!loading && pageItems.length === 0 ? (
+
+ محصولی یافت نشد.
+
+ ) : null}
+ {pageItems.map((product, i) => {
+ const hasDiscount =
+ typeof product.discountPrice === "number" &&
+ product.discountPrice < product.price;
+ const percent = hasDiscount
+ ? discountPercent(product.price, product.discountPrice!)
+ : null;
+ const variantCount = product.variantPrices?.length ?? 0;
+ const discountCount = product.variantPrices?.length
+ ? product.variantPrices.filter((row) => {
+ const n = Number(row.discountPrice);
+ return row.discountPrice && !Number.isNaN(n) && n > 0;
+ }).length
+ : hasDiscount
+ ? 1
+ : 0;
+
+ return (
+
setDetailProduct(product)}
+ >
+
+
+ {percent ? (
+
+ {percent}%-
+
+ ) : null}
+
+
+
+
+ {product.nameFa}
+
+
+ {product.nameEn}
+
+
+ {hasDiscount ? (
+ <>
+
+
+ {formatPrice(product.discountPrice!)}
+
+ تومان
+
+
+
+ {formatPrice(product.price)}
+
+ تومان
+
+ >
+ ) : (
+
+
+ {formatPrice(product.price)}
+
+ تومان
+
+ )}
+
+
+
+ e.stopPropagation()}
+ >
+
+
+
+ void handleDelete(product.id)}
+ >
+
+
+ openVariants(product)}
+ >
+
+
+ openDiscount(product)}
+ >
+
+
+
+
+ );
+ })}
+
+
+ {list.length === 0 ? (
+
+ محصولی با این فیلترها پیدا نشد.
+
+ ) : (
+
+ )}
+
+
+ setDetailProduct(null)}
+ wide="full"
+ footer={
+
+ }
+ >
+ {detailProduct ? (
+
+
+
+
+
+
+ {(detailProduct.gallery?.length ?? 0) > 0 ? (
+
+
گالری
+
+ {detailProduct.gallery!.map((src) => (
+
+
+
+ ))}
+
+
+ ) : null}
+
+
+
+
+
+ {detailProduct.nameFa}
+
+ {detailProduct.nameEn ? (
+
+ {detailProduct.nameEn}
+
+ ) : null}
+
+
+
+
+
- دستهبندی
+ -
+ {findCategoryNode(categoryTree, detailProduct.categoryId)
+ ?.nameFa || "—"}
+
+
+
+
- برند
+ -
+ {brandById.get(detailProduct.brandId)?.nameFa || "—"}
+
+
+
+
- قیمت
+ -
+ {typeof detailProduct.discountPrice === "number" &&
+ detailProduct.discountPrice < detailProduct.price ? (
+ <>
+
+
+ {formatPrice(detailProduct.discountPrice)}
+
+ تومان
+
+
+
+ {formatPrice(detailProduct.price)}
+
+ تومان
+
+ >
+ ) : (
+
+
+ {formatPrice(detailProduct.price)}
+
+ تومان
+
+ )}
+
+
+
+
+ {detailProduct.summary ? (
+
+
خلاصه
+
+ {detailProduct.summary}
+
+
+ ) : null}
+
+ {detailProduct.description ? (
+
+
توضیحات
+
+ {detailProduct.description}
+
+
+ ) : null}
+
+ {detailProduct.tags.length ? (
+
+
برچسبها
+
+ {detailProduct.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+
+ ) : null}
+
+
+
تنوعها
+ {detailProduct.variantPrices?.length ? (
+
+ {detailProduct.variantPrices.map((row) => {
+ const rowDiscount = Number(row.discountPrice);
+ const hasRowDiscount =
+ row.discountPrice &&
+ !Number.isNaN(rowDiscount) &&
+ rowDiscount > 0;
+ return (
+ -
+
+ {getVariantLabel(
+ row,
+ detailProduct.categoryId,
+ categoryTree,
+ )}
+
+
+ {hasRowDiscount ? (
+ <>
+
+ {formatPrice(rowDiscount)}
+
+
+ {formatPrice(Number(row.price) || 0)}
+
+ >
+ ) : (
+ formatPrice(Number(row.price) || 0)
+ )}
+
+
+ );
+ })}
+
+ ) : (
+
تنوعی ثبت نشده است.
+ )}
+
+
+
+ ) : null}
+
+
+
+
+ هر نوع تنوع (رنگ، سایز، پکیج) جداست. میتوانید خالی بگذارید.
+
+
+
+ ردیفها
+
+
+
+
+ {variantRows.map((row, index) => (
+
+
+
+ ردیف {new Intl.NumberFormat("en-US").format(index + 1)}
+
+
+
+
+
+
+ {variantGroups.colors.length ? (
+
+
+
+
+ ) : null}
+ {variantGroups.sizes.length ? (
+
+
+
+
+ ) : null}
+ {variantGroups.packages.length ? (
+
+
+
+
+ ) : null}
+ {!hasAnyVariantOption ? (
+
+ تنوعی برای این دسته تعریف نشده.
+
+ ) : null}
+
+
+
+
+
+
+ updateRow(row.id, "price", e.target.value)
+ }
+ placeholder="3570000"
+ />
+
+
+
+
+ ))}
+
+
+
+
+
+ تنوعهای موجود و قیمت فعلی را ببینید و قیمت تخفیف را وارد کنید.
+
+
+
+ {discountRows.map((row) => {
+ const currentPrice = Number(row.price);
+ const label = discountProduct
+ ? getVariantLabel(row, discountProduct.categoryId, categoryTree)
+ : "بدون تنوع";
+
+ return (
+
+
{label}
+
+
+
قیمت فعلی
+
+
+ {Number.isNaN(currentPrice)
+ ? row.price || "—"
+ : formatPrice(currentPrice)}
+
+ {!Number.isNaN(currentPrice) && row.price ? (
+ تومان
+ ) : null}
+
+
+
+
+
+ updateDiscountPrice(row.id, e.target.value)
+ }
+ placeholder="3570000"
+ />
+
+
+
+ );
+ })}
+
+
+ >
+ );
+}
diff --git a/src/app/clothes/new/page.tsx b/src/app/clothes/new/page.tsx
new file mode 100644
index 0000000..c9a0a01
--- /dev/null
+++ b/src/app/clothes/new/page.tsx
@@ -0,0 +1,423 @@
+"use client";
+
+import Image from "next/image";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import { ChangeEvent, FormEvent, useEffect, useRef, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import CategoryTreeSelect from "@/components/ui/CategoryTreeSelect";
+import type { Brand, CategoryNode } from "@/data/clothes";
+import { ApiError, uploadMedia } from "@/lib/api";
+import {
+ createProduct,
+ fetchBrands,
+ fetchCategoriesTree,
+} from "@/lib/clothes-api";
+
+export default function AddProductPage() {
+ const router = useRouter();
+ const coverRef = useRef(null);
+ const galleryRef = useRef(null);
+
+ const [categoryTree, setCategoryTree] = useState([]);
+ const [brands, setBrands] = useState([]);
+ const [categoryId, setCategoryId] = useState("");
+ const [brandId, setBrandId] = useState("");
+ const [nameFa, setNameFa] = useState("");
+ const [nameEn, setNameEn] = useState("");
+ const [price, setPrice] = useState("");
+ const [abstract, setAbstract] = useState("");
+ const [desc, setDesc] = useState("");
+ const [tags, setTags] = useState([]);
+ const [tagInput, setTagInput] = useState("");
+ const [coverPreview, setCoverPreview] = useState(
+ "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg",
+ );
+ const [coverFile, setCoverFile] = useState(null);
+ const [galleryItems, setGalleryItems] = useState<
+ Array<{ preview: string; file: File }>
+ >([]);
+ const [saving, setSaving] = useState(false);
+ const [error, setError] = useState(null);
+ const [loadingMeta, setLoadingMeta] = useState(true);
+
+ useEffect(() => {
+ let cancelled = false;
+ (async () => {
+ try {
+ const [cats, brandRows] = await Promise.all([
+ fetchCategoriesTree(),
+ fetchBrands(),
+ ]);
+ if (cancelled) return;
+ setCategoryTree(cats);
+ setBrands(brandRows);
+ } catch (err) {
+ if (!cancelled) {
+ setError(
+ err instanceof ApiError
+ ? err.message
+ : "بارگذاری دستهها و برندها ناموفق بود.",
+ );
+ }
+ } finally {
+ if (!cancelled) setLoadingMeta(false);
+ }
+ })();
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ function addTag() {
+ const next = tagInput.trim();
+ if (!next || tags.includes(next)) return;
+ setTags((prev) => [...prev, next]);
+ setTagInput("");
+ }
+
+ function handleCoverChange(event: ChangeEvent) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ setCoverFile(file);
+ setCoverPreview(URL.createObjectURL(file));
+ }
+
+ function handleGalleryChange(event: ChangeEvent) {
+ const files = event.target.files;
+ if (!files?.length) return;
+ const next = Array.from(files).map((file) => ({
+ preview: URL.createObjectURL(file),
+ file,
+ }));
+ setGalleryItems((prev) => [...prev, ...next]);
+ event.target.value = "";
+ }
+
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault();
+ if (!nameFa.trim()) {
+ setError("نام فارسی الزامی است.");
+ return;
+ }
+
+ const priceTrimmed = price.trim();
+ const priceNum = priceTrimmed ? Number(priceTrimmed) : 0;
+ if (priceTrimmed && (!Number.isFinite(priceNum) || priceNum < 0)) {
+ setError("قیمت معتبر وارد کنید.");
+ return;
+ }
+
+ setSaving(true);
+ setError(null);
+ try {
+ let imageUrl: string | undefined;
+ let imageKey: string | undefined;
+ if (coverFile) {
+ const uploaded = await uploadMedia(coverFile, "main");
+ imageUrl = uploaded.url;
+ imageKey = uploaded.storageKey;
+ }
+
+ const galleryUrls: string[] = [];
+ const galleryKeys: string[] = [];
+ for (const item of galleryItems) {
+ const uploaded = await uploadMedia(item.file, "gallery");
+ galleryUrls.push(uploaded.url);
+ galleryKeys.push(uploaded.storageKey);
+ }
+
+ const roundedPrice = Math.round(priceNum);
+ await createProduct({
+ nameFa: nameFa.trim(),
+ nameEn: nameEn.trim() || undefined,
+ summary: abstract.trim() || undefined,
+ description: desc.trim() || undefined,
+ price: roundedPrice,
+ categoryId: categoryId || undefined,
+ brandId: brandId || undefined,
+ tags,
+ imageUrl,
+ imageKey,
+ galleryUrls,
+ galleryKeys,
+ published: true,
+ ...(priceTrimmed
+ ? {
+ variants: [
+ {
+ colorId: "",
+ sizeId: "",
+ packageId: "",
+ price: roundedPrice,
+ },
+ ],
+ }
+ : {}),
+ });
+
+ router.push("/clothes/list");
+ router.refresh();
+ } catch (err) {
+ setError(
+ err instanceof ApiError ? err.message : "ثبت محصول ناموفق بود.",
+ );
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/src/app/clothes/page.tsx b/src/app/clothes/page.tsx
new file mode 100644
index 0000000..8457590
--- /dev/null
+++ b/src/app/clothes/page.tsx
@@ -0,0 +1,132 @@
+import DashboardBanner from "@/components/dashboard/DashboardBanner";
+import DashTileGrid, {
+ DashTileItem,
+} from "@/components/dashboard/DashTileGrid";
+import ClothesShell from "@/components/clothes/ClothesShell";
+
+const clothesTiles: DashTileItem[] = [
+ {
+ href: "/clothes/list",
+ title: "لباسهای من",
+ titleEn: "My Clothes",
+ description: "فهرست و مدیریت محصولات",
+ icon: ,
+ },
+ {
+ href: "/clothes/new",
+ title: "افزودن لباس",
+ titleEn: "Add a New Cloth",
+ description: "ثبت محصول جدید در فروشگاه",
+ icon: ,
+ },
+ {
+ href: "/clothes/categories",
+ title: "دستهبندیها",
+ titleEn: "Categories",
+ description: "ساختار و گروهبندی لباسها",
+ icon: ,
+ },
+ {
+ href: "/clothes/brands",
+ title: "برندها",
+ titleEn: "Brands",
+ description: "مدیریت برندهای فروشگاه",
+ icon: ,
+ },
+];
+
+export default function ClothesPage() {
+ const bannerDelay = 80 + clothesTiles.length * 70;
+
+ return (
+
+
+
+
+
+ );
+}
+
+function iconProps() {
+ return {
+ width: 56,
+ height: 56,
+ viewBox: "0 0 24 24",
+ fill: "none",
+ "aria-hidden": true as const,
+ };
+}
+
+function ClothesIcon() {
+ return (
+
+ );
+}
+
+function AddClothIcon() {
+ return (
+
+ );
+}
+
+function CategoriesIcon() {
+ return (
+
+ );
+}
+
+function BrandsIcon() {
+ return (
+
+ );
+}
diff --git a/src/app/coming-soon/page.tsx b/src/app/coming-soon/page.tsx
new file mode 100644
index 0000000..2eb9f82
--- /dev/null
+++ b/src/app/coming-soon/page.tsx
@@ -0,0 +1,87 @@
+import type { Metadata } from "next";
+import Image from "next/image";
+import ManaLogo from "@/components/ui/ManaLogo";
+
+export const metadata: Metadata = {
+ title: "بهزودی | مانا کالکشن",
+ description: "فروشگاه آنلاین مانا کالکشن بهزودی در دسترس خواهد بود.",
+};
+
+const STORE_LOGIN =
+ process.env.NEXT_PUBLIC_STORE_URL?.replace(/\/$/, "") ||
+ "http://store.mana-collection.com:3000";
+
+export default function ComingSoonPage() {
+ return (
+
+ {/* dir=ltr keeps content on visual left, image on visual right */}
+
+ {/* Content — left */}
+
+
+
+
+
+
+
+
+
+ Coming soon
+
+
+ بهزودی
+
+
+ در این آدرس میزبان شما خواهیم بود.
+
+
+
+
+
+
+
+
+ {/* Image — right */}
+
+
+
+ );
+}
diff --git a/src/app/customers/page.tsx b/src/app/customers/page.tsx
new file mode 100644
index 0000000..f7e04a8
--- /dev/null
+++ b/src/app/customers/page.tsx
@@ -0,0 +1,187 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import IconButton, {
+ ClearFilterIcon,
+ FilterIcon,
+} from "@/components/ui/IconButton";
+import Pagination, { usePagination } from "@/components/ui/Pagination";
+import {
+ Customer,
+ formatJoinedDate,
+} from "@/data/customers";
+import { ApiError } from "@/lib/api";
+import { fetchCustomers } from "@/lib/customers-api";
+
+const PAGE_SIZE = 5;
+
+type Filters = {
+ name: string;
+ phone: string;
+};
+
+const emptyFilters: Filters = {
+ name: "",
+ phone: "",
+};
+
+export default function CustomersPage() {
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [draft, setDraft] = useState(emptyFilters);
+ const [applied, setApplied] = useState(emptyFilters);
+
+ const reload = useCallback(async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ setItems(await fetchCustomers());
+ } catch (err) {
+ setError(
+ err instanceof ApiError
+ ? err.message
+ : "بارگذاری مشتریان ناموفق بود.",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ void reload();
+ }, [reload]);
+
+ const list = items.filter((customer) => {
+ const nameQ = applied.name.trim();
+ const phoneQ = applied.phone.trim();
+ const matchesName = !nameQ || customer.nameFa.includes(nameQ);
+ const matchesPhone = !phoneQ || customer.phone.includes(phoneQ);
+ return matchesName && matchesPhone;
+ });
+
+ const { page, setPage, pageItems, totalPages, totalItems, pageSize } =
+ usePagination(list, PAGE_SIZE, JSON.stringify(applied));
+
+ return (
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+
+
+ {loading ? (
+ در حال بارگذاری...
+ ) : (
+ <>
+
+ {pageItems.map((customer, i) => (
+
+
+
+ {customer.nameFa}
+
+
+ {customer.phone}
+
+
+
+
+ عضویت
+
+
+
+ ))}
+
+ {list.length === 0 ? (
+
+ مشتریای با این فیلترها پیدا نشد.
+
+ ) : null}
+
+
+ {list.length > 0 ? (
+
+ ) : null}
+ >
+ )}
+
+ );
+}
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/src/app/favicon.ico differ
diff --git a/src/app/globals.css b/src/app/globals.css
new file mode 100644
index 0000000..2ac1e14
--- /dev/null
+++ b/src/app/globals.css
@@ -0,0 +1,1668 @@
+@import "tailwindcss";
+
+:root {
+ --background: #fbfbfa;
+ --foreground: #0a0a0a;
+ --surface: #ffffff;
+ --muted: #6b6b6b;
+ --line: #e4e4e4;
+ --ink: #0a0a0a;
+}
+
+@theme inline {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-surface: var(--surface);
+ --color-muted: var(--muted);
+ --color-line: var(--line);
+ --color-ink: var(--ink);
+ --font-sans: var(--font-doran);
+ --font-display: var(--font-cailyne);
+}
+
+body {
+ background: var(--background);
+ color: var(--foreground);
+ font-family: var(--font-doran), Tahoma, sans-serif;
+}
+
+.font-display {
+ font-family: var(--font-cailyne), Georgia, serif;
+ letter-spacing: 0.04em;
+}
+
+.font-montserrat {
+ font-family: var(--font-montserrat), system-ui, sans-serif;
+}
+
+/* Soft paper atmosphere + scattered random dots */
+@keyframes coming-soon-rise {
+ from {
+ opacity: 0;
+ transform: translateY(22px);
+ filter: blur(6px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ filter: blur(0);
+ }
+}
+
+@keyframes coming-soon-panel {
+ from {
+ opacity: 0;
+ transform: translateX(24px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes coming-soon-drift {
+ 0% {
+ transform: scale(1) translate3d(0, 0, 0);
+ }
+ 100% {
+ transform: scale(1.06) translate3d(-0.8%, 0.5%, 0);
+ }
+}
+
+@keyframes coming-soon-line {
+ from {
+ transform: scaleX(0);
+ opacity: 0;
+ }
+ to {
+ transform: scaleX(1);
+ opacity: 1;
+ }
+}
+
+@keyframes coming-soon-glow {
+ 0%,
+ 100% {
+ box-shadow: 0 0 0 0 rgba(10, 10, 10, 0);
+ }
+ 50% {
+ box-shadow: 0 0 0 4px rgba(10, 10, 10, 0.06);
+ }
+}
+
+.coming-soon-seq {
+ opacity: 0;
+ animation: coming-soon-rise 0.95s cubic-bezier(0.16, 1, 0.3, 1) forwards;
+}
+
+.coming-soon-seq-1 {
+ animation-delay: 0.12s;
+}
+
+.coming-soon-seq-2 {
+ animation-delay: 0.38s;
+}
+
+.coming-soon-seq-3 {
+ animation-delay: 0.58s;
+}
+
+.coming-soon-seq-4 {
+ animation-delay: 0.78s;
+}
+
+.coming-soon-seq-5 {
+ animation-delay: 1s;
+}
+
+.coming-soon-seq-5 {
+ position: relative;
+}
+
+.coming-soon-seq-5::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ inset-inline: 0;
+ height: 1px;
+ background: var(--line);
+ transform-origin: center;
+ animation: coming-soon-line 0.7s cubic-bezier(0.16, 1, 0.3, 1) 1.05s both;
+}
+
+.coming-soon-seq-image {
+ opacity: 0;
+ animation: coming-soon-panel 1.1s ease-out 0.05s forwards;
+}
+
+.coming-soon-image {
+ transform: scale(1);
+ animation: coming-soon-drift 20s ease-in-out 1.2s alternate infinite both;
+ will-change: transform;
+}
+
+.coming-soon-login {
+ animation: coming-soon-glow 2.4s ease-in-out 1.6s 2;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .coming-soon-seq,
+ .coming-soon-seq-image,
+ .coming-soon-image,
+ .coming-soon-seq-5::before,
+ .coming-soon-login {
+ animation: none !important;
+ opacity: 1 !important;
+ filter: none !important;
+ transform: none !important;
+ }
+}
+
+.mana-canvas,
+.auth-canvas {
+ background:
+ radial-gradient(ellipse 80% 60% at 20% 20%, rgba(0, 0, 0, 0.02), transparent 55%),
+ radial-gradient(ellipse 70% 50% at 90% 80%, rgba(0, 0, 0, 0.022), transparent 50%),
+ linear-gradient(160deg, #fcfcfb 0%, #f7f7f5 48%, #f3f3f0 100%);
+}
+
+.mana-canvas::before,
+.auth-canvas::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0.45;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cg fill='%230a0a0a'%3E%3Ccircle cx='12' cy='18' r='1.1' opacity='.28'/%3E%3Ccircle cx='48' cy='9' r='0.7' opacity='.18'/%3E%3Ccircle cx='91' cy='27' r='1.4' opacity='.22'/%3E%3Ccircle cx='133' cy='14' r='0.8' opacity='.3'/%3E%3Ccircle cx='176' cy='31' r='1.2' opacity='.16'/%3E%3Ccircle cx='208' cy='8' r='0.9' opacity='.24'/%3E%3Ccircle cx='27' cy='56' r='0.75' opacity='.2'/%3E%3Ccircle cx='69' cy='71' r='1.3' opacity='.26'/%3E%3Ccircle cx='112' cy='49' r='0.65' opacity='.15'/%3E%3Ccircle cx='154' cy='63' r='1.05' opacity='.29'/%3E%3Ccircle cx='197' cy='78' r='0.85' opacity='.19'/%3E%3Ccircle cx='8' cy='99' r='1.15' opacity='.23'/%3E%3Ccircle cx='41' cy='118' r='0.7' opacity='.17'/%3E%3Ccircle cx='83' cy='104' r='1.45' opacity='.27'/%3E%3Ccircle cx='126' cy='129' r='0.9' opacity='.21'/%3E%3Ccircle cx='168' cy='111' r='0.6' opacity='.14'/%3E%3Ccircle cx='201' cy='136' r='1.2' opacity='.25'/%3E%3Ccircle cx='22' cy='158' r='0.95' opacity='.18'/%3E%3Ccircle cx='58' cy='179' r='1.25' opacity='.3'/%3E%3Ccircle cx='97' cy='163' r='0.7' opacity='.16'/%3E%3Ccircle cx='139' cy='188' r='1.1' opacity='.22'/%3E%3Ccircle cx='181' cy='171' r='0.8' opacity='.28'/%3E%3Ccircle cx='213' cy='194' r='1' opacity='.19'/%3E%3Ccircle cx='35' cy='208' r='0.65' opacity='.24'/%3E%3Ccircle cx='74' cy='201' r='1.35' opacity='.15'/%3E%3Ccircle cx='118' cy='214' r='0.85' opacity='.26'/%3E%3Ccircle cx='160' cy='203' r='0.75' opacity='.2'/%3E%3Ccircle cx='16' cy='78' r='0.55' opacity='.12'/%3E%3Ccircle cx='104' cy='86' r='0.5' opacity='.13'/%3E%3Ccircle cx='187' cy='52' r='0.6' opacity='.11'/%3E%3Ccircle cx='149' cy='149' r='0.55' opacity='.14'/%3E%3C/g%3E%3C/svg%3E");
+ background-size: 220px 220px;
+ background-repeat: repeat;
+}
+
+.mana-canvas::after,
+.auth-canvas::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0.16;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.45'/%3E%3C/svg%3E");
+ background-size: 180px 180px;
+ mix-blend-mode: multiply;
+}
+
+@keyframes auth-rise {
+ from {
+ opacity: 0;
+ transform: translateY(14px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes auth-fade {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes image-drift {
+ from {
+ transform: scale(1.06);
+ }
+ to {
+ transform: scale(1);
+ }
+}
+
+.animate-auth-rise {
+ animation: auth-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+.animate-auth-fade {
+ animation: auth-fade 0.9s ease both;
+}
+
+.animate-image-drift {
+ animation: image-drift 1.4s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+@keyframes tile-in {
+ from {
+ opacity: 0;
+ transform: translateY(22px) scale(0.96);
+ filter: blur(6px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ filter: blur(0);
+ }
+}
+
+.dash-tile-enter,
+.dash-enter {
+ animation: tile-in 0.45s cubic-bezier(0.22, 1, 0.36, 1) backwards;
+}
+
+.auth-input {
+ width: 100%;
+ border: none;
+ border-bottom: 1px solid var(--line);
+ background: transparent;
+ padding: 0.2rem 0.1rem 0.35rem;
+ font-size: 0.95rem;
+ line-height: 1.3;
+ color: var(--ink);
+ outline: none;
+ transition: border-color 0.25s ease;
+}
+
+.auth-input::placeholder {
+ color: #a3a3a3;
+}
+
+.auth-input:focus {
+ border-bottom-color: var(--ink);
+}
+
+.auth-label {
+ display: block;
+ font-size: 0.75rem;
+ letter-spacing: 0.02em;
+ color: var(--muted);
+ margin-bottom: 0.1rem;
+}
+
+/* Submit button — invert wipe + light sweep */
+.auth-button {
+ position: relative;
+ isolation: isolate;
+ overflow: hidden;
+ width: 100%;
+ margin-top: 0.25rem;
+ padding: 0.875rem 1.5rem;
+ border: 1px solid var(--ink);
+ background: var(--ink);
+ color: #fff;
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+.auth-button > span {
+ position: relative;
+ z-index: 2;
+}
+
+.auth-button::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ z-index: 0;
+ background: #fff;
+ transform: translateY(101%);
+ transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+.auth-button::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: -40%;
+ z-index: 1;
+ width: 40%;
+ background: linear-gradient(
+ 105deg,
+ transparent 0%,
+ rgba(255, 255, 255, 0.22) 45%,
+ transparent 100%
+ );
+ transform: skewX(-18deg) translateX(0);
+ transition: transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
+ pointer-events: none;
+}
+
+.auth-button:hover {
+ color: var(--ink);
+}
+
+.auth-button:hover::before {
+ transform: translateY(0);
+}
+
+.auth-button:hover::after {
+ transform: skewX(-18deg) translateX(380%);
+}
+
+.auth-button:active {
+ transform: scale(0.985);
+}
+
+/* Logo lockup — same invert wipe as auth-button */
+.mana-logo-swap-plate,
+.mana-logo-swap-tagline {
+ position: relative;
+ isolation: isolate;
+ overflow: hidden;
+}
+
+.mana-logo-swap-plate::before,
+.mana-logo-swap-tagline::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ z-index: 0;
+ transform: translateY(101%);
+ transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
+ pointer-events: none;
+}
+
+.mana-logo-swap-plate::before {
+ background: #fff;
+}
+
+.mana-logo-swap-tagline::before {
+ background: var(--ink);
+}
+
+.group:hover .mana-logo-swap-plate::before,
+.group:hover .mana-logo-swap-tagline::before {
+ transform: translateY(0);
+}
+
+.mana-logo-swap-plate > *,
+.mana-logo-swap-tagline > * {
+ position: relative;
+ z-index: 2;
+}
+
+.mana-logo-swap-tagline {
+ transition: color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+.group:hover .mana-logo-swap-tagline {
+ color: #fff;
+}
+
+/* Dashboard banner — white wipe overlay */
+.dash-banner {
+ cursor: pointer;
+}
+
+.dash-banner-wipe {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #fff;
+ transform: translateY(101%);
+ transition: transform 0.32s cubic-bezier(0.7, 0, 0.84, 0.2);
+}
+
+.dash-banner:hover .dash-banner-wipe {
+ transform: translateY(0);
+}
+
+/* Dashboard tiles */
+.dash-tile {
+ position: relative;
+ display: flex;
+ min-height: 12rem;
+ flex-direction: column;
+ justify-content: space-between;
+ overflow: hidden;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: var(--surface);
+ padding: 1.15rem 1rem;
+ align-items: center;
+ text-align: center;
+ transition:
+ border-color 0.35s ease,
+ transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
+ box-shadow 0.45s ease;
+}
+
+.dash-tile::before {
+ content: "";
+ position: absolute;
+ inset: auto 0 0 0;
+ height: 2px;
+ background: var(--ink);
+ transform: scaleX(0);
+ transform-origin: right;
+ transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+.dash-tile:hover {
+ border-color: var(--ink);
+ transform: translateY(-3px);
+ box-shadow: 0 18px 40px rgba(0, 0, 0, 0.06);
+}
+
+.dash-tile:hover::before {
+ transform: scaleX(1);
+}
+
+.dash-tile-index {
+ font-family: var(--font-cailyne), Georgia, serif;
+ font-size: 0.85rem;
+ letter-spacing: 0.12em;
+ color: var(--muted);
+}
+
+.dash-menu-panel {
+ position: absolute;
+ top: calc(100% + 0.5rem);
+ inset-inline-end: 0;
+ z-index: 40;
+ min-width: 12.5rem;
+ border: 1px solid var(--line);
+ background: var(--surface);
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.08);
+ animation: auth-fade 0.2s ease both;
+}
+
+.dash-menu-item {
+ display: flex;
+ width: 100%;
+ align-items: center;
+ gap: 0.65rem;
+ padding: 0.75rem 1rem;
+ text-align: start;
+ font-size: 0.85rem;
+ color: var(--ink);
+ transition: background-color 0.2s ease;
+ cursor: pointer;
+}
+
+.dash-menu-item:hover {
+ background: #f4f4f2;
+}
+
+.dash-chart {
+ border-radius: 8px;
+}
+
+/* Clothes admin */
+.clothes-plus {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.45rem;
+ border: 1px solid var(--ink);
+ background: var(--ink);
+ color: #fff;
+ padding: 0.65rem 1rem;
+ border-radius: 8px;
+ transition:
+ color 0.35s ease,
+ background-color 0.35s ease,
+ transform 0.2s ease;
+ cursor: pointer;
+}
+
+.clothes-plus:hover {
+ background: #fff;
+ color: var(--ink);
+}
+
+.clothes-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.clothes-field label {
+ font-size: 0.7rem;
+ color: var(--muted);
+}
+
+.clothes-field input:not([type="radio"]):not([type="checkbox"]):not([type="file"]):not([type="range"]),
+.clothes-field select,
+.clothes-field textarea {
+ width: 100%;
+ border: 1px solid var(--line);
+ background: #fff;
+ padding: 0.45rem 0.6rem;
+ font-size: 0.8rem;
+ color: var(--ink);
+ border-radius: 6px;
+ outline: none;
+ transition: border-color 0.2s ease;
+}
+
+.clothes-field input:not([type="radio"]):not([type="checkbox"]):not([type="file"]):not([type="range"]):focus,
+.clothes-field select:focus,
+.clothes-field textarea:focus {
+ border-color: var(--ink);
+}
+
+.clothes-field input[dir="ltr"],
+.clothes-field textarea[dir="ltr"],
+.clothes-field select[dir="ltr"] {
+ font-family: var(--font-montserrat), system-ui, sans-serif;
+}
+
+.clothes-field textarea {
+ min-height: 7rem;
+ resize: vertical;
+}
+
+.category-tree-select {
+ position: relative;
+}
+
+.category-tree-panel {
+ position: absolute;
+ inset-inline: 0;
+ top: calc(100% + 0.35rem);
+ z-index: 40;
+ max-height: 16rem;
+ overflow: auto;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 14px 36px rgba(0, 0, 0, 0.1);
+ padding: 0.35rem 0;
+}
+
+.category-tree-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.category-tree-row {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ min-height: 2.15rem;
+}
+
+.category-tree-toggle,
+.category-tree-toggle-spacer {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.35rem;
+ height: 1.35rem;
+ flex-shrink: 0;
+}
+
+.category-tree-toggle {
+ border: 1px solid var(--line);
+ background: #f7f7f5;
+ color: var(--muted);
+ border-radius: 4px;
+ font-size: 0.75rem;
+ cursor: pointer;
+}
+
+.category-tree-toggle:hover {
+ color: var(--ink);
+ border-color: #cfcfcf;
+}
+
+.category-tree-label {
+ flex: 1;
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 0.75rem;
+ min-width: 0;
+ border: none;
+ background: transparent;
+ padding: 0.35rem 0.55rem 0.35rem 0.25rem;
+ text-align: start;
+ cursor: pointer;
+ color: var(--ink);
+ font-size: 0.85rem;
+}
+
+.category-tree-label:hover {
+ background: #f4f4f2;
+}
+
+.category-tree-row.is-selected .category-tree-label {
+ background: #f0f0ee;
+ font-weight: 500;
+}
+
+.category-tree-en {
+ flex-shrink: 0;
+ font-size: 0.7rem;
+ color: var(--muted);
+ letter-spacing: 0.04em;
+}
+
+.category-tree-empty {
+ padding: 0.85rem 1rem;
+ font-size: 0.8rem;
+ color: var(--muted);
+ text-align: center;
+}
+
+.product-card {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ border: 1px solid var(--line);
+ background: var(--surface);
+ border-radius: 8px;
+ transition:
+ border-color 0.3s ease,
+ transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
+ box-shadow 0.35s ease;
+}
+
+.product-card:hover {
+ border-color: #cfcfcf;
+ transform: translateY(-2px);
+ box-shadow: 0 14px 32px rgba(0, 0, 0, 0.05);
+}
+
+.product-card-actions {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ border-top: 1px solid var(--line);
+}
+
+.product-card-actions .icon-btn {
+ width: 100%;
+ height: 2.85rem;
+ border-radius: 0;
+ border-inline-start: 1px solid var(--line);
+}
+
+.product-card-actions .icon-btn:first-child {
+ border-inline-start: none;
+}
+
+.tree-box {
+ border: 1px solid var(--line);
+ background: var(--surface);
+ border-radius: 8px;
+ padding: 0.75rem;
+}
+
+.tree-row-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem;
+}
+
+.tree-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 8px;
+ padding: 0.85rem 0.95rem;
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02);
+}
+
+.icon-btn-badge {
+ position: absolute;
+ top: 0.2rem;
+ inset-inline-end: 0.2rem;
+ z-index: 1;
+ min-width: 1rem;
+ height: 1rem;
+ padding: 0 0.22rem;
+ border-radius: 999px;
+ background: var(--ink);
+ color: #fff;
+ font-size: 0.62rem;
+ line-height: 1rem;
+ text-align: center;
+ pointer-events: none;
+}
+
+.icon-btn {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.75rem;
+ height: 2.75rem;
+ border-radius: 6px;
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ background-color 0.2s ease,
+ border-color 0.2s ease;
+}
+
+.icon-btn[data-tooltip]::before,
+.icon-btn[data-tooltip]::after {
+ position: absolute;
+ left: 50%;
+ z-index: 50;
+ opacity: 0;
+ pointer-events: none;
+ transition:
+ opacity 0.15s ease,
+ transform 0.15s ease;
+ transform: translateX(-50%) translateY(4px);
+}
+
+.icon-btn[data-tooltip]::after {
+ content: attr(data-tooltip);
+ bottom: calc(100% + 8px);
+ white-space: nowrap;
+ border-radius: 6px;
+ background: var(--ink);
+ color: #fff;
+ font-size: 0.7rem;
+ line-height: 1;
+ padding: 0.4rem 0.55rem;
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
+}
+
+.icon-btn[data-tooltip]::before {
+ content: "";
+ bottom: calc(100% + 4px);
+ border: 4px solid transparent;
+ border-top-color: var(--ink);
+}
+
+.icon-btn[data-tooltip]:hover::before,
+.icon-btn[data-tooltip]:hover::after,
+.icon-btn[data-tooltip]:focus-visible::before,
+.icon-btn[data-tooltip]:focus-visible::after {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+
+.icon-btn-ghost {
+ border: none;
+ background: transparent;
+ color: #9a9a9a;
+}
+
+.icon-btn-ghost:hover {
+ color: var(--ink);
+ background: #f4f4f2;
+}
+
+.icon-btn-line {
+ border: 1px solid #ebebeb;
+ background: #f7f7f5;
+ color: #9a9a9a;
+}
+
+.icon-btn-line:hover {
+ color: var(--ink);
+ border-color: #d6d6d6;
+ background: #fff;
+}
+
+.icon-btn-solid {
+ border: 1px solid var(--ink);
+ background: var(--ink);
+ color: #fff;
+}
+
+.icon-btn-solid:hover {
+ background: #fff;
+ color: var(--ink);
+}
+
+.clothes-filter-bar {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: end;
+ gap: 0.5rem;
+ border: 1px solid var(--line);
+ background: var(--surface);
+ border-radius: 8px;
+ padding: 0.65rem;
+}
+
+.clothes-filter-bar .clothes-field {
+ flex: 1 1 7.5rem;
+ min-width: 7rem;
+ max-width: 11rem;
+}
+
+.clothes-filter-actions {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-inline-start: auto;
+ padding-bottom: 0.05rem;
+}
+
+.brand-card {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 8px;
+ padding: 0.85rem;
+ transition: border-color 0.25s ease;
+}
+
+.brand-card:hover {
+ border-color: #cfcfcf;
+}
+
+.customer-card {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 8px;
+ padding: 0.9rem 1rem;
+ transition: border-color 0.25s ease;
+}
+
+.customer-card:hover {
+ border-color: #cfcfcf;
+}
+
+.customer-joined {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.15rem;
+ min-width: 6.5rem;
+}
+
+.customer-joined-label {
+ font-size: 0.65rem;
+ color: color-mix(in srgb, var(--muted) 75%, white);
+}
+
+.customer-joined-date {
+ font-size: 0.85rem;
+ color: color-mix(in srgb, var(--ink) 55%, white);
+ font-variant-numeric: tabular-nums;
+ letter-spacing: 0.02em;
+ direction: ltr;
+ unicode-bidi: isolate;
+}
+
+.customer-sub-premium {
+ color: #fff !important;
+ border-color: var(--ink) !important;
+ background: var(--ink) !important;
+}
+
+.customer-sub-premium:hover {
+ color: var(--ink) !important;
+ background: #fff !important;
+}
+
+.blog-card {
+ display: flex;
+ align-items: stretch;
+ gap: 1rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 8px;
+ padding: 0.75rem;
+ transition: border-color 0.25s ease;
+}
+
+.blog-card:hover {
+ border-color: #cfcfcf;
+}
+
+.blog-card-image {
+ position: relative;
+ width: 7.5rem;
+ flex-shrink: 0;
+ aspect-ratio: 3 / 2;
+ overflow: hidden;
+ border-radius: 6px;
+ background: #f3f3f1;
+}
+
+@media (min-width: 640px) {
+ .blog-card-image {
+ width: 10rem;
+ }
+}
+
+.rich-text {
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: #fff;
+ overflow: hidden;
+}
+
+.rich-text-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.45rem 0.55rem;
+ border-bottom: 1px solid var(--line);
+ background: #f7f7f5;
+}
+
+.rich-text-toolbar button {
+ min-width: 2rem;
+ height: 1.85rem;
+ padding: 0 0.55rem;
+ border: 1px solid var(--line);
+ border-radius: 5px;
+ background: #fff;
+ color: var(--ink);
+ font-size: 0.8rem;
+ cursor: pointer;
+}
+
+.rich-text-toolbar button.italic {
+ font-style: italic;
+}
+
+.rich-text-toolbar button:hover {
+ border-color: var(--ink);
+}
+
+.rich-text-divider {
+ width: 1px;
+ height: 1.1rem;
+ background: var(--line);
+ margin-inline: 0.2rem;
+}
+
+.rich-text-editor {
+ min-height: 12rem;
+ padding: 0.75rem 0.85rem;
+ font-size: 0.9rem;
+ line-height: 1.8;
+ color: var(--ink);
+ outline: none;
+}
+
+.rich-text-editor:empty::before {
+ content: attr(data-placeholder);
+ color: #b0b0b0;
+ pointer-events: none;
+}
+
+.rich-text-editor .rich-inline-image,
+.rich-text-editor img {
+ display: block;
+ max-width: 100%;
+ margin: 0.75rem 0;
+ border-radius: 6px;
+}
+
+.pagination {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.75rem;
+ margin-top: 1rem;
+ padding: 0.75rem 0.15rem 0.25rem;
+}
+
+.pagination-meta {
+ font-size: 0.8rem;
+ color: var(--muted);
+}
+
+.pagination-controls {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.35rem;
+}
+
+.pagination-btn {
+ min-width: 2.25rem;
+ height: 2.25rem;
+ padding: 0 0.7rem;
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ background: #fff;
+ color: var(--muted);
+ font-size: 0.8rem;
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ border-color 0.2s ease,
+ background-color 0.2s ease;
+}
+
+.pagination-btn:hover:not(:disabled) {
+ color: var(--ink);
+ border-color: #cfcfcf;
+}
+
+.pagination-btn:disabled {
+ opacity: 0.35;
+ cursor: default;
+}
+
+.pagination-num.is-active {
+ color: #fff;
+ border-color: var(--ink);
+ background: var(--ink);
+}
+
+.modal-root {
+ position: fixed;
+ inset: 0;
+ z-index: 80;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+}
+
+.modal-backdrop {
+ position: absolute;
+ inset: 0;
+ border: none;
+ background: rgba(10, 10, 10, 0.42);
+ cursor: pointer;
+}
+
+.modal-panel {
+ position: relative;
+ z-index: 1;
+ width: min(100%, 28rem);
+ max-height: min(92dvh, 40rem);
+ overflow: hidden;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ background: #fff;
+ box-shadow: 0 24px 60px rgba(0, 0, 0, 0.16);
+ animation: modal-in 0.22s ease;
+}
+
+.modal-panel-wide {
+ width: min(100%, 30rem);
+}
+
+.modal-panel-xl {
+ width: min(100%, 56rem);
+ max-height: min(92dvh, 48rem);
+ overflow: auto;
+}
+
+.modal-panel-full {
+ width: min(100%, 72rem);
+ max-height: min(94dvh, 56rem);
+ overflow: auto;
+}
+
+@keyframes modal-in {
+ from {
+ opacity: 0;
+ transform: translateY(8px) scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
+.modal-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ padding: 0.85rem 1rem 0.65rem;
+ border-bottom: 1px solid var(--line);
+}
+
+.modal-close {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ border: none;
+ background: transparent;
+ color: var(--muted);
+ font-size: 1.35rem;
+ line-height: 1;
+ cursor: pointer;
+ border-radius: 6px;
+}
+
+.modal-close:hover {
+ color: var(--ink);
+ background: #f4f4f2;
+}
+
+.modal-body {
+ padding: 0.85rem 1rem;
+}
+
+.modal-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 0.5rem;
+ padding: 0.85rem 1rem 1.35rem;
+ border-top: 1px solid var(--line);
+}
+
+.modal-btn-ghost,
+.modal-btn-solid {
+ border-radius: 8px;
+ padding: 0.55rem 1rem;
+ font-size: 0.85rem;
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ background-color 0.2s ease,
+ border-color 0.2s ease;
+}
+
+.modal-btn-ghost {
+ border: 1px solid var(--line);
+ background: #fff;
+ color: var(--muted);
+}
+
+.modal-btn-ghost:hover {
+ color: var(--ink);
+ border-color: #cfcfcf;
+}
+
+.modal-btn-solid {
+ border: 1px solid var(--ink);
+ background: var(--ink);
+ color: #fff;
+}
+
+.modal-btn-solid:hover {
+ background: #fff;
+ color: var(--ink);
+}
+
+/* Destructive confirm */
+.confirm-root {
+ position: fixed;
+ inset: 0;
+ z-index: 90;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+}
+
+.confirm-backdrop {
+ position: absolute;
+ inset: 0;
+ border: none;
+ background: rgba(160, 20, 30, 0.52);
+ cursor: pointer;
+}
+
+.confirm-panel {
+ position: relative;
+ z-index: 1;
+ width: min(100%, 22rem);
+ border: 1px solid #e8d0d2;
+ border-radius: 10px;
+ background: #fff;
+ padding: 1.25rem 1.15rem 1.1rem;
+ box-shadow: 0 24px 60px rgba(120, 10, 20, 0.22);
+ animation: modal-in 0.22s ease;
+ text-align: center;
+}
+
+.confirm-title {
+ font-size: 1.05rem;
+ color: var(--ink);
+}
+
+.confirm-message {
+ margin-top: 0.55rem;
+ font-size: 0.875rem;
+ line-height: 1.7;
+ color: var(--muted);
+}
+
+.confirm-actions {
+ display: flex;
+ justify-content: center;
+ gap: 0.5rem;
+ margin-top: 1.15rem;
+}
+
+.confirm-btn-cancel,
+.confirm-btn-danger {
+ min-width: 5.5rem;
+ padding: 0.55rem 1rem;
+ border-radius: 6px;
+ font-size: 0.85rem;
+ cursor: pointer;
+ transition:
+ background-color 0.2s ease,
+ color 0.2s ease,
+ border-color 0.2s ease;
+}
+
+.confirm-btn-cancel {
+ border: 1px solid var(--line);
+ background: #fff;
+ color: var(--muted);
+}
+
+.confirm-btn-cancel:hover {
+ border-color: var(--ink);
+ color: var(--ink);
+}
+
+.confirm-btn-danger {
+ border: 1px solid #b91c1c;
+ background: #b91c1c;
+ color: #fff;
+}
+
+.confirm-btn-danger:hover {
+ background: #fff;
+ color: #b91c1c;
+}
+
+.brand-image-pick {
+ display: flex;
+ align-items: center;
+ gap: 0.85rem;
+}
+
+.brand-image-pick-preview {
+ position: relative;
+ width: 4.5rem;
+ height: 4.5rem;
+ overflow: hidden;
+ border-radius: 8px;
+ border: 1px dashed var(--line);
+ background: #f3f3f1;
+ flex-shrink: 0;
+}
+
+.brand-image-pick-preview img {
+ object-fit: cover;
+}
+
+.crop-ratio-radios {
+ display: flex;
+ gap: 0.65rem;
+}
+
+.crop-ratio-option {
+ display: inline-flex;
+ flex: 1;
+ align-items: center;
+ justify-content: center;
+ gap: 0.55rem;
+ min-width: 0;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 8px;
+ padding: 0.7rem 1.35rem;
+ font-size: 0.9rem;
+ color: var(--muted);
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ border-color 0.2s ease,
+ background-color 0.2s ease;
+}
+
+.crop-ratio-option:hover {
+ color: var(--ink);
+ border-color: #cfcfcf;
+}
+
+.crop-ratio-option:has(input:checked) {
+ color: var(--ink);
+ border-color: var(--ink);
+ background: #f7f7f5;
+}
+
+.crop-ratio-option input {
+ appearance: none;
+ -webkit-appearance: none;
+ box-sizing: border-box;
+ flex: 0 0 1rem;
+ width: 1rem;
+ height: 1rem;
+ min-width: 1rem;
+ max-width: 1rem;
+ margin: 0;
+ padding: 0;
+ border: 1px solid #c8c8c8;
+ border-radius: 50%;
+ background: #fff;
+ display: grid;
+ place-content: center;
+ cursor: pointer;
+ aspect-ratio: 1 / 1;
+}
+
+.crop-ratio-option input::before {
+ content: "";
+ width: 0.4rem;
+ height: 0.4rem;
+ border-radius: 50%;
+ background: var(--ink);
+ transform: scale(0);
+ transition: transform 0.15s ease;
+}
+
+.crop-ratio-option input:checked {
+ border-color: var(--ink);
+}
+
+.crop-ratio-option input:checked::before {
+ transform: scale(1);
+}
+
+.image-cropper {
+ display: flex;
+ flex-direction: column;
+ gap: 0.55rem;
+}
+
+.crop-frame {
+ position: relative;
+ aspect-ratio: 2 / 3;
+ width: min(100%, 280px);
+ margin-inline: auto;
+ overflow: hidden;
+ border: 1px dashed #bdbdbd;
+ background:
+ linear-gradient(45deg, #f3f3f1 25%, transparent 25%),
+ linear-gradient(-45deg, #f3f3f1 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, #f3f3f1 75%),
+ linear-gradient(-45deg, transparent 75%, #f3f3f1 75%);
+ background-size: 16px 16px;
+ background-position:
+ 0 0,
+ 0 8px,
+ 8px -8px,
+ -8px 0;
+ border-radius: 8px;
+ transition: aspect-ratio 0.25s ease;
+ touch-action: none;
+ user-select: none;
+}
+
+.crop-frame-brand {
+ width: min(100%, 220px);
+}
+
+.blog-cover-cropper .crop-frame-brand {
+ width: 100%;
+}
+
+.blog-cover-cropper .crop-zoom-bar {
+ width: 100%;
+}
+
+.profile-avatar-cropper .crop-frame-brand {
+ width: min(100%, 200px);
+}
+
+.profile-avatar-cropper .crop-zoom-bar {
+ width: min(100%, 200px);
+}
+
+.profile-input-locked {
+ background: #f4f4f2 !important;
+ color: var(--muted) !important;
+ cursor: not-allowed;
+}
+
+.address-block {
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: #fff;
+ padding: 0.9rem;
+}
+
+.variant-type-block {
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ padding: 0.75rem;
+ background: #fafaf8;
+}
+
+.variant-type-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.9rem;
+ color: var(--ink);
+ cursor: pointer;
+}
+
+.variant-type-toggle input {
+ width: 1rem;
+ height: 1rem;
+ accent-color: var(--ink);
+ cursor: pointer;
+}
+
+.variant-chip-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.45rem;
+ margin-top: 0.7rem;
+}
+
+.variant-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ background: #fff;
+ padding: 0.35rem 0.7rem;
+ font-size: 0.78rem;
+ color: var(--muted);
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ border-color 0.2s ease,
+ background-color 0.2s ease;
+}
+
+.variant-chip input {
+ position: absolute;
+ opacity: 0;
+ pointer-events: none;
+}
+
+.variant-chip:hover {
+ color: var(--ink);
+ border-color: #cfcfcf;
+}
+
+.variant-chip.is-active {
+ color: var(--ink);
+ border-color: var(--ink);
+ background: #f0f0ee;
+}
+
+.variant-chip-all {
+ border-style: dashed;
+ font-weight: 500;
+}
+
+.variant-swatch {
+ width: 0.85rem;
+ height: 0.85rem;
+ border-radius: 50%;
+ border: 1px solid rgba(0, 0, 0, 0.12);
+ flex-shrink: 0;
+}
+
+.variant-price-row {
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: #fff;
+ padding: 0.75rem;
+}
+
+.variant-price-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 0.65rem;
+ align-items: end;
+}
+
+@media (min-width: 640px) {
+ .variant-price-grid {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+}
+
+.variant-price-fields {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 0.65rem;
+}
+
+@media (min-width: 640px) {
+ .variant-price-fields {
+ grid-column: span 8;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+}
+
+.variant-price-amount {
+ display: grid;
+ gap: 0.65rem;
+}
+
+@media (min-width: 640px) {
+ .variant-price-amount {
+ grid-column: span 4;
+ padding-inline-start: 0.85rem;
+ border-inline-start: 1px solid var(--line);
+ }
+}
+
+.crop-frame.crop-ratio-1-1 {
+ aspect-ratio: 1 / 1;
+}
+
+.crop-frame.crop-ratio-3-2 {
+ aspect-ratio: 3 / 2;
+}
+
+.crop-frame.crop-ratio-2-3 {
+ aspect-ratio: 2 / 3;
+}
+
+.crop-frame-media {
+ position: absolute;
+ inset: 0;
+ transform-origin: center center;
+ will-change: transform;
+}
+
+.crop-frame::after {
+ content: "";
+ position: absolute;
+ inset: 12%;
+ border: 1px solid rgba(10, 10, 10, 0.55);
+ box-shadow: 0 0 0 999px rgba(255, 255, 255, 0.35);
+ pointer-events: none;
+ z-index: 1;
+}
+
+.crop-zoom-bar {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.55rem;
+ width: min(100%, 220px);
+ margin-inline: auto;
+}
+
+.crop-zoom-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ background: #fff;
+ color: var(--ink);
+ font-size: 1.1rem;
+ line-height: 1;
+ cursor: pointer;
+ transition:
+ color 0.2s ease,
+ border-color 0.2s ease,
+ background-color 0.2s ease;
+}
+
+.crop-zoom-btn:hover:not(:disabled) {
+ border-color: var(--ink);
+}
+
+.crop-zoom-btn:disabled {
+ opacity: 0.35;
+ cursor: default;
+}
+
+.crop-zoom-range {
+ flex: 1;
+ min-width: 0;
+ accent-color: var(--ink);
+ cursor: pointer;
+}
+
+.gallery-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 0.5rem;
+}
+
+.gallery-slot {
+ aspect-ratio: 1;
+ border: 1px dashed var(--line);
+ border-radius: 8px;
+ background: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--muted);
+ font-size: 0.75rem;
+ cursor: pointer;
+ transition: border-color 0.2s ease;
+}
+
+.gallery-slot:hover {
+ border-color: var(--ink);
+}
+
+.tag-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 999px;
+ padding: 0.25rem 0.65rem;
+ font-size: 0.75rem;
+ color: var(--ink);
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
new file mode 100644
index 0000000..a1e6c7c
--- /dev/null
+++ b/src/app/layout.tsx
@@ -0,0 +1,77 @@
+import type { Metadata } from "next";
+import { Montserrat } from "next/font/google";
+import localFont from "next/font/local";
+import Providers from "@/components/Providers";
+import RequireStoreAuth from "@/components/RequireStoreAuth";
+import "./globals.css";
+
+const doran = localFont({
+ src: [
+ {
+ path: "../fonts/doran/Doran-Thin.woff",
+ weight: "100",
+ style: "normal",
+ },
+ {
+ path: "../fonts/doran/Doran-Regular.woff",
+ weight: "400",
+ style: "normal",
+ },
+ {
+ path: "../fonts/doran/Doran-Medium.woff",
+ weight: "500",
+ style: "normal",
+ },
+ {
+ path: "../fonts/doran/Doran-Bold.woff",
+ weight: "700",
+ style: "normal",
+ },
+ ],
+ variable: "--font-doran",
+ display: "swap",
+});
+
+const cailyne = localFont({
+ src: [
+ {
+ path: "../fonts/Cailyne.otf",
+ weight: "400",
+ style: "normal",
+ },
+ ],
+ variable: "--font-cailyne",
+ display: "swap",
+});
+
+const montserrat = Montserrat({
+ subsets: ["latin"],
+ weight: ["400", "500", "600"],
+ variable: "--font-montserrat",
+ display: "swap",
+});
+
+export const metadata: Metadata = {
+ title: "مانا کالکشن | Mana Collection",
+ description: "فروشگاه لباسهای مینیمال و شیک — مانا کالکشن",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
new file mode 100644
index 0000000..5c1d2cb
--- /dev/null
+++ b/src/app/login/page.tsx
@@ -0,0 +1,5 @@
+import AuthForm from "@/components/auth/AuthForm";
+
+export default function LoginPage() {
+ return ;
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 0000000..43d3cd9
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,176 @@
+import DashboardBanner from "@/components/dashboard/DashboardBanner";
+import DashboardCharts from "@/components/dashboard/DashboardCharts";
+import DashboardHeader from "@/components/dashboard/DashboardHeader";
+import DashTileGrid, {
+ DashTileItem,
+} from "@/components/dashboard/DashTileGrid";
+
+const tiles: DashTileItem[] = [
+ {
+ href: "/clothes",
+ title: "لباسهای من",
+ titleEn: "My Clothes",
+ description: "موجودی، دستهبندی و محصولات",
+ icon: ,
+ },
+ {
+ href: "/customers",
+ title: "مشتریان من",
+ titleEn: "My Customers",
+ description: "فهرست و جزئیات مشتریان",
+ icon: ,
+ },
+ {
+ href: "/blog",
+ title: "بلاگ من",
+ titleEn: "My Blog",
+ description: "مطالب، کاور و متا تگها",
+ icon: ,
+ },
+ {
+ href: "/orders",
+ title: "سفارشهای من",
+ titleEn: "My Orders",
+ description: "پیگیری ارسال و پرداخت",
+ icon: ,
+ },
+ {
+ href: "/profile",
+ title: "پروفایل من",
+ titleEn: "My Profile",
+ description: "حساب، فروشگاه و امنیت",
+ icon: ,
+ },
+];
+
+export default function HomePage() {
+ const bannerDelay = 80 + tiles.length * 70;
+
+ return (
+
+
+
+
+
+
+
+ Admin
+
+
+ •
+
+ داشبورد مدیریت
+
+
+ از اینجا لباسها، مشتریان، بلاگ، سفارشها و پروفایل فروشگاه را مدیریت کنید.
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function iconProps() {
+ return {
+ width: 56,
+ height: 56,
+ viewBox: "0 0 24 24",
+ fill: "none",
+ "aria-hidden": true as const,
+ };
+}
+
+function ClothesIcon() {
+ return (
+
+ );
+}
+
+function CustomersIcon() {
+ return (
+
+ );
+}
+
+function BlogIcon() {
+ return (
+
+ );
+}
+
+function OrdersIcon() {
+ return (
+
+ );
+}
+
+function ProfileIcon() {
+ return (
+
+ );
+}
diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx
new file mode 100644
index 0000000..656a318
--- /dev/null
+++ b/src/app/profile/page.tsx
@@ -0,0 +1,365 @@
+"use client";
+
+import { ChangeEvent, FormEvent, useRef, useState } from "react";
+import ClothesShell from "@/components/clothes/ClothesShell";
+import ImageCropper from "@/components/ui/ImageCropper";
+
+type AddressItem = {
+ id: string;
+ label: string;
+ province: string;
+ city: string;
+ fullAddress: string;
+ landline: string;
+};
+
+const DEFAULT_AVATAR = "/images/ryanwar-hanif-98XENwtPMCc-unsplash.jpg";
+
+const provinces = [
+ "تهران",
+ "اصفهان",
+ "فارس",
+ "خراسان رضوی",
+ "آذربایجان شرقی",
+ "آذربایجان غربی",
+ "گیلان",
+ "مازندران",
+ "خوزستان",
+ "کرمان",
+ "یزد",
+ "قم",
+ "البرز",
+ "همدان",
+ "کردستان",
+ "کرمانشاه",
+ "هرمزگان",
+ "بوشهر",
+ "سیستان و بلوچستان",
+ "گلستان",
+ "قزوین",
+ "زنجان",
+ "اردبیل",
+ "لرستان",
+ "مرکزی",
+ "سمنان",
+ "چهارمحال و بختیاری",
+ "کهگیلویه و بویراحمد",
+ "ایلام",
+ "خراسان شمالی",
+ "خراسان جنوبی",
+];
+
+function emptyAddress(): AddressItem {
+ return {
+ id: `addr-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
+ label: "",
+ province: "",
+ city: "",
+ fullAddress: "",
+ landline: "",
+ };
+}
+
+export default function ProfilePage() {
+ const fileRef = useRef(null);
+ const [avatar, setAvatar] = useState(DEFAULT_AVATAR);
+ const [nameFa, setNameFa] = useState("سارا محمدی");
+ const [nameEn, setNameEn] = useState("Sara Mohammadi");
+ const [phone] = useState("09121234567");
+ const [email, setEmail] = useState("sara@manacollection.com");
+ const [instagram, setInstagram] = useState("@manacollection");
+ const [about, setAbout] = useState(
+ "علاقهمند به طراحی مینیمال و استایلهای آرام روزمره.",
+ );
+ const [addresses, setAddresses] = useState([
+ {
+ id: "addr-1",
+ label: "منزل",
+ province: "تهران",
+ city: "تهران",
+ fullAddress: "خیابان ولیعصر، بالاتر از پارک وی، پلاک ۱۲",
+ landline: "02122001122",
+ },
+ ]);
+
+ function handleAvatarChange(event: ChangeEvent) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ setAvatar(URL.createObjectURL(file));
+ }
+
+ function updateAddress(
+ id: string,
+ field: keyof Omit,
+ value: string,
+ ) {
+ setAddresses((prev) =>
+ prev.map((item) =>
+ item.id === id ? { ...item, [field]: value } : item,
+ ),
+ );
+ }
+
+ function addAddress() {
+ setAddresses((prev) => [...prev, emptyAddress()]);
+ }
+
+ function removeAddress(id: string) {
+ setAddresses((prev) =>
+ prev.length <= 1 ? prev : prev.filter((item) => item.id !== id),
+ );
+ }
+
+ function handleSubmit(event: FormEvent) {
+ event.preventDefault();
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/src/components/Providers.tsx b/src/components/Providers.tsx
new file mode 100644
index 0000000..263f853
--- /dev/null
+++ b/src/components/Providers.tsx
@@ -0,0 +1,13 @@
+"use client";
+
+import { ConfirmProvider } from "@/components/ui/ConfirmDialog";
+import { AuthProvider } from "@/lib/auth";
+import type { ReactNode } from "react";
+
+export default function Providers({ children }: { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/RequireStoreAuth.tsx b/src/components/RequireStoreAuth.tsx
new file mode 100644
index 0000000..1701e0b
--- /dev/null
+++ b/src/components/RequireStoreAuth.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useEffect } from "react";
+import { usePathname, useRouter } from "next/navigation";
+import { useAuth } from "@/lib/auth";
+
+const PUBLIC_PATHS = ["/login", "/coming-soon"];
+
+const WEBSITE_HOSTS = new Set([
+ "mana-collection.com",
+ "www.mana-collection.com",
+]);
+
+export default function RequireStoreAuth({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const { user, loading } = useAuth();
+ const pathname = usePathname();
+ const router = useRouter();
+
+ const host =
+ typeof window !== "undefined"
+ ? window.location.hostname.toLowerCase()
+ : "";
+ const onWebsite = WEBSITE_HOSTS.has(host);
+ const isPublic =
+ onWebsite ||
+ PUBLIC_PATHS.some((p) => pathname === p || pathname.startsWith(`${p}/`));
+
+ useEffect(() => {
+ if (loading || isPublic) return;
+ if (!user) {
+ router.replace("/login");
+ return;
+ }
+ if (user.role === "CUSTOMER") {
+ router.replace("/login?as=customer");
+ }
+ }, [user, loading, isPublic, router]);
+
+ if (isPublic) return <>{children}>;
+ if (loading) {
+ return (
+
+ در حال بارگذاری…
+
+ );
+ }
+ if (!user || user.role === "CUSTOMER") return null;
+ return <>{children}>;
+}
diff --git a/src/components/auth/AuthForm.tsx b/src/components/auth/AuthForm.tsx
new file mode 100644
index 0000000..466e2bc
--- /dev/null
+++ b/src/components/auth/AuthForm.tsx
@@ -0,0 +1,538 @@
+"use client";
+
+import Image from "next/image";
+import { useRouter, useSearchParams } from "next/navigation";
+import {
+ FormEvent,
+ InputHTMLAttributes,
+ ReactNode,
+ Suspense,
+ useState,
+} from "react";
+import ManaLogo from "@/components/ui/ManaLogo";
+import { ApiError } from "@/lib/api";
+import { useAuth } from "@/lib/auth";
+
+type AuthMode = "login" | "register";
+type LoginMethod = "password" | "otp";
+
+function AuthFormInner() {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+ const {
+ login,
+ sendLoginOtp,
+ loginWithOtp,
+ registerSendCode,
+ registerVerify,
+ } = useAuth();
+
+ const [mode, setMode] = useState("login");
+ const [loginMethod, setLoginMethod] = useState("password");
+ const [otpSent, setOtpSent] = useState(false);
+ const [registerOtpSent, setRegisterOtpSent] = useState(false);
+ const [pendingCell, setPendingCell] = useState("");
+ const [error, setError] = useState(null);
+ const [busy, setBusy] = useState(false);
+ const isLogin = mode === "login";
+ const customerHint = searchParams.get("as") === "customer";
+
+ function afterAuth(role: string) {
+ if (role === "CUSTOMER") {
+ setError(
+ "این پنل مخصوص فروشندگان است. مشتریان از وبسایت مانا کالکشن وارد شوند.",
+ );
+ return;
+ }
+ router.replace("/");
+ }
+
+ async function handleLoginPassword(event: FormEvent) {
+ event.preventDefault();
+ setError(null);
+ setBusy(true);
+ const form = new FormData(event.currentTarget);
+ const cellNumber = String(form.get("cellNumber") ?? "").trim();
+ const password = String(form.get("password") ?? "");
+ try {
+ const user = await login(cellNumber, password);
+ afterAuth(user.role);
+ } catch (err) {
+ setError(err instanceof ApiError ? err.message : "ورود ناموفق بود");
+ } finally {
+ setBusy(false);
+ }
+ }
+
+ async function handleLoginOtp(event: FormEvent) {
+ event.preventDefault();
+ setError(null);
+ setBusy(true);
+ const form = new FormData(event.currentTarget);
+ const cellNumber = String(form.get("cellNumber") ?? "").trim();
+ const code = String(form.get("code") ?? "").trim();
+ try {
+ if (!otpSent) {
+ await sendLoginOtp(cellNumber);
+ setPendingCell(cellNumber);
+ setOtpSent(true);
+ } else {
+ const user = await loginWithOtp(cellNumber || pendingCell, code);
+ afterAuth(user.role);
+ }
+ } catch (err) {
+ setError(err instanceof ApiError ? err.message : "خطا در ورود با کد");
+ } finally {
+ setBusy(false);
+ }
+ }
+
+ async function handleRegister(event: FormEvent) {
+ event.preventDefault();
+ setError(null);
+ setBusy(true);
+ const form = new FormData(event.currentTarget);
+ const firstName = String(form.get("firstName") ?? "").trim();
+ const lastName = String(form.get("lastName") ?? "").trim();
+ const cellNumber = String(form.get("cellNumber") ?? "").trim();
+ const password = String(form.get("password") ?? "");
+ const confirm = String(form.get("confirm") ?? "");
+ const code = String(form.get("code") ?? "").trim();
+
+ try {
+ if (!registerOtpSent) {
+ if (password !== confirm) {
+ setError("رمز عبور و تکرار آن یکسان نیست");
+ return;
+ }
+ await registerSendCode({ firstName, lastName, cellNumber, password });
+ setPendingCell(cellNumber);
+ setRegisterOtpSent(true);
+ } else {
+ const user = await registerVerify(cellNumber || pendingCell, code);
+ afterAuth(user.role);
+ }
+ } catch (err) {
+ setError(err instanceof ApiError ? err.message : "ثبتنام ناموفق بود");
+ } finally {
+ setBusy(false);
+ }
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {customerHint ? (
+
+ حساب شما مشتری است. برای مدیریت فروشگاه باید با حساب فروشنده وارد
+ شوید.
+
+ ) : null}
+
+ {error ? (
+ {error}
+ ) : null}
+
+
+
+
+
+ {loginMethod === "password" ? (
+
+ ) : otpSent ? (
+
+ ) : null}
+
+
+ {loginMethod === "password" ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+ {!registerOtpSent ? (
+ <>
+
+
+
+
+
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+
+ با ادامه، شرایط استفاده و حریم خصوصی مانا را میپذیرید.
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default function AuthForm() {
+ return (
+
+ در حال بارگذاری…
+
+ }
+ >
+
+
+ );
+}
+
+function AuthPanel({
+ title,
+ subtitle,
+ onSubmit,
+ children,
+}: {
+ title: string;
+ subtitle: string;
+ onSubmit: (event: FormEvent) => void;
+ children: ReactNode;
+}) {
+ return (
+
+
{title}
+
{subtitle}
+
+
+ );
+}
+
+function Field({
+ id,
+ label,
+ ...props
+}: {
+ id: string;
+ label: string;
+} & InputHTMLAttributes) {
+ return (
+
+
+
+
+ );
+}
+
+function OtpIcon() {
+ return (
+
+ );
+}
+
+function KeyMiniIcon() {
+ return (
+
+ );
+}
diff --git a/src/components/clothes/ClothesShell.tsx b/src/components/clothes/ClothesShell.tsx
new file mode 100644
index 0000000..9c720cf
--- /dev/null
+++ b/src/components/clothes/ClothesShell.tsx
@@ -0,0 +1,83 @@
+import Link from "next/link";
+import { ReactNode } from "react";
+import DashboardHeader from "@/components/dashboard/DashboardHeader";
+import Breadcrumb, { Crumb } from "@/components/ui/Breadcrumb";
+
+type ClothesShellProps = {
+ eyebrow: string;
+ title: string;
+ description?: string;
+ breadcrumbs?: Crumb[];
+ plusHref?: string;
+ onPlusClick?: () => void;
+ plusLabel?: string;
+ children: ReactNode;
+};
+
+export default function ClothesShell({
+ eyebrow,
+ title,
+ description,
+ breadcrumbs,
+ plusHref,
+ onPlusClick,
+ plusLabel = "افزودن",
+ children,
+}: ClothesShellProps) {
+ const plusContent = (
+ <>
+
+ +
+
+ {plusLabel}
+ >
+ );
+
+ return (
+
+
+
+
+
+
+ {breadcrumbs?.length ?
: null}
+
+
+ {eyebrow}
+
+
+ •
+
+ {title}
+
+ {description ? (
+
+ {description}
+
+ ) : null}
+
+
+ {onPlusClick ? (
+
+ ) : plusHref ? (
+
+ {plusContent}
+
+ ) : null}
+
+
+ {children}
+
+
+ );
+}
diff --git a/src/components/dashboard/DashTileGrid.tsx b/src/components/dashboard/DashTileGrid.tsx
new file mode 100644
index 0000000..700c338
--- /dev/null
+++ b/src/components/dashboard/DashTileGrid.tsx
@@ -0,0 +1,55 @@
+import Link from "next/link";
+import { ReactNode } from "react";
+
+export type DashTileItem = {
+ href: string;
+ title: string;
+ titleEn: string;
+ description: string;
+ icon: ReactNode;
+};
+
+type DashTileGridProps = {
+ tiles: DashTileItem[];
+ startDelayMs?: number;
+ stepMs?: number;
+};
+
+export default function DashTileGrid({
+ tiles,
+ startDelayMs = 80,
+ stepMs = 70,
+}: DashTileGridProps) {
+ return (
+
+ {tiles.map((tile, i) => (
+
+
{tile.icon}
+
+
{tile.title}
+
+ {tile.titleEn}
+
+
+ {tile.description}
+
+
+
+ مشاهده
+
+ ←
+
+
+
+ ))}
+
+ );
+}
diff --git a/src/components/dashboard/DashboardBanner.tsx b/src/components/dashboard/DashboardBanner.tsx
new file mode 100644
index 0000000..fce6538
--- /dev/null
+++ b/src/components/dashboard/DashboardBanner.tsx
@@ -0,0 +1,61 @@
+import Image from "next/image";
+import type { CSSProperties } from "react";
+
+type DashboardBannerProps = {
+ src: string;
+ alt: string;
+ caption?: string;
+ hoverTitle?: string;
+ hoverSubtitle?: string;
+ className?: string;
+ style?: CSSProperties;
+ priority?: boolean;
+};
+
+export default function DashboardBanner({
+ src,
+ alt,
+ caption = "Quiet elegance.",
+ hoverTitle = "مدیریت فروش ویژه ی من",
+ hoverSubtitle = "Special Sale",
+ className = "",
+ style,
+ priority = false,
+}: DashboardBannerProps) {
+ return (
+
+
+
+ {caption ? (
+
+ {caption}
+
+ ) : null}
+
+
+
+
{hoverTitle}
+
+ {hoverSubtitle}
+
+
+
+
+ );
+}
diff --git a/src/components/dashboard/DashboardCharts.tsx b/src/components/dashboard/DashboardCharts.tsx
new file mode 100644
index 0000000..595dff9
--- /dev/null
+++ b/src/components/dashboard/DashboardCharts.tsx
@@ -0,0 +1,248 @@
+const visitSeries = [
+ 42, 58, 51, 67, 73, 69, 88, 81, 95, 102, 97, 110, 118, 124, 119, 132, 140,
+ 136, 148, 155, 149, 162, 170, 166, 178, 185, 179, 192, 201, 214,
+];
+
+const topProducts = [
+ { name: "مانتو مشکی کلاسیک", visits: 842 },
+ { name: "پیراهن سفید مینیمال", visits: 765 },
+ { name: "کت پشمی طوسی", visits: 698 },
+ { name: "شلوار بگ کرم", visits: 641 },
+ { name: "بلوز ابریشمی", visits: 590 },
+ { name: "دامن پلیسه", visits: 552 },
+ { name: "کت جین روشن", visits: 521 },
+];
+
+function persianDayMonth(date: Date) {
+ const parts = new Intl.DateTimeFormat("en-US-u-ca-persian", {
+ month: "2-digit",
+ day: "2-digit",
+ }).formatToParts(date);
+
+ const month = parts.find((part) => part.type === "month")?.value ?? "01";
+ const day = parts.find((part) => part.type === "day")?.value ?? "01";
+ return `${day}-${month}`;
+}
+
+function buildVisitDays(count: number) {
+ const today = new Date();
+ today.setHours(12, 0, 0, 0);
+
+ return Array.from({ length: count }, (_, index) => {
+ const date = new Date(today);
+ date.setDate(today.getDate() - (count - 1 - index));
+ return {
+ value: visitSeries[index],
+ label: persianDayMonth(date),
+ };
+ });
+}
+
+function niceMax(value: number) {
+ const padded = value * 1.08;
+ const magnitude = 10 ** Math.floor(Math.log10(padded));
+ return Math.ceil(padded / magnitude) * magnitude;
+}
+
+export default function DashboardCharts({
+ startDelayMs = 0,
+}: {
+ startDelayMs?: number;
+}) {
+ const days = buildVisitDays(visitSeries.length);
+ const maxVisit = niceMax(Math.max(...visitSeries));
+ const totalVisits = visitSeries.reduce((sum, n) => sum + n, 0);
+ const maxProduct = Math.max(...topProducts.map((product) => product.visits));
+
+ const chartW = 560;
+ const chartH = 220;
+ const pad = { top: 14, right: 12, bottom: 34, left: 40 };
+ const plotW = chartW - pad.left - pad.right;
+ const plotH = chartH - pad.top - pad.bottom;
+ const step = plotW / (days.length - 1);
+ const yTicks = [0, 0.25, 0.5, 0.75, 1].map((ratio) => ({
+ ratio,
+ value: Math.round(maxVisit * ratio),
+ }));
+ const xLabelIndexes = [0, 5, 10, 15, 20, 25, days.length - 1];
+
+ const points = days
+ .map((day, index) => {
+ const x = pad.left + index * step;
+ const y = pad.top + plotH - (day.value / maxVisit) * plotH;
+ return `${x},${y}`;
+ })
+ .join(" ");
+
+ const areaPoints = `${pad.left},${pad.top + plotH} ${points} ${
+ pad.left + (days.length - 1) * step
+ },${pad.top + plotH}`;
+
+ return (
+
+
+
+
+
+ بازدید کل وبسایت
+
+
+ Last 30 days
+
+
+
+ {totalVisits.toLocaleString("en-US")}
+
+
+
+
+
+
+
+
+
+
+
+ پربازدیدترین محصولات
+
+
+ Top 7 product visits
+
+
+
+
+ {topProducts.map((product, index) => (
+ -
+
+ {String(index + 1).padStart(2, "0")}
+
+
+
+ {product.visits}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/dashboard/DashboardHeader.tsx b/src/components/dashboard/DashboardHeader.tsx
new file mode 100644
index 0000000..b77bffc
--- /dev/null
+++ b/src/components/dashboard/DashboardHeader.tsx
@@ -0,0 +1,197 @@
+"use client";
+
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import { useEffect, useRef, useState } from "react";
+import ManaLogo from "@/components/ui/ManaLogo";
+import { useAuth } from "@/lib/auth";
+
+type DashboardHeaderProps = {
+ userName?: string;
+};
+
+export default function DashboardHeader({
+ userName,
+}: DashboardHeaderProps) {
+ const { user, logout } = useAuth();
+ const router = useRouter();
+ const displayName = userName ?? user?.name ?? "کاربر";
+ const [menuOpen, setMenuOpen] = useState(false);
+ const [userOpen, setUserOpen] = useState(false);
+ const userRef = useRef(null);
+
+ useEffect(() => {
+ function handleClick(event: MouseEvent) {
+ if (!userRef.current?.contains(event.target as Node)) {
+ setUserOpen(false);
+ }
+ }
+
+ document.addEventListener("mousedown", handleClick);
+ return () => document.removeEventListener("mousedown", handleClick);
+ }, []);
+
+ async function handleLogout() {
+ setUserOpen(false);
+ await logout();
+ router.replace("/login");
+ }
+ return (
+ <>
+
+
+ {menuOpen && (
+
+ )}
+ >
+ );
+}
+
+function MenuIcon({ open }: { open: boolean }) {
+ return (
+
+ );
+}
+
+function UserIcon() {
+ return (
+
+ );
+}
+
+function KeyIcon() {
+ return (
+
+ );
+}
+
+function LogoutIcon() {
+ return (
+
+ );
+}
diff --git a/src/components/ui/Breadcrumb.tsx b/src/components/ui/Breadcrumb.tsx
new file mode 100644
index 0000000..32d8193
--- /dev/null
+++ b/src/components/ui/Breadcrumb.tsx
@@ -0,0 +1,39 @@
+import Link from "next/link";
+
+export type Crumb = {
+ label: string;
+ href?: string;
+};
+
+export default function Breadcrumb({ items }: { items: Crumb[] }) {
+ return (
+
+ );
+}
diff --git a/src/components/ui/CategoryTreeSelect.tsx b/src/components/ui/CategoryTreeSelect.tsx
new file mode 100644
index 0000000..0b29e98
--- /dev/null
+++ b/src/components/ui/CategoryTreeSelect.tsx
@@ -0,0 +1,179 @@
+"use client";
+
+import { useEffect, useMemo, useRef, useState } from "react";
+import {
+ CategoryNode,
+ categoryMatchesQuery,
+ findCategoryPath,
+} from "@/data/clothes";
+
+type CategoryTreeSelectProps = {
+ nodes: CategoryNode[];
+ value: string;
+ onChange: (id: string) => void;
+ placeholder?: string;
+ id?: string;
+};
+
+export default function CategoryTreeSelect({
+ nodes,
+ value,
+ onChange,
+ placeholder = "جستجو و انتخاب دسته...",
+ id = "category",
+}: CategoryTreeSelectProps) {
+ const rootRef = useRef(null);
+ const [open, setOpen] = useState(false);
+ const [query, setQuery] = useState("");
+ const [expanded, setExpanded] = useState>({
+ c1: true,
+ "c1-1": true,
+ c2: true,
+ });
+
+ const selectedLabel = useMemo(() => {
+ const path = findCategoryPath(nodes, value);
+ return path ? path.join(" / ") : "";
+ }, [nodes, value]);
+
+ useEffect(() => {
+ function onDocClick(event: MouseEvent) {
+ if (!rootRef.current?.contains(event.target as Node)) {
+ setOpen(false);
+ setQuery("");
+ }
+ }
+ document.addEventListener("mousedown", onDocClick);
+ return () => document.removeEventListener("mousedown", onDocClick);
+ }, []);
+
+ function toggleExpand(nodeId: string) {
+ setExpanded((prev) => ({ ...prev, [nodeId]: !prev[nodeId] }));
+ }
+
+ function selectNode(nodeId: string) {
+ onChange(nodeId);
+ setOpen(false);
+ setQuery("");
+ }
+
+ const inputValue = open ? query : selectedLabel;
+
+ return (
+
+
setOpen(true)}
+ onChange={(e) => {
+ setQuery(e.target.value);
+ setOpen(true);
+ }}
+ aria-expanded={open}
+ aria-haspopup="listbox"
+ role="combobox"
+ />
+
+ {open ? (
+
+
+
+ ) : null}
+
+ );
+}
+
+function CategoryTreeList({
+ nodes,
+ depth,
+ query,
+ expanded,
+ selectedId,
+ onToggle,
+ onSelect,
+}: {
+ nodes: CategoryNode[];
+ depth: number;
+ query: string;
+ expanded: Record;
+ selectedId: string;
+ onToggle: (id: string) => void;
+ onSelect: (id: string) => void;
+}) {
+ const filtered = nodes.filter((node) => categoryMatchesQuery(node, query));
+
+ if (!filtered.length) {
+ return depth === 0 ? (
+ دستهای پیدا نشد.
+ ) : null;
+ }
+
+ const forceOpen = Boolean(query.trim());
+
+ return (
+
+ );
+}
diff --git a/src/components/ui/ConfirmDialog.tsx b/src/components/ui/ConfirmDialog.tsx
new file mode 100644
index 0000000..f78e478
--- /dev/null
+++ b/src/components/ui/ConfirmDialog.tsx
@@ -0,0 +1,125 @@
+"use client";
+
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useRef,
+ useState,
+} from "react";
+
+export type ConfirmOptions = {
+ title?: string;
+ message: string;
+ confirmLabel?: string;
+ cancelLabel?: string;
+};
+
+type ConfirmContextValue = {
+ confirm: (options: ConfirmOptions | string) => Promise;
+};
+
+const ConfirmContext = createContext(null);
+
+type Pending = ConfirmOptions & {
+ resolve: (value: boolean) => void;
+};
+
+export function ConfirmProvider({ children }: { children: ReactNode }) {
+ const [pending, setPending] = useState(null);
+ const pendingRef = useRef(null);
+
+ const close = useCallback((value: boolean) => {
+ const current = pendingRef.current;
+ pendingRef.current = null;
+ setPending(null);
+ current?.resolve(value);
+ }, []);
+
+ const confirm = useCallback((options: ConfirmOptions | string) => {
+ const opts =
+ typeof options === "string" ? { message: options } : options;
+
+ return new Promise((resolve) => {
+ const next: Pending = {
+ title: opts.title ?? "تأیید حذف",
+ message: opts.message,
+ confirmLabel: opts.confirmLabel ?? "حذف",
+ cancelLabel: opts.cancelLabel ?? "انصراف",
+ resolve,
+ };
+ pendingRef.current = next;
+ setPending(next);
+ });
+ }, []);
+
+ useEffect(() => {
+ if (!pending) return;
+ const onKey = (e: KeyboardEvent) => {
+ if (e.key === "Escape") close(false);
+ };
+ document.addEventListener("keydown", onKey);
+ const prev = document.body.style.overflow;
+ document.body.style.overflow = "hidden";
+ return () => {
+ document.removeEventListener("keydown", onKey);
+ document.body.style.overflow = prev;
+ };
+ }, [pending, close]);
+
+ return (
+
+ {children}
+ {pending ? (
+
+
+ ) : null}
+
+ );
+}
+
+export function useConfirm() {
+ const ctx = useContext(ConfirmContext);
+ if (!ctx) {
+ throw new Error("useConfirm must be used within ConfirmProvider");
+ }
+ return ctx.confirm;
+}
diff --git a/src/components/ui/IconButton.tsx b/src/components/ui/IconButton.tsx
new file mode 100644
index 0000000..08aabe0
--- /dev/null
+++ b/src/components/ui/IconButton.tsx
@@ -0,0 +1,147 @@
+import { ButtonHTMLAttributes, ReactNode } from "react";
+
+type IconButtonProps = ButtonHTMLAttributes & {
+ label: string;
+ children: ReactNode;
+ variant?: "ghost" | "solid" | "line";
+ badge?: number | string | null;
+};
+
+const stroke = {
+ stroke: "currentColor",
+ strokeWidth: 1,
+ strokeLinecap: "round" as const,
+ strokeLinejoin: "round" as const,
+ fill: "none",
+};
+
+export default function IconButton({
+ label,
+ children,
+ variant = "ghost",
+ badge,
+ className = "",
+ type = "button",
+ ...props
+}: IconButtonProps) {
+ const showBadge =
+ badge !== null &&
+ badge !== undefined &&
+ badge !== "" &&
+ !(typeof badge === "number" && badge <= 0);
+
+ return (
+
+ {children}
+ {showBadge ? (
+
+ {badge}
+
+ ) : null}
+
+ );
+}
+
+export function EditIcon() {
+ return (
+
+ );
+}
+
+export function TrashIcon() {
+ return (
+
+ );
+}
+
+export function VariantIcon() {
+ return (
+
+ );
+}
+
+export function DiscountIcon() {
+ return (
+
+ );
+}
+
+export function FilterIcon() {
+ return (
+
+ );
+}
+
+export function ClearFilterIcon() {
+ return (
+
+ );
+}
+
+export function AddChildIcon() {
+ return (
+
+ );
+}
+
+export function SubscriptionIcon({ premium = false }: { premium?: boolean }) {
+ if (premium) {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+export function MetaTagsIcon() {
+ return (
+
+ );
+}
diff --git a/src/components/ui/ImageCropper.tsx b/src/components/ui/ImageCropper.tsx
new file mode 100644
index 0000000..a11946f
--- /dev/null
+++ b/src/components/ui/ImageCropper.tsx
@@ -0,0 +1,163 @@
+"use client";
+
+import Image from "next/image";
+import {
+ PointerEvent,
+ WheelEvent,
+ useEffect,
+ useRef,
+ useState,
+} from "react";
+
+type AspectRatio = "1:1" | "3:2" | "2:3";
+
+type ImageCropperProps = {
+ src: string;
+ aspect: AspectRatio;
+ alt?: string;
+ className?: string;
+};
+
+const MIN_ZOOM = 1;
+const MAX_ZOOM = 3;
+const ZOOM_STEP = 0.15;
+
+const aspectClass: Record = {
+ "1:1": "crop-ratio-1-1",
+ "3:2": "crop-ratio-3-2",
+ "2:3": "crop-ratio-2-3",
+};
+
+export default function ImageCropper({
+ src,
+ aspect,
+ alt = "پیشنمایش برش",
+ className = "",
+}: ImageCropperProps) {
+ const [zoom, setZoom] = useState(MIN_ZOOM);
+ const [offset, setOffset] = useState({ x: 0, y: 0 });
+ const dragRef = useRef<{
+ pointerId: number;
+ startX: number;
+ startY: number;
+ originX: number;
+ originY: number;
+ } | null>(null);
+
+ useEffect(() => {
+ setZoom(MIN_ZOOM);
+ setOffset({ x: 0, y: 0 });
+ }, [src, aspect]);
+
+ function clampZoom(value: number) {
+ return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Number(value.toFixed(2))));
+ }
+
+ function zoomBy(delta: number) {
+ setZoom((prev) => clampZoom(prev + delta));
+ }
+
+ useEffect(() => {
+ if (zoom <= MIN_ZOOM) setOffset({ x: 0, y: 0 });
+ }, [zoom]);
+
+ function onWheel(event: WheelEvent) {
+ event.preventDefault();
+ zoomBy(event.deltaY < 0 ? ZOOM_STEP : -ZOOM_STEP);
+ }
+
+ function onPointerDown(event: PointerEvent) {
+ if (zoom <= MIN_ZOOM) return;
+ event.currentTarget.setPointerCapture(event.pointerId);
+ dragRef.current = {
+ pointerId: event.pointerId,
+ startX: event.clientX,
+ startY: event.clientY,
+ originX: offset.x,
+ originY: offset.y,
+ };
+ }
+
+ function onPointerMove(event: PointerEvent) {
+ const drag = dragRef.current;
+ if (!drag || drag.pointerId !== event.pointerId) return;
+ setOffset({
+ x: drag.originX + (event.clientX - drag.startX),
+ y: drag.originY + (event.clientY - drag.startY),
+ });
+ }
+
+ function onPointerUp(event: PointerEvent) {
+ if (dragRef.current?.pointerId === event.pointerId) {
+ dragRef.current = null;
+ }
+ }
+
+ const unoptimized = src.startsWith("blob:");
+
+ return (
+
+
MIN_ZOOM ? "grab" : "default" }}
+ >
+
+
+
+
+
+
+ zoomBy(-ZOOM_STEP)}
+ >
+ −
+
+ {
+ const next = clampZoom(Number(e.target.value));
+ setZoom(next);
+ if (next <= MIN_ZOOM) setOffset({ x: 0, y: 0 });
+ }}
+ />
+ = MAX_ZOOM}
+ onClick={() => zoomBy(ZOOM_STEP)}
+ >
+ +
+
+
+
+ );
+}
diff --git a/src/components/ui/ManaLogo.tsx b/src/components/ui/ManaLogo.tsx
new file mode 100644
index 0000000..3b4c7a5
--- /dev/null
+++ b/src/components/ui/ManaLogo.tsx
@@ -0,0 +1,185 @@
+import Image from "next/image";
+import Link from "next/link";
+
+const LOGO_ASPECT = 1172 / 304;
+
+export const MANA_LOGO_SRC = {
+ default: "/images/brand/Mana-Logo.png",
+ black: "/images/brand/Mana-Logo-Black.png",
+ white: "/images/brand/Mana-Logo-White.png",
+} as const;
+
+type ManaLogoProps = {
+ href?: string;
+ className?: string;
+ priority?: boolean;
+ /** Visual height of the wordmark */
+ height?: number;
+ /** Visual width of the wordmark (overrides height when set) */
+ width?: number;
+ /** Framed lockup like the brand board */
+ framed?: boolean;
+ /** Show “The Style you desire” under the mark */
+ showTagline?: boolean;
+ taglineClassName?: string;
+ /** Logo color version */
+ variant?: keyof typeof MANA_LOGO_SRC;
+ /** Wrap mark on a black plate (slogan stays outside) */
+ blackBg?: boolean;
+ /** Slogan font size in px (default 24) */
+ taglineSize?: number;
+ /** On hover, invert logo plate + slogan colors */
+ hoverSwap?: boolean;
+};
+
+function LogoImage({
+ src,
+ width,
+ height,
+ priority,
+ className = "",
+}: {
+ src: string;
+ width: number;
+ height: number;
+ priority?: boolean;
+ className?: string;
+}) {
+ return (
+
+ );
+}
+
+export default function ManaLogo({
+ href = "/",
+ className = "",
+ priority = false,
+ height = 36,
+ width: widthProp,
+ framed = false,
+ showTagline = false,
+ taglineClassName = "",
+ variant = "default",
+ blackBg = false,
+ taglineSize = 24,
+ hoverSwap = false,
+}: ManaLogoProps) {
+ const width = widthProp ?? Math.round(height * LOGO_ASPECT);
+ const renderHeight = widthProp
+ ? Math.round(widthProp / LOGO_ASPECT)
+ : height;
+ const src =
+ variant === "white"
+ ? MANA_LOGO_SRC.white
+ : variant === "black"
+ ? MANA_LOGO_SRC.black
+ : MANA_LOGO_SRC.default;
+ const swapSrc =
+ variant === "white" ? MANA_LOGO_SRC.black : MANA_LOGO_SRC.white;
+
+ const image = (
+
+
+ {hoverSwap ? (
+
+ ) : null}
+
+ );
+
+ const markInner = framed ? (
+
+
+ {image}
+
+
+ ) : (
+ image
+ );
+
+ const mark = blackBg ? (
+
+ {markInner}
+
+ ) : (
+ markInner
+ );
+
+ const tagline = showTagline ? (
+
+ The Style you desire
+
+ ) : null;
+
+ const lockup = (
+
+ {mark}
+ {tagline}
+
+ );
+
+ if (!href) {
+ return lockup;
+ }
+
+ const isExternal = /^https?:\/\//i.test(href);
+ const interactiveClass = `group inline-flex cursor-pointer ${
+ hoverSwap ? "" : "transition-opacity duration-200 hover:opacity-80"
+ }`;
+
+ if (isExternal) {
+ return (
+
+ {lockup}
+
+ );
+ }
+
+ return (
+
+ {lockup}
+
+ );
+}
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
new file mode 100644
index 0000000..81ad6f0
--- /dev/null
+++ b/src/components/ui/Modal.tsx
@@ -0,0 +1,129 @@
+"use client";
+
+import { FormEvent, ReactNode, useEffect } from "react";
+
+type ModalProps = {
+ open: boolean;
+ title: string;
+ onClose: () => void;
+ children: ReactNode;
+ footer?: ReactNode;
+ wide?: boolean | "xl" | "full";
+};
+
+export default function Modal({
+ open,
+ title,
+ onClose,
+ children,
+ footer,
+ wide = false,
+}: ModalProps) {
+ useEffect(() => {
+ if (!open) return;
+ const onKey = (e: KeyboardEvent) => {
+ if (e.key === "Escape") onClose();
+ };
+ document.addEventListener("keydown", onKey);
+ const prev = document.body.style.overflow;
+ document.body.style.overflow = "hidden";
+ return () => {
+ document.removeEventListener("keydown", onKey);
+ document.body.style.overflow = prev;
+ };
+ }, [open, onClose]);
+
+ if (!open) return null;
+
+ const panelClass =
+ wide === "full"
+ ? "modal-panel modal-panel-full"
+ : wide === "xl"
+ ? "modal-panel modal-panel-xl"
+ : wide
+ ? "modal-panel modal-panel-wide"
+ : "modal-panel";
+
+ return (
+
+
+
+
+
+ {title}
+
+
+ ×
+
+
+
{children}
+ {footer ?
{footer}
: null}
+
+
+ );
+}
+
+type FormModalProps = {
+ open: boolean;
+ title: string;
+ onClose: () => void;
+ onSubmit: (event: FormEvent) => void;
+ submitLabel?: string;
+ children: ReactNode;
+ wide?: boolean | "xl" | "full";
+};
+
+export function FormModal({
+ open,
+ title,
+ onClose,
+ onSubmit,
+ submitLabel = "ذخیره",
+ children,
+ wide = false,
+}: FormModalProps) {
+ return (
+
+
+ انصراف
+
+
+ {submitLabel}
+
+ >
+ }
+ >
+
+
+ );
+}
diff --git a/src/components/ui/Pagination.tsx b/src/components/ui/Pagination.tsx
new file mode 100644
index 0000000..8c3b78f
--- /dev/null
+++ b/src/components/ui/Pagination.tsx
@@ -0,0 +1,101 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+
+export function usePagination(
+ items: T[],
+ pageSize: number,
+ resetKey?: string | number,
+) {
+ const [page, setPage] = useState(1);
+ const totalItems = items.length;
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize) || 1);
+
+ useEffect(() => {
+ setPage(1);
+ }, [resetKey, pageSize]);
+
+ const safePage = Math.min(Math.max(1, page), totalPages);
+
+ const pageItems = useMemo(() => {
+ const start = (safePage - 1) * pageSize;
+ return items.slice(start, start + pageSize);
+ }, [items, safePage, pageSize]);
+
+ return {
+ page: safePage,
+ setPage,
+ pageItems,
+ totalPages,
+ totalItems,
+ pageSize,
+ };
+}
+
+type PaginationProps = {
+ page: number;
+ totalPages: number;
+ totalItems: number;
+ pageSize: number;
+ onChange: (page: number) => void;
+};
+
+export default function Pagination({
+ page,
+ totalPages,
+ totalItems,
+ pageSize,
+ onChange,
+}: PaginationProps) {
+ if (totalItems === 0) return null;
+
+ const from = (page - 1) * pageSize + 1;
+ const to = Math.min(page * pageSize, totalItems);
+ const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
+
+ return (
+
+
+ {new Intl.NumberFormat("fa-IR").format(from)}–
+ {new Intl.NumberFormat("fa-IR").format(to)} از{" "}
+ {new Intl.NumberFormat("fa-IR").format(totalItems)}
+
+
+
+ onChange(page - 1)}
+ >
+ قبلی
+
+
+ {pages.map((n) => (
+ onChange(n)}
+ >
+ {new Intl.NumberFormat("fa-IR").format(n)}
+
+ ))}
+
+ = totalPages}
+ aria-label="صفحه بعد"
+ onClick={() => onChange(page + 1)}
+ >
+ بعدی
+
+
+
+ );
+}
diff --git a/src/components/ui/RichTextArea.tsx b/src/components/ui/RichTextArea.tsx
new file mode 100644
index 0000000..81825e1
--- /dev/null
+++ b/src/components/ui/RichTextArea.tsx
@@ -0,0 +1,101 @@
+"use client";
+
+import {
+ ChangeEvent,
+ useEffect,
+ useRef,
+} from "react";
+
+type RichTextAreaProps = {
+ value: string;
+ onChange: (html: string) => void;
+ placeholder?: string;
+};
+
+export default function RichTextArea({
+ value,
+ onChange,
+ placeholder = "متن مطلب را بنویسید...",
+}: RichTextAreaProps) {
+ const editorRef = useRef(null);
+ const fileRef = useRef(null);
+
+ useEffect(() => {
+ const el = editorRef.current;
+ if (!el) return;
+ if (el.innerHTML !== value) {
+ el.innerHTML = value || "";
+ }
+ }, [value]);
+
+ function emitChange() {
+ onChange(editorRef.current?.innerHTML ?? "");
+ }
+
+ function runCommand(command: string) {
+ editorRef.current?.focus();
+ document.execCommand(command, false);
+ emitChange();
+ }
+
+ function insertImage(event: ChangeEvent) {
+ const file = event.target.files?.[0];
+ if (!file || !editorRef.current) return;
+
+ const url = URL.createObjectURL(file);
+ editorRef.current.focus();
+ document.execCommand(
+ "insertHTML",
+ false,
+ `
`,
+ );
+ emitChange();
+ event.target.value = "";
+ }
+
+ return (
+
+
+ runCommand("bold")} aria-label="پررنگ">
+ B
+
+ runCommand("italic")}
+ aria-label="ایتالیک"
+ className="italic"
+ >
+ I
+
+ runCommand("underline")} aria-label="زیرخط">
+ U
+
+
+ fileRef.current?.click()}
+ aria-label="افزودن تصویر"
+ >
+ تصویر
+
+
+
+
+
+ );
+}
diff --git a/src/data/blog.ts b/src/data/blog.ts
new file mode 100644
index 0000000..8184185
--- /dev/null
+++ b/src/data/blog.ts
@@ -0,0 +1,77 @@
+export type BlogPost = {
+ id: string;
+ title: string;
+ date: string;
+ author: string;
+ abstract: string;
+ body: string;
+ image: string;
+ tags: string[];
+ metaTitle: string;
+ metaDescription: string;
+ metaKeywords: string;
+};
+
+export const blogPosts: BlogPost[] = [
+ {
+ id: "bl1",
+ title: "زیبایی در سادگی",
+ date: "2026-03-12",
+ author: "سارا محمدی",
+ abstract: "نگاهی به مینیمالیسم در طراحی لباس و نقش خطوط آرام در کالکشن مانا.",
+ body: "سادگی فقط حذف نیست؛ انتخاب آگاهانه است. در این مطلب درباره بافت، رنگ و فرم صحبت میکنیم.
",
+ image: "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg",
+ tags: ["مینیمال", "طراحی"],
+ metaTitle: "زیبایی در سادگی | مانا",
+ metaDescription: "نگاهی به مینیمالیسم در طراحی لباس",
+ metaKeywords: "مینیمال، لباس، مانا",
+ },
+ {
+ id: "bl2",
+ title: "پارچههای فصل بهار",
+ date: "2026-02-28",
+ author: "نیلوفر احمدی",
+ abstract: "انتخاب پارچه مناسب برای هوای ملایم بهار و ترکیب رنگهای خنثی.",
+ body: "بهار فرصت بازی با بافتهای سبک است. لینن، پنبه نرم و لایههای شفاف.
",
+ image: "/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg",
+ tags: ["بهار", "پارچه"],
+ metaTitle: "پارچههای فصل بهار | مانا",
+ metaDescription: "راهنمای انتخاب پارچه برای بهار",
+ metaKeywords: "بهار، پارچه، کالکشن",
+ },
+ {
+ id: "bl3",
+ title: "استایل روزمره شیک",
+ date: "2026-01-18",
+ author: "مریم کریمی",
+ abstract: "چگونه با چند قطعه پایه، استایلی مرتب و ماندگار بسازید.",
+ body: "قطعات پایه مثل مانتو کلاسیک و پیراهن ساده، ستون استایل روزمرهاند.
",
+ image: "/images/aiony-haust-owp8uQgoK8U-unsplash.jpg",
+ tags: ["استایل", "روزمره"],
+ metaTitle: "استایل روزمره شیک | مانا",
+ metaDescription: "ساخت استایل روزمره با قطعات پایه",
+ metaKeywords: "استایل، روزمره",
+ },
+ {
+ id: "bl4",
+ title: "رنگهای خنثی در کمد",
+ date: "2025-12-05",
+ author: "الهام رضایی",
+ abstract: "چرا پالت مشکی، سفید و بژ همیشه کار میکند و چگونه ترکیب شود.",
+ body: "رنگهای خنثی فضای تنفس به استایل میدهند و ترکیب آنها آسان است.
",
+ image: "/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg",
+ tags: ["رنگ", "کمد"],
+ metaTitle: "رنگهای خنثی در کمد | مانا",
+ metaDescription: "کار با پالت خنثی در استایل",
+ metaKeywords: "رنگ، مشکی، بژ",
+ },
+];
+
+export function formatBlogDate(isoDate: string) {
+ const date = new Date(`${isoDate}T12:00:00`);
+ return new Intl.DateTimeFormat("fa-IR-u-ca-persian", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ }).format(date);
+}
diff --git a/src/data/clothes.ts b/src/data/clothes.ts
new file mode 100644
index 0000000..4697809
--- /dev/null
+++ b/src/data/clothes.ts
@@ -0,0 +1,436 @@
+export type Brand = {
+ id: string;
+ nameFa: string;
+ nameEn: string;
+ image: string;
+};
+
+export type CategoryVariants = {
+ colors: string[];
+ sizes: string[];
+ packages: Array<"6" | "12">;
+};
+
+export type CategoryNode = {
+ id: string;
+ nameFa: string;
+ nameEn: string;
+ children?: CategoryNode[];
+ variants?: CategoryVariants;
+};
+
+export type ProductVariantPrice = {
+ id: string;
+ colorId: string;
+ sizeId: string;
+ packageId: string;
+ price: string;
+ discountPrice?: string;
+};
+
+export type Product = {
+ id: string;
+ nameFa: string;
+ nameEn: string;
+ summary?: string;
+ description?: string;
+ categoryId: string;
+ brandId: string;
+ price: number;
+ discountPrice?: number;
+ image: string;
+ gallery?: string[];
+ tags: string[];
+ variantPrices?: ProductVariantPrice[];
+};
+
+/** Mock DB catalogs for category variants */
+export const colorCatalog = [
+ { id: "black", nameFa: "مشکی", hex: "#0a0a0a" },
+ { id: "white", nameFa: "سفید", hex: "#f5f5f5" },
+ { id: "cream", nameFa: "کرم", hex: "#e8dcc8" },
+ { id: "beige", nameFa: "بژ", hex: "#c4a882" },
+ { id: "navy", nameFa: "سرمهای", hex: "#1b2a4a" },
+ { id: "olive", nameFa: "زیتونی", hex: "#556b2f" },
+ { id: "burgundy", nameFa: "زرشکی", hex: "#6b1e2a" },
+ { id: "gray", nameFa: "طوسی", hex: "#8a8a8a" },
+ { id: "brown", nameFa: "قهوهای", hex: "#6b4423" },
+ { id: "red", nameFa: "قرمز", hex: "#b91c1c" },
+];
+
+export const sizeCatalog = [
+ { id: "xs", nameFa: "XS" },
+ { id: "s", nameFa: "S" },
+ { id: "m", nameFa: "M" },
+ { id: "l", nameFa: "L" },
+ { id: "xl", nameFa: "XL" },
+ { id: "xxl", nameFa: "XXL" },
+ { id: "36", nameFa: "36" },
+ { id: "38", nameFa: "38" },
+ { id: "40", nameFa: "40" },
+ { id: "42", nameFa: "42" },
+ { id: "44", nameFa: "44" },
+];
+
+export const packageCatalog: Array<{ id: "6" | "12"; nameFa: string }> = [
+ { id: "6", nameFa: "۶ تایی" },
+ { id: "12", nameFa: "۱۲ تایی" },
+];
+
+export const emptyVariants = (): CategoryVariants => ({
+ colors: [],
+ sizes: [],
+ packages: [],
+});
+
+export const brands: Brand[] = [
+ {
+ id: "b1",
+ nameFa: "مانا",
+ nameEn: "Mana",
+ image: "/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg",
+ },
+ {
+ id: "b2",
+ nameFa: "نویر",
+ nameEn: "Noir",
+ image: "/images/aiony-haust-owp8uQgoK8U-unsplash.jpg",
+ },
+ {
+ id: "b3",
+ nameFa: "لومن",
+ nameEn: "Lumen",
+ image: "/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg",
+ },
+ {
+ id: "b4",
+ nameFa: "اتلیه",
+ nameEn: "Atelier",
+ image: "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg",
+ },
+];
+
+export const categories: CategoryNode[] = [
+ {
+ id: "c1",
+ nameFa: "زنانه",
+ nameEn: "Women",
+ children: [
+ {
+ id: "c1-1",
+ nameFa: "مانتو",
+ nameEn: "Manteau",
+ variants: {
+ colors: ["black", "cream", "navy", "gray"],
+ sizes: ["s", "m", "l", "xl"],
+ packages: ["6"],
+ },
+ children: [
+ { id: "c1-1-1", nameFa: "بهاره", nameEn: "Spring" },
+ { id: "c1-1-2", nameFa: "پاییزه", nameEn: "Autumn" },
+ ],
+ },
+ {
+ id: "c1-2",
+ nameFa: "پیراهن",
+ nameEn: "Dress",
+ variants: {
+ colors: ["white", "olive", "red", "beige"],
+ sizes: ["36", "38", "40", "42"],
+ packages: ["6", "12"],
+ },
+ },
+ {
+ id: "c1-3",
+ nameFa: "شلوار",
+ nameEn: "Trousers",
+ variants: {
+ colors: ["black", "beige", "olive"],
+ sizes: ["38", "40", "42", "44"],
+ packages: [],
+ },
+ },
+ ],
+ },
+ {
+ id: "c2",
+ nameFa: "مردانه",
+ nameEn: "Men",
+ children: [
+ { id: "c2-1", nameFa: "کت", nameEn: "Jacket" },
+ { id: "c2-2", nameFa: "پیراهن رسمی", nameEn: "Shirt" },
+ ],
+ },
+ {
+ id: "c3",
+ nameFa: "اکسسوری",
+ nameEn: "Accessories",
+ children: [
+ { id: "c3-1", nameFa: "کیف", nameEn: "Bag" },
+ { id: "c3-2", nameFa: "کفش", nameEn: "Shoes" },
+ ],
+ },
+];
+
+export const products: Product[] = [
+ {
+ id: "p1",
+ nameFa: "مانتو مشکی کلاسیک",
+ nameEn: "Classic Black Manteau",
+ categoryId: "c1-1",
+ brandId: "b1",
+ price: 4200000,
+ discountPrice: 3570000,
+ image: "/images/aiony-haust-owp8uQgoK8U-unsplash.jpg",
+ tags: ["کلاسیک", "مشکی"],
+ },
+ {
+ id: "p2",
+ nameFa: "پیراهن سفید مینیمال",
+ nameEn: "Minimal White Dress",
+ categoryId: "c1-2",
+ brandId: "b3",
+ price: 2800000,
+ image: "/images/jonathan-borba-XJt51hAa3z8-unsplash.jpg",
+ tags: ["مینیمال", "سفید"],
+ },
+ {
+ id: "p3",
+ nameFa: "کت پشمی طوسی",
+ nameEn: "Grey Wool Coat",
+ categoryId: "c2-1",
+ brandId: "b2",
+ price: 5100000,
+ discountPrice: 4590000,
+ image: "/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg",
+ tags: ["زمستانه"],
+ },
+ {
+ id: "p4",
+ nameFa: "شلوار بگ کرم",
+ nameEn: "Cream Baggy Pants",
+ categoryId: "c1-3",
+ brandId: "b1",
+ price: 1950000,
+ image: "/images/chyntia-juls-HlVjI5WmoQY-unsplash.jpg",
+ tags: ["روزمره"],
+ },
+ {
+ id: "p5",
+ nameFa: "بلوز ابریشمی زیتونی",
+ nameEn: "Olive Silk Blouse",
+ categoryId: "c1-2",
+ brandId: "b4",
+ price: 2400000,
+ discountPrice: 1920000,
+ image: "/images/valerie-elash-T5tIoXFJfSk-unsplash.jpg",
+ tags: ["ابریشم"],
+ },
+ {
+ id: "p6",
+ nameFa: "دامن پلیسه مشکی",
+ nameEn: "Black Pleated Skirt",
+ categoryId: "c1-2",
+ brandId: "b2",
+ price: 1680000,
+ image: "/images/eve-maier-u1OuYQa0WtQ-unsplash.jpg",
+ tags: ["مجلسی"],
+ },
+ {
+ id: "p7",
+ nameFa: "کت جین روشن",
+ nameEn: "Light Denim Jacket",
+ categoryId: "c2-1",
+ brandId: "b3",
+ price: 3200000,
+ discountPrice: 2880000,
+ image: "/images/amir-asghari-xoEb3kS_YoM-unsplash.jpg",
+ tags: ["جین"],
+ },
+ {
+ id: "p8",
+ nameFa: "پیراهن زرد ابریشمی",
+ nameEn: "Yellow Silk Dress",
+ categoryId: "c1-2",
+ brandId: "b4",
+ price: 3900000,
+ image: "/images/ryanwar-hanif-98XENwtPMCc-unsplash.jpg",
+ tags: ["رنگارنگ"],
+ },
+];
+
+export function formatPrice(value: number) {
+ return new Intl.NumberFormat("en-US").format(value);
+}
+
+export function discountPercent(price: number, discountPrice: number) {
+ return Math.round(((price - discountPrice) / price) * 100);
+}
+
+export function flattenCategories(
+ nodes: CategoryNode[],
+ prefix = "",
+): { id: string; label: string }[] {
+ return nodes.flatMap((node) => {
+ const label = prefix ? `${prefix} / ${node.nameFa}` : node.nameFa;
+ return [
+ { id: node.id, label },
+ ...(node.children ? flattenCategories(node.children, label) : []),
+ ];
+ });
+}
+
+export function findCategoryNode(
+ nodes: CategoryNode[],
+ id: string,
+): CategoryNode | null {
+ for (const node of nodes) {
+ if (node.id === id) return node;
+ if (node.children?.length) {
+ const found = findCategoryNode(node.children, id);
+ if (found) return found;
+ }
+ }
+ return null;
+}
+
+/** Resolve variants from category or nearest parent that has them */
+export function resolveCategoryVariants(
+ categoryId: string,
+ nodes: CategoryNode[] = categories,
+): CategoryVariants | null {
+ let current = findCategoryNode(nodes, categoryId);
+ while (current) {
+ if (
+ current.variants &&
+ (current.variants.colors.length ||
+ current.variants.sizes.length ||
+ current.variants.packages.length)
+ ) {
+ return current.variants;
+ }
+ const parent = findParentCategory(nodes, current.id);
+ if (!parent) break;
+ current = parent;
+ }
+ return null;
+}
+
+function findParentCategory(
+ nodes: CategoryNode[],
+ childId: string,
+): CategoryNode | null {
+ for (const node of nodes) {
+ if (node.children?.some((c) => c.id === childId)) return node;
+ if (node.children?.length) {
+ const found = findParentCategory(node.children, childId);
+ if (found) return found;
+ }
+ }
+ return null;
+}
+
+export function getCategoryVariantOptions(
+ categoryId: string,
+ nodes: CategoryNode[] = categories,
+) {
+ const groups = getCategoryVariantGroups(categoryId, nodes);
+ return [
+ ...groups.colors.map((opt) => ({
+ value: `color:${opt.value}`,
+ label: `رنگ · ${opt.label}`,
+ })),
+ ...groups.sizes.map((opt) => ({
+ value: `size:${opt.value}`,
+ label: `سایز · ${opt.label}`,
+ })),
+ ...groups.packages.map((opt) => ({
+ value: `package:${opt.value}`,
+ label: `پکیج · ${opt.label}`,
+ })),
+ ];
+}
+
+export function getCategoryVariantGroups(
+ categoryId: string,
+ nodes: CategoryNode[] = categories,
+) {
+ const variants = resolveCategoryVariants(categoryId, nodes);
+ const empty = {
+ colors: [] as { value: string; label: string }[],
+ sizes: [] as { value: string; label: string }[],
+ packages: [] as { value: string; label: string }[],
+ };
+ if (!variants) return empty;
+
+ return {
+ colors: variants.colors
+ .map((id) => {
+ const color = colorCatalog.find((item) => item.id === id);
+ return color ? { value: id, label: color.nameFa } : null;
+ })
+ .filter(Boolean) as { value: string; label: string }[],
+ sizes: variants.sizes
+ .map((id) => {
+ const size = sizeCatalog.find((item) => item.id === id);
+ return size ? { value: id, label: size.nameFa } : null;
+ })
+ .filter(Boolean) as { value: string; label: string }[],
+ packages: variants.packages
+ .map((id) => {
+ const pack = packageCatalog.find((item) => item.id === id);
+ return pack
+ ? { value: id, label: `${pack.nameFa} (${id} pcs)` }
+ : null;
+ })
+ .filter(Boolean) as { value: string; label: string }[],
+ };
+}
+
+export function getVariantLabel(
+ row: Pick,
+ categoryId: string,
+ nodes: CategoryNode[] = categories,
+) {
+ const groups = getCategoryVariantGroups(categoryId, nodes);
+ const parts: string[] = [];
+ if (row.colorId) {
+ const color = groups.colors.find((opt) => opt.value === row.colorId);
+ if (color) parts.push(`رنگ · ${color.label}`);
+ }
+ if (row.sizeId) {
+ const size = groups.sizes.find((opt) => opt.value === row.sizeId);
+ if (size) parts.push(`سایز · ${size.label}`);
+ }
+ if (row.packageId) {
+ const pack = groups.packages.find((opt) => opt.value === row.packageId);
+ if (pack) parts.push(`پکیج · ${pack.label}`);
+ }
+ return parts.length ? parts.join(" / ") : "بدون تنوع";
+}
+
+export function findCategoryPath(
+ nodes: CategoryNode[],
+ id: string,
+ trail: string[] = [],
+): string[] | null {
+ for (const node of nodes) {
+ const next = [...trail, node.nameFa];
+ if (node.id === id) return next;
+ if (node.children?.length) {
+ const found = findCategoryPath(node.children, id, next);
+ if (found) return found;
+ }
+ }
+ return null;
+}
+
+export function categoryMatchesQuery(node: CategoryNode, query: string): boolean {
+ const q = query.trim().toLowerCase();
+ if (!q) return true;
+ const self =
+ node.nameFa.includes(query.trim()) ||
+ node.nameEn.toLowerCase().includes(q);
+ if (self) return true;
+ return Boolean(node.children?.some((child) => categoryMatchesQuery(child, query)));
+}
diff --git a/src/data/customers.ts b/src/data/customers.ts
new file mode 100644
index 0000000..3013149
--- /dev/null
+++ b/src/data/customers.ts
@@ -0,0 +1,81 @@
+export type SubscriptionStatus = "regular" | "premium";
+
+export type Customer = {
+ id: string;
+ nameFa: string;
+ phone: string;
+ joinedAt: string;
+ subscription: SubscriptionStatus;
+};
+
+export const customers: Customer[] = [
+ {
+ id: "cu1",
+ nameFa: "سارا محمدی",
+ phone: "09121234567",
+ joinedAt: "2025-11-12",
+ subscription: "premium",
+ },
+ {
+ id: "cu2",
+ nameFa: "نیلوفر احمدی",
+ phone: "09351239876",
+ joinedAt: "2026-01-04",
+ subscription: "regular",
+ },
+ {
+ id: "cu3",
+ nameFa: "مریم کریمی",
+ phone: "09197654321",
+ joinedAt: "2025-08-21",
+ subscription: "premium",
+ },
+ {
+ id: "cu4",
+ nameFa: "الهام رضایی",
+ phone: "09014567890",
+ joinedAt: "2026-02-18",
+ subscription: "regular",
+ },
+ {
+ id: "cu5",
+ nameFa: "هانیه موسوی",
+ phone: "09128887766",
+ joinedAt: "2025-12-02",
+ subscription: "regular",
+ },
+ {
+ id: "cu6",
+ nameFa: "یاسمن نوری",
+ phone: "09361112233",
+ joinedAt: "2026-03-09",
+ subscription: "premium",
+ },
+ {
+ id: "cu7",
+ nameFa: "زهرا حسینی",
+ phone: "09201230000",
+ joinedAt: "2025-06-30",
+ subscription: "regular",
+ },
+ {
+ id: "cu8",
+ nameFa: "فرناز اکبری",
+ phone: "09193456789",
+ joinedAt: "2026-04-01",
+ subscription: "premium",
+ },
+];
+
+export function formatJoinedDate(isoDate: string) {
+ const date = new Date(`${isoDate}T12:00:00`);
+ return new Intl.DateTimeFormat("fa-IR-u-ca-persian", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ }).format(date);
+}
+
+export function subscriptionLabel(status: SubscriptionStatus) {
+ return status === "premium" ? "پرمیوم" : "عادی";
+}
diff --git a/src/fonts/Cailyne.otf b/src/fonts/Cailyne.otf
new file mode 100644
index 0000000..94665c2
Binary files /dev/null and b/src/fonts/Cailyne.otf differ
diff --git a/src/fonts/Cailyne.ttf b/src/fonts/Cailyne.ttf
new file mode 100644
index 0000000..a61ccd9
Binary files /dev/null and b/src/fonts/Cailyne.ttf differ
diff --git a/src/fonts/doran/Doran-Bold.woff b/src/fonts/doran/Doran-Bold.woff
new file mode 100644
index 0000000..08506e0
Binary files /dev/null and b/src/fonts/doran/Doran-Bold.woff differ
diff --git a/src/fonts/doran/Doran-Medium.woff b/src/fonts/doran/Doran-Medium.woff
new file mode 100644
index 0000000..6d7817a
Binary files /dev/null and b/src/fonts/doran/Doran-Medium.woff differ
diff --git a/src/fonts/doran/Doran-Regular.woff b/src/fonts/doran/Doran-Regular.woff
new file mode 100644
index 0000000..dc4a563
Binary files /dev/null and b/src/fonts/doran/Doran-Regular.woff differ
diff --git a/src/fonts/doran/Doran-Thin.woff b/src/fonts/doran/Doran-Thin.woff
new file mode 100644
index 0000000..44fbba7
Binary files /dev/null and b/src/fonts/doran/Doran-Thin.woff differ
diff --git a/src/lib/api.ts b/src/lib/api.ts
new file mode 100644
index 0000000..d33d1b7
--- /dev/null
+++ b/src/lib/api.ts
@@ -0,0 +1,188 @@
+const API_URL =
+ process.env.NEXT_PUBLIC_API_URL?.replace(/\/$/, "") ||
+ "http://api.mana-collection.com:3002/api/v1";
+
+export class ApiError extends Error {
+ status: number;
+ body: unknown;
+
+ constructor(status: number, message: string, body?: unknown) {
+ super(message);
+ this.status = status;
+ this.body = body;
+ }
+}
+
+type RequestOptions = {
+ method?: string;
+ body?: unknown;
+ token?: string | null;
+ auth?: boolean;
+};
+
+function getStoredAccessToken() {
+ if (typeof window === "undefined") return null;
+ return localStorage.getItem("mana_access_token");
+}
+
+function getStoredRefreshToken() {
+ if (typeof window === "undefined") return null;
+ return localStorage.getItem("mana_refresh_token");
+}
+
+export function setTokens(accessToken: string, refreshToken: string) {
+ localStorage.setItem("mana_access_token", accessToken);
+ localStorage.setItem("mana_refresh_token", refreshToken);
+}
+
+export function clearTokens() {
+ localStorage.removeItem("mana_access_token");
+ localStorage.removeItem("mana_refresh_token");
+ localStorage.removeItem("mana_user");
+}
+
+export function storeUser(user: unknown) {
+ localStorage.setItem("mana_user", JSON.stringify(user));
+}
+
+export function readStoredUser() {
+ if (typeof window === "undefined") return null;
+ const raw = localStorage.getItem("mana_user");
+ if (!raw) return null;
+ try {
+ return JSON.parse(raw) as T;
+ } catch {
+ return null;
+ }
+}
+
+async function parseError(res: Response) {
+ const body = await res.json().catch(() => null);
+ const message =
+ (body && typeof body === "object" && "message" in body
+ ? Array.isArray((body as { message: unknown }).message)
+ ? (body as { message: string[] }).message.join("، ")
+ : String((body as { message: unknown }).message)
+ : null) || res.statusText || "خطای سرور";
+ return new ApiError(res.status, message, body);
+}
+
+let refreshPromise: Promise | null = null;
+
+async function refreshAccessToken(): Promise {
+ const refreshToken = getStoredRefreshToken();
+ if (!refreshToken) return null;
+ if (!refreshPromise) {
+ refreshPromise = (async () => {
+ try {
+ const res = await fetch(`${API_URL}/auth/refresh`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ refreshToken }),
+ });
+ if (!res.ok) {
+ clearTokens();
+ return null;
+ }
+ const data = (await res.json()) as {
+ accessToken: string;
+ refreshToken: string;
+ user: unknown;
+ };
+ setTokens(data.accessToken, data.refreshToken);
+ storeUser(data.user);
+ return data.accessToken;
+ } catch {
+ clearTokens();
+ return null;
+ } finally {
+ refreshPromise = null;
+ }
+ })();
+ }
+ return refreshPromise;
+}
+
+export async function api(
+ path: string,
+ options: RequestOptions = {},
+): Promise {
+ const headers: Record = {};
+ if (options.body !== undefined) {
+ headers["Content-Type"] = "application/json";
+ }
+
+ const useAuth = options.auth !== false;
+ let token = options.token ?? (useAuth ? getStoredAccessToken() : null);
+ if (token) headers.Authorization = `Bearer ${token}`;
+
+ const doFetch = () =>
+ fetch(`${API_URL}${path.startsWith("/") ? path : `/${path}`}`, {
+ method: options.method ?? (options.body !== undefined ? "POST" : "GET"),
+ headers,
+ body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
+ });
+
+ let res = await doFetch();
+
+ if (res.status === 401 && useAuth && !options.token) {
+ const next = await refreshAccessToken();
+ if (next) {
+ headers.Authorization = `Bearer ${next}`;
+ res = await doFetch();
+ }
+ }
+
+ if (!res.ok) throw await parseError(res);
+ if (res.status === 204) return undefined as T;
+ return (await res.json()) as T;
+}
+
+export type MediaKind =
+ | "main"
+ | "gallery"
+ | "blog"
+ | "brand"
+ | "store"
+ | "avatar"
+ | "temp";
+
+export type MediaUploadResult = {
+ url: string;
+ storageKey: string;
+ storageDisk: string;
+};
+
+export async function uploadMedia(
+ file: File,
+ kind: MediaKind,
+): Promise {
+ const form = new FormData();
+ form.append("file", file);
+
+ const headers: Record = {};
+ let token = getStoredAccessToken();
+ if (token) headers.Authorization = `Bearer ${token}`;
+
+ const doFetch = () =>
+ fetch(`${API_URL}/media/upload?kind=${encodeURIComponent(kind)}`, {
+ method: "POST",
+ headers,
+ body: form,
+ });
+
+ let res = await doFetch();
+
+ if (res.status === 401) {
+ const next = await refreshAccessToken();
+ if (next) {
+ headers.Authorization = `Bearer ${next}`;
+ res = await doFetch();
+ }
+ }
+
+ if (!res.ok) throw await parseError(res);
+ return (await res.json()) as MediaUploadResult;
+}
+
+export { API_URL };
diff --git a/src/lib/auth.tsx b/src/lib/auth.tsx
new file mode 100644
index 0000000..fdd371c
--- /dev/null
+++ b/src/lib/auth.tsx
@@ -0,0 +1,201 @@
+"use client";
+
+import {
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useState,
+ type ReactNode,
+} from "react";
+import {
+ api,
+ clearTokens,
+ readStoredUser,
+ setTokens,
+ storeUser,
+} from "@/lib/api";
+
+export type AuthStore = {
+ id: string;
+ slug: string;
+ nameFa: string;
+ nameEn?: string;
+ status: "pending" | "active" | "rejected" | "suspended";
+} | null;
+
+export type AuthSessionUser = {
+ id: string;
+ firstName: string;
+ lastName: string;
+ cellNumber: string;
+ role: "CUSTOMER" | "STORE_ADMIN" | "SUPER_ADMIN";
+ name: string;
+ store?: AuthStore;
+};
+
+type TokenResponse = {
+ accessToken: string;
+ refreshToken: string;
+ user: AuthSessionUser;
+};
+
+type AuthContextValue = {
+ user: AuthSessionUser | null;
+ loading: boolean;
+ login: (cellNumber: string, password: string) => Promise;
+ loginWithOtp: (cellNumber: string, code: string) => Promise;
+ sendLoginOtp: (cellNumber: string) => Promise;
+ registerSendCode: (input: {
+ firstName: string;
+ lastName: string;
+ cellNumber: string;
+ password: string;
+ }) => Promise;
+ registerVerify: (
+ cellNumber: string,
+ code: string,
+ ) => Promise;
+ logout: () => Promise;
+ refreshMe: () => Promise;
+};
+
+const AuthContext = createContext(null);
+
+function persistSession(data: TokenResponse) {
+ setTokens(data.accessToken, data.refreshToken);
+ storeUser(data.user);
+ return data.user;
+}
+
+export function AuthProvider({ children }: { children: ReactNode }) {
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ const refreshMe = useCallback(async () => {
+ try {
+ const me = await api("/auth/me");
+ storeUser(me);
+ setUser(me);
+ } catch {
+ clearTokens();
+ setUser(null);
+ }
+ }, []);
+
+ useEffect(() => {
+ const cached = readStoredUser();
+ if (cached) setUser(cached);
+ const token =
+ typeof window !== "undefined"
+ ? localStorage.getItem("mana_access_token")
+ : null;
+ if (!token) {
+ setLoading(false);
+ return;
+ }
+ void refreshMe().finally(() => setLoading(false));
+ }, [refreshMe]);
+
+ const login = useCallback(async (cellNumber: string, password: string) => {
+ const data = await api("/auth/login", {
+ auth: false,
+ body: { cellNumber, password },
+ });
+ const next = persistSession(data);
+ setUser(next);
+ return next;
+ }, []);
+
+ const sendLoginOtp = useCallback(async (cellNumber: string) => {
+ await api("/auth/login/send-code", {
+ auth: false,
+ body: { cellNumber },
+ });
+ }, []);
+
+ const loginWithOtp = useCallback(async (cellNumber: string, code: string) => {
+ const data = await api("/auth/login/verify", {
+ auth: false,
+ body: { cellNumber, code },
+ });
+ const next = persistSession(data);
+ setUser(next);
+ return next;
+ }, []);
+
+ const registerSendCode = useCallback(
+ async (input: {
+ firstName: string;
+ lastName: string;
+ cellNumber: string;
+ password: string;
+ }) => {
+ await api("/auth/register/send-code", { auth: false, body: input });
+ },
+ [],
+ );
+
+ const registerVerify = useCallback(
+ async (cellNumber: string, code: string) => {
+ const data = await api("/auth/register/verify", {
+ auth: false,
+ body: { cellNumber, code },
+ });
+ const next = persistSession(data);
+ setUser(next);
+ return next;
+ },
+ [],
+ );
+
+ const logout = useCallback(async () => {
+ const refreshToken =
+ typeof window !== "undefined"
+ ? localStorage.getItem("mana_refresh_token")
+ : null;
+ try {
+ if (refreshToken) {
+ await api("/auth/logout", { auth: false, body: { refreshToken } });
+ }
+ } catch {
+ /* ignore */
+ }
+ clearTokens();
+ setUser(null);
+ }, []);
+
+ const value = useMemo(
+ () => ({
+ user,
+ loading,
+ login,
+ loginWithOtp,
+ sendLoginOtp,
+ registerSendCode,
+ registerVerify,
+ logout,
+ refreshMe,
+ }),
+ [
+ user,
+ loading,
+ login,
+ loginWithOtp,
+ sendLoginOtp,
+ registerSendCode,
+ registerVerify,
+ logout,
+ refreshMe,
+ ],
+ );
+
+ return {children};
+}
+
+export function useAuth() {
+ const ctx = useContext(AuthContext);
+ if (!ctx) throw new Error("useAuth must be used within AuthProvider");
+ return ctx;
+}
diff --git a/src/lib/blog-api.ts b/src/lib/blog-api.ts
new file mode 100644
index 0000000..025873b
--- /dev/null
+++ b/src/lib/blog-api.ts
@@ -0,0 +1,59 @@
+import { api } from "@/lib/api";
+import type { BlogPost } from "@/data/blog";
+
+export type ApiBlog = {
+ id: string;
+ title: string;
+ summary: string;
+ body: string;
+ author: string;
+ imageUrl: string | null;
+ imageKey?: string | null;
+ published: boolean;
+ metaTitle: string | null;
+ metaDescription: string | null;
+ slug: string | null;
+ createdAt: string;
+ updatedAt?: string;
+};
+
+export function mapBlog(row: ApiBlog): BlogPost {
+ const created = row.createdAt ? new Date(row.createdAt) : new Date();
+ return {
+ id: row.id,
+ title: row.title,
+ date: created.toISOString().slice(0, 10),
+ author: row.author || "",
+ abstract: row.summary || "",
+ body: row.body || "",
+ image: row.imageUrl || "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg",
+ tags: [],
+ metaTitle: row.metaTitle || "",
+ metaDescription: row.metaDescription || "",
+ metaKeywords: "",
+ };
+}
+
+export async function fetchBlogs() {
+ const rows = await api("/blogs");
+ return rows.map(mapBlog);
+}
+
+export async function fetchBlog(id: string) {
+ const row = await api(`/blogs/${id}`);
+ return mapBlog(row);
+}
+
+export async function createBlog(body: Record) {
+ const row = await api("/blogs", { method: "POST", body });
+ return mapBlog(row);
+}
+
+export async function updateBlog(id: string, body: Record) {
+ const row = await api(`/blogs/${id}`, { method: "PATCH", body });
+ return mapBlog(row);
+}
+
+export async function deleteBlog(id: string) {
+ await api(`/blogs/${id}`, { method: "DELETE" });
+}
diff --git a/src/lib/clothes-api.ts b/src/lib/clothes-api.ts
new file mode 100644
index 0000000..fb2a5d9
--- /dev/null
+++ b/src/lib/clothes-api.ts
@@ -0,0 +1,257 @@
+import { api } from "@/lib/api";
+import type {
+ Brand,
+ CategoryNode,
+ Product,
+ ProductVariantPrice,
+} from "@/data/clothes";
+
+export type ApiProductVariant = {
+ id: string;
+ colorId: string;
+ sizeId: string;
+ packageId: string;
+ price: number;
+ discountPrice: number | null;
+};
+
+export type ApiProduct = {
+ id: string;
+ nameFa: string;
+ nameEn: string;
+ summary?: string;
+ description?: string;
+ categoryId: string | null;
+ brandId: string | null;
+ price: number;
+ discountPrice: number | null;
+ imageUrl: string | null;
+ galleryUrls?: string[];
+ tags: string[];
+ variants: ApiProductVariant[];
+};
+
+export type ApiCategory = {
+ id: string;
+ parentId: string | null;
+ nameFa: string;
+ nameEn: string;
+ sortOrder: number;
+ colors: string[];
+ sizes: string[];
+ packages: string[];
+ children?: ApiCategory[];
+};
+
+export function mapVariant(v: ApiProductVariant): ProductVariantPrice {
+ return {
+ id: v.id,
+ colorId: v.colorId ?? "",
+ sizeId: v.sizeId ?? "",
+ packageId: v.packageId ?? "",
+ price: String(v.price ?? ""),
+ discountPrice:
+ v.discountPrice != null ? String(v.discountPrice) : undefined,
+ };
+}
+
+export function mapProduct(p: ApiProduct): Product {
+ return {
+ id: p.id,
+ nameFa: p.nameFa,
+ nameEn: p.nameEn ?? "",
+ summary: p.summary ?? "",
+ description: p.description ?? "",
+ categoryId: p.categoryId ?? "",
+ brandId: p.brandId ?? "",
+ price: p.price,
+ discountPrice: p.discountPrice ?? undefined,
+ image: p.imageUrl || "/images/ahmad-ebadi-r5IzkiO08JU-unsplash.jpg",
+ gallery: p.galleryUrls ?? [],
+ tags: p.tags ?? [],
+ variantPrices: (p.variants ?? []).map(mapVariant),
+ };
+}
+
+export function toVariantPayload(rows: ProductVariantPrice[]) {
+ return rows.map((row) => ({
+ ...(row.id && !row.id.startsWith("vp-") ? { id: row.id } : {}),
+ colorId: row.colorId || "",
+ sizeId: row.sizeId || "",
+ packageId: row.packageId || "",
+ price: Number(row.price) || 0,
+ discountPrice: row.discountPrice
+ ? Number(row.discountPrice) || undefined
+ : undefined,
+ }));
+}
+
+export async function fetchProducts(params?: {
+ name?: string;
+ categoryId?: string;
+ minPrice?: number;
+ maxPrice?: number;
+}) {
+ const q = new URLSearchParams();
+ if (params?.name) q.set("name", params.name);
+ if (params?.categoryId) q.set("categoryId", params.categoryId);
+ if (params?.minPrice != null) q.set("minPrice", String(params.minPrice));
+ if (params?.maxPrice != null) q.set("maxPrice", String(params.maxPrice));
+ const qs = q.toString();
+ const rows = await api(`/products${qs ? `?${qs}` : ""}`);
+ return rows.map(mapProduct);
+}
+
+export async function updateProduct(
+ id: string,
+ body: Record,
+) {
+ const row = await api(`/products/${id}`, {
+ method: "PATCH",
+ body,
+ });
+ return mapProduct(row);
+}
+
+export async function deleteProduct(id: string) {
+ await api(`/products/${id}`, { method: "DELETE" });
+}
+
+export async function createProduct(body: Record) {
+ const row = await api(`/products`, {
+ method: "POST",
+ body,
+ });
+ return mapProduct(row);
+}
+
+export type ApiBrand = {
+ id: string;
+ nameFa: string;
+ nameEn: string;
+ imageUrl: string | null;
+ imageKey?: string | null;
+};
+
+export function mapBrand(b: ApiBrand): Brand {
+ return {
+ id: b.id,
+ nameFa: b.nameFa,
+ nameEn: b.nameEn ?? "",
+ image: b.imageUrl || "/images/ola-szkolda-J61EvbE1UCE-unsplash.jpg",
+ };
+}
+
+export async function fetchBrands() {
+ const rows = await api("/brands");
+ return rows.map(mapBrand);
+}
+
+export async function createBrand(body: {
+ nameFa: string;
+ nameEn?: string;
+ imageUrl?: string;
+ imageKey?: string;
+}) {
+ const row = await api("/brands", { method: "POST", body });
+ return mapBrand(row);
+}
+
+export async function updateBrand(
+ id: string,
+ body: {
+ nameFa?: string;
+ nameEn?: string;
+ imageUrl?: string | null;
+ imageKey?: string | null;
+ },
+) {
+ const row = await api(`/brands/${id}`, { method: "PATCH", body });
+ return mapBrand(row);
+}
+
+export async function deleteBrand(id: string) {
+ await api(`/brands/${id}`, { method: "DELETE" });
+}
+
+export async function createCategory(body: {
+ nameFa: string;
+ nameEn?: string;
+ parentId?: string;
+ colors?: string[];
+ sizes?: string[];
+ packages?: string[];
+ sortOrder?: number;
+}) {
+ await api("/categories", { method: "POST", body });
+ return fetchCategoriesTree();
+}
+
+export async function updateCategory(
+ id: string,
+ body: {
+ nameFa?: string;
+ nameEn?: string;
+ parentId?: string | null;
+ colors?: string[];
+ sizes?: string[];
+ packages?: string[];
+ sortOrder?: number;
+ },
+) {
+ await api(`/categories/${id}`, { method: "PATCH", body });
+ return fetchCategoriesTree();
+}
+
+export async function deleteCategory(id: string) {
+ await api(`/categories/${id}`, { method: "DELETE" });
+ return fetchCategoriesTree();
+}
+
+function nestCategories(flat: ApiCategory[]): CategoryNode[] {
+ const byParent = new Map();
+ for (const cat of flat) {
+ const key = cat.parentId;
+ const list = byParent.get(key) ?? [];
+ list.push(cat);
+ byParent.set(key, list);
+ }
+
+ function build(parentId: string | null): CategoryNode[] {
+ const nodes = (byParent.get(parentId) ?? []).sort(
+ (a, b) => a.sortOrder - b.sortOrder,
+ );
+ return nodes.map((node) => ({
+ id: node.id,
+ nameFa: node.nameFa,
+ nameEn: node.nameEn,
+ variants: {
+ colors: node.colors ?? [],
+ sizes: node.sizes ?? [],
+ packages: (node.packages ?? []) as Array<"6" | "12">,
+ },
+ children: build(node.id),
+ }));
+ }
+
+ return build(null);
+}
+
+export async function fetchCategoriesTree(): Promise {
+ const rows = await api("/categories");
+ if (rows.some((r) => r.children && r.children.length)) {
+ const mapNode = (node: ApiCategory): CategoryNode => ({
+ id: node.id,
+ nameFa: node.nameFa,
+ nameEn: node.nameEn,
+ variants: {
+ colors: node.colors ?? [],
+ sizes: node.sizes ?? [],
+ packages: (node.packages ?? []) as Array<"6" | "12">,
+ },
+ children: (node.children ?? []).map(mapNode),
+ });
+ return rows.filter((r) => !r.parentId).map(mapNode);
+ }
+ return nestCategories(rows);
+}
diff --git a/src/lib/customers-api.ts b/src/lib/customers-api.ts
new file mode 100644
index 0000000..dbc9bbd
--- /dev/null
+++ b/src/lib/customers-api.ts
@@ -0,0 +1,39 @@
+import { api } from "@/lib/api";
+import type { Customer } from "@/data/customers";
+
+export type ApiCustomer = {
+ id: string;
+ firstName?: string;
+ lastName?: string;
+ name?: string;
+ cellNumber: string;
+ email?: string | null;
+ instagram?: string | null;
+ about?: string | null;
+ avatarUrl?: string | null;
+ disabled?: boolean;
+ createdAt: string;
+};
+
+export function mapCustomer(row: ApiCustomer): Customer {
+ const name =
+ row.name?.trim() ||
+ `${row.firstName ?? ""} ${row.lastName ?? ""}`.trim() ||
+ "بدون نام";
+ const joined = row.createdAt
+ ? new Date(row.createdAt).toISOString().slice(0, 10)
+ : new Date().toISOString().slice(0, 10);
+
+ return {
+ id: row.id,
+ nameFa: name,
+ phone: row.cellNumber,
+ joinedAt: joined,
+ subscription: "regular",
+ };
+}
+
+export async function fetchCustomers() {
+ const rows = await api("/customers");
+ return rows.map(mapCustomer);
+}
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..d712e92
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,35 @@
+import { NextRequest, NextResponse } from "next/server";
+
+const WEBSITE_HOSTS = new Set([
+ "mana-collection.com",
+ "www.mana-collection.com",
+]);
+
+export function middleware(request: NextRequest) {
+ const host = request.headers.get("host")?.split(":")[0]?.toLowerCase() ?? "";
+ if (!WEBSITE_HOSTS.has(host)) {
+ return NextResponse.next();
+ }
+
+ const { pathname } = request.nextUrl;
+ if (
+ pathname.startsWith("/_next") ||
+ pathname.startsWith("/images") ||
+ pathname.startsWith("/fonts") ||
+ pathname === "/favicon.ico"
+ ) {
+ return NextResponse.next();
+ }
+
+ if (pathname === "/coming-soon") {
+ return NextResponse.next();
+ }
+
+ const url = request.nextUrl.clone();
+ url.pathname = "/coming-soon";
+ return NextResponse.redirect(url);
+}
+
+export const config = {
+ matcher: ["/((?!_next/static|_next/image|.*\\.(?:svg|png|jpg|jpeg|gif|webp|woff|woff2|otf|ttf)$).*)"],
+};
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..cf9c65d
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "**/*.mts"
+ ],
+ "exclude": ["node_modules"]
+}