From 32690c293e24736912ab7aab42dbd2ab57d36b36 Mon Sep 17 00:00:00 2001 From: Shawn Date: Fri, 12 Jun 2026 15:30:03 -0400 Subject: [PATCH] feat: comprehensive React SPA replacing Jinja2 UI - New dark UI with 7 tabs: Rig, FX Chain, Models, IRs, Presets, Settings, Record - All screens wired to live API endpoints - Real-time state via WebSocket + polling fallback - Models screen: list/load/unload/upload NAM files + Tone3000 search/install - IRs screen: list/load/unload/upload IR files + Tone3000 search/install - Presets screen: browse banks, activate, save, delete - Settings screen: WiFi scan/connect/hotspot, Bluetooth/MIDI, 4CM routing - Rig screen: live state, volume, bypass, tuner, signal chain - FX Chain screen: block params, per-block bypass - Serves at / instead of /ui - Built with Vite, ~71KB gzipped --- frontend-react/.gitignore | 24 + frontend-react/README.md | 16 + frontend-react/eslint.config.js | 21 + frontend-react/index.html | 13 + frontend-react/package-lock.json | 2427 +++++++++++++++++++++ frontend-react/package.json | 27 + frontend-react/public/favicon.svg | 1 + frontend-react/public/icons.svg | 24 + frontend-react/src/App.jsx | 1564 +++++++++++++ frontend-react/src/index.css | 2 + frontend-react/src/main.jsx | 10 + frontend-react/vite.config.js | 12 + src/web/server.py | 11 +- src/web/ui-dist/assets/index-3XaYhUGn.js | 152 ++ src/web/ui-dist/assets/index-CuJgR-s6.css | 1 + src/web/ui-dist/favicon.svg | 1 + src/web/ui-dist/icons.svg | 24 + src/web/ui-dist/index.html | 14 + 18 files changed, 4342 insertions(+), 2 deletions(-) create mode 100644 frontend-react/.gitignore create mode 100644 frontend-react/README.md create mode 100644 frontend-react/eslint.config.js create mode 100644 frontend-react/index.html create mode 100644 frontend-react/package-lock.json create mode 100644 frontend-react/package.json create mode 100644 frontend-react/public/favicon.svg create mode 100644 frontend-react/public/icons.svg create mode 100644 frontend-react/src/App.jsx create mode 100644 frontend-react/src/index.css create mode 100644 frontend-react/src/main.jsx create mode 100644 frontend-react/vite.config.js create mode 100644 src/web/ui-dist/assets/index-3XaYhUGn.js create mode 100644 src/web/ui-dist/assets/index-CuJgR-s6.css create mode 100644 src/web/ui-dist/favicon.svg create mode 100644 src/web/ui-dist/icons.svg create mode 100644 src/web/ui-dist/index.html diff --git a/frontend-react/.gitignore b/frontend-react/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend-react/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend-react/README.md b/frontend-react/README.md new file mode 100644 index 0000000..a36934d --- /dev/null +++ b/frontend-react/README.md @@ -0,0 +1,16 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/frontend-react/eslint.config.js b/frontend-react/eslint.config.js new file mode 100644 index 0000000..ea36dd3 --- /dev/null +++ b/frontend-react/eslint.config.js @@ -0,0 +1,21 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + globals: globals.browser, + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + }, +]) diff --git a/frontend-react/index.html b/frontend-react/index.html new file mode 100644 index 0000000..5330da2 --- /dev/null +++ b/frontend-react/index.html @@ -0,0 +1,13 @@ + + + + + + + Pi Multi-FX Pedal + + +
+ + + diff --git a/frontend-react/package-lock.json b/frontend-react/package-lock.json new file mode 100644 index 0000000..98d7684 --- /dev/null +++ b/frontend-react/package-lock.json @@ -0,0 +1,2427 @@ +{ + "name": "frontend-react", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend-react", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "vite": "^8.0.12" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-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.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "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.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "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.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/@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.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/@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.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "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/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "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.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "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": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "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/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "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/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/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/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/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/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "dev": true, + "license": "ISC" + }, + "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": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@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", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.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", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "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-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "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-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/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/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/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.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/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": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/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-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/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/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-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/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/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/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/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/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/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "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/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/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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/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/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/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "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/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/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/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/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/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/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/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/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.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "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/frontend-react/package.json b/frontend-react/package.json new file mode 100644 index 0000000..cc8009a --- /dev/null +++ b/frontend-react/package.json @@ -0,0 +1,27 @@ +{ + "name": "frontend-react", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "vite": "^8.0.12" + } +} diff --git a/frontend-react/public/favicon.svg b/frontend-react/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/frontend-react/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend-react/public/icons.svg b/frontend-react/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/frontend-react/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend-react/src/App.jsx b/frontend-react/src/App.jsx new file mode 100644 index 0000000..03b05cf --- /dev/null +++ b/frontend-react/src/App.jsx @@ -0,0 +1,1564 @@ +import { useState, useRef, useEffect, useCallback } from "react"; + +// ── Design tokens ────────────────────────────────────────────── +const T = { + bg: "#0A0A0C", + panel: "#141418", + surface: "#1C1C22", + border: "#2A2A32", + amber: "#E8A030", + amberDim: "#7A5218", + blue: "#3A7BA8", + blueDim: "#1E4060", + green: "#3AB87A", + red: "#C84040", + textPrimary: "#F0EDE6", + textSec: "#8888A0", + textDim: "#444458", +}; + +const API = window.location.origin; +const WS_URL = API.replace(/^http/, 'ws') + '/ws'; + +// ── API helpers ──────────────────────────────────────────────── +async function apiGet(path) { + const r = await fetch(`${API}${path}`); + if (!r.ok) throw new Error(`${path} => ${r.status}`); + return r.json(); +} + +async function apiPost(path, data) { + const r = await fetch(`${API}${path}`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: data != null ? JSON.stringify(data) : undefined, + }); + if (!r.ok) throw new Error(`${path} => ${r.status}`); + return r.json(); +} + +async function apiPut(path, data) { + const r = await fetch(`${API}${path}`, { + method: 'PUT', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + if (!r.ok) throw new Error(`${path} => ${r.status}`); + return r.json(); +} + +async function apiDelete(path) { + const r = await fetch(`${API}${path}`, { method: 'DELETE' }); + if (!r.ok) throw new Error(`${path} => ${r.status}`); + return r.json(); +} + +async function apiUpload(path, file) { + const fd = new FormData(); + fd.append('file', file); + const r = await fetch(`${API}${path}`, { method: 'POST', body: fd }); + if (!r.ok) throw new Error(`${path} => ${r.status}`); + return r.json(); +} + +// ── usePedalState hook ───────────────────────────────────────── +function usePedalState() { + const [state, setState] = useState(null); + const [connected, setConnected] = useState(false); + const wsRef = useRef(null); + const pollRef = useRef(null); + + useEffect(() => { + // Fetch initial state + apiGet('/api/state').then(s => { setState(s); setConnected(true); }).catch(() => { setConnected(false); }); + + // WebSocket for real-time updates + let reconnectTimer; + function connect() { + try { + const ws = new WebSocket(WS_URL); + ws.onmessage = (e) => { + try { + const msg = JSON.parse(e.data); + if (msg.type === 'connected' || msg.type === 'state') { + setState(msg.state); + setConnected(true); + } + if (msg.type === 'preset_changed' && msg.state) setState(msg.state); + if (msg.type === 'bypass_changed') setState(prev => prev ? { ...prev, bypass: msg.bypass } : prev); + if (msg.type === 'tuner_changed') setState(prev => prev ? { ...prev, tuner_enabled: msg.tuner_enabled } : prev); + if (msg.type === 'routing_changed') setState(prev => prev ? { ...prev, routing_mode: msg.routing_mode, routing_breakpoint: msg.routing_breakpoint } : prev); + if (msg.type === 'model_loaded' || msg.type === 'ir_loaded') { + apiGet('/api/state').then(s => setState(s)); + } + } catch (e) { /* ignore parse errors */ } + }; + ws.onclose = () => { + setConnected(false); + reconnectTimer = setTimeout(connect, 3000); + }; + ws.onerror = () => ws.close(); + wsRef.current = ws; + } catch (e) { reconnectTimer = setTimeout(connect, 3000); } + } + connect(); + + // Polling fallback every 5s + pollRef.current = setInterval(() => { + apiGet('/api/state').then(s => { setState(s); setConnected(true); }).catch(() => {}); + }, 5000); + + return () => { + clearInterval(pollRef.current); + clearTimeout(reconnectTimer); + if (wsRef.current) wsRef.current.close(); + }; + }, []); + + const refresh = useCallback(() => { + apiGet('/api/state').then(s => { setState(s); setConnected(true); }).catch(() => {}); + }, []); + + return { state, connected, refresh }; +} + +const css = ` + @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600&display=swap'); + * { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; } + body { background: ${T.bg}; color: ${T.textPrimary}; font-family: 'Inter', sans-serif; user-select: none; } + :root { --amber: ${T.amber}; --blue: ${T.blue}; --green: ${T.green}; } + + .mono { font-family: 'JetBrains Mono', monospace; } + + ::-webkit-scrollbar { width: 4px; height: 4px; } + ::-webkit-scrollbar-track { background: ${T.panel}; } + ::-webkit-scrollbar-thumb { background: ${T.border}; border-radius: 2px; } + + input, textarea, select { font-family: inherit; } + + .knob-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; cursor: pointer; } + .knob { border-radius: 50%; position: relative; touch-action: none; } + .knob-inner { border-radius: 50%; width: 100%; height: 100%; position: relative; + background: radial-gradient(circle at 35% 30%, #3A3A48, #1A1A22); + box-shadow: 0 2px 8px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.07); } + .knob-dot { position: absolute; width: 3px; border-radius: 2px; background: var(--amber); + left: 50%; transform-origin: bottom center; box-shadow: 0 0 6px var(--amber); } + .knob-ring { position: absolute; inset: -5px; border-radius: 50%; } + .knob-label { font-size: 10px; color: ${T.textSec}; letter-spacing: .06em; text-transform: uppercase; text-align: center; } + .knob-value { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: ${T.amber}; } + + .toggle { display: flex; background: ${T.surface}; border-radius: 6px; border: 1px solid ${T.border}; overflow: hidden; } + .toggle-btn { flex: 1; padding: 7px 12px; font-size: 12px; font-weight: 500; letter-spacing: .04em; + background: none; border: none; color: ${T.textSec}; cursor: pointer; transition: all .15s; } + .toggle-btn.active { background: ${T.amber}; color: #000; } + + .vu-bar { display: flex; gap: 2px; align-items: flex-end; height: 100%; } + .vu-seg { width: 4px; border-radius: 1px; transition: opacity .05s; } + + .fader-track { width: 4px; border-radius: 2px; background: ${T.border}; position: relative; cursor: pointer; touch-action: none; } + .fader-fill { width: 100%; border-radius: 2px; position: absolute; bottom: 0; transition: height .05s; } + .fader-thumb { width: 28px; height: 10px; border-radius: 3px; position: absolute; left: 50%; transform: translateX(-50%); + background: linear-gradient(180deg, #3A3A4A, #252530); + border: 1px solid #4A4A5A; box-shadow: 0 2px 4px rgba(0,0,0,.5); + cursor: grab; touch-action: none; } + .fader-thumb::after { content: ''; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); + width: 16px; height: 2px; border-radius: 1px; background: rgba(255,255,255,.15); + box-shadow: 0 3px 0 rgba(255,255,255,.15), 0 -3px 0 rgba(255,255,255,.15); } + + .tabbar { display: flex; background: ${T.panel}; border-bottom: 1px solid ${T.border}; flex-shrink: 0; } + .tab { flex: 1; padding: 10px 4px; font-size: 10px; font-weight: 500; letter-spacing: .04em; + text-align: center; text-transform: uppercase; color: ${T.textDim}; + cursor: pointer; border-bottom: 2px solid transparent; transition: all .15s; } + .tab.active { color: ${T.amber}; border-bottom-color: ${T.amber}; } + + .card { background: ${T.panel}; border: 1px solid ${T.border}; border-radius: 10px; padding: 16px; } + .card-sm { background: ${T.surface}; border: 1px solid ${T.border}; border-radius: 8px; padding: 12px; } + + .btn { padding: 10px 18px; border-radius: 7px; font-size: 13px; font-weight: 600; + letter-spacing: .04em; border: none; cursor: pointer; transition: all .12s; } + .btn-primary { background: ${T.amber}; color: #000; } + .btn-primary:active { filter: brightness(.85); transform: scale(.97); } + .btn-ghost { background: ${T.surface}; color: ${T.textPrimary}; border: 1px solid ${T.border}; } + .btn-ghost:active { background: ${T.border}; } + .btn-danger { background: rgba(200,64,64,.2); color: ${T.red}; border: 1px solid rgba(200,64,64,.3); } + .btn-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; + justify-content: center; background: ${T.surface}; border: 1px solid ${T.border}; cursor: pointer; + font-size: 16px; transition: all .12s; } + .btn-icon:active { transform: scale(.93); } + .btn-icon.active { background: rgba(232,160,48,.15); border-color: ${T.amber}; color: ${T.amber}; } + .btn-sm { padding: 6px 12px; font-size: 12px; } + + .fx-block { background: ${T.panel}; border: 1px solid ${T.border}; border-radius: 10px; + overflow: hidden; transition: border-color .15s; } + .fx-block.active { border-color: ${T.amber}; } + .fx-block.bypassed { opacity: .45; } + .fx-header { display: flex; align-items: center; gap: 10px; padding: 10px 12px; + border-bottom: 1px solid ${T.border}; background: ${T.surface}; cursor: pointer; } + .fx-body { padding: 12px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; } + .bypass-led { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } + .led-on { background: ${T.green}; box-shadow: 0 0 8px ${T.green}; } + .led-off { background: ${T.textDim}; } + + .waveform-wrap { position: relative; overflow: hidden; border-radius: 6px; background: #0F0F14; } + .waveform-canvas { display: block; } + .playhead { position: absolute; top: 0; bottom: 0; width: 1.5px; background: ${T.amber}; + box-shadow: 0 0 8px ${T.amber}; pointer-events: none; transition: left .08s linear; } + + .nam-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; + background: rgba(58,123,168,.15); border: 1px solid rgba(58,123,168,.35); border-radius: 5px; + font-family: 'JetBrains Mono', monospace; font-size: 11px; color: ${T.blue}; } + + .section-label { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; + color: ${T.textDim}; font-weight: 600; margin-bottom: 10px; } + + .preset-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; + border-radius: 8px; cursor: pointer; transition: background .12s; border: 1px solid transparent; } + .preset-row:active, .preset-row.active { background: rgba(232,160,48,.08); border-color: rgba(232,160,48,.25); } + + .transport-btn { width: 44px; height: 44px; border-radius: 50%; display: flex; + align-items: center; justify-content: center; font-size: 16px; cursor: pointer; + border: 2px solid ${T.border}; background: ${T.surface}; transition: all .12s; } + .transport-btn:active { transform: scale(.92); } + .transport-btn.rec { border-color: ${T.red}; background: rgba(200,64,64,.15); } + .transport-btn.play { border-color: ${T.green}; background: rgba(58,184,122,.15); } + + .badge { display: inline-flex; align-items: center; justify-content: center; + padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 700; + letter-spacing: .06em; text-transform: uppercase; } + .badge-amber { background: rgba(232,160,48,.2); color: ${T.amber}; } + .badge-green { background: rgba(58,184,122,.2); color: ${T.green}; } + .badge-blue { background: rgba(58,123,168,.2); color: ${T.blue}; } + .badge-red { background: rgba(200,64,64,.2); color: ${T.red}; } + + .screen-header { padding: 12px 14px 8px; display: flex; align-items: center; + justify-content: space-between; border-bottom: 1px solid ${T.border}; flex-shrink: 0; } + .screen-title { font-size: 13px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: ${T.textSec}; } + + .screen-body { flex: 1; overflow-y: auto; padding: 12px; display: flex; + flex-direction: column; gap: 12px; } + + /* Settings lists */ + .setting-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid ${T.border}; } + .setting-label { font-size: 13px; color: ${T.textPrimary}; } + .setting-desc { font-size: 11px; color: ${T.textDim}; margin-top: 2px; } + .switch { width: 40px; height: 22px; border-radius: 11px; background: ${T.border}; cursor: pointer; position: relative; transition: background .2s; flex-shrink: 0; } + .switch.on { background: ${T.green}; } + .switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: white; transition: transform .15s; } + .switch.on::after { transform: translateX(18px); } + + .search-bar { display: flex; background: ${T.surface}; border-radius: 7px; border: 1px solid ${T.border}; + padding: 8px 12px; gap: 8px; align-items: center; } + .search-bar input { background: none; border: none; outline: none; color: ${T.textPrimary}; font-size: 13px; flex: 1; } + .search-bar input::placeholder { color: ${T.textDim}; } + + .file-drop { border: 2px dashed ${T.border}; border-radius: 8px; padding: 20px; text-align: center; + cursor: pointer; transition: all .15s; font-size: 13px; color: ${T.textDim}; } + .file-drop:hover, .file-drop.dragover { border-color: ${T.amber}; color: ${T.amber}; } + + .loader { width: 20px; height: 20px; border: 2px solid ${T.border}; border-top-color: ${T.amber}; + border-radius: 50%; animation: spin .6s linear infinite; } + @keyframes spin { to { transform: rotate(360deg); } } + + .slide-panel { position: fixed; inset: 0; background: rgba(0,0,0,.7); z-index: 100; + display: flex; align-items: flex-end; justify-content: center; } + .slide-panel-inner { background: ${T.bg}; max-width: 440px; width: 100%; max-height: 85vh; + border-radius: 16px 16px 0 0; overflow: hidden; display: flex; flex-direction: column; } + .slide-panel-handle { width: 36px; height: 4px; border-radius: 2px; background: ${T.border}; + margin: 8px auto; flex-shrink: 0; } +`; + +// ── Knob ────────────────────────────────────────────────────── +function Knob({ label, value = 50, onChange, size = 52, color = T.amber, min = 0, max = 100 }) { + const ref = useRef(null); + const startRef = useRef(null); + const norm = (value - min) / (max - min); + const angle = -140 + norm * 280; + + const handleStart = (e) => { + e.preventDefault(); + const clientY = e.touches ? e.touches[0].clientY : e.clientY; + startRef.current = { y: clientY, val: value }; + const move = (ev) => { + const cy = ev.touches ? ev.touches[0].clientY : ev.clientY; + const delta = (startRef.current.y - cy) / 120; + const next = Math.max(min, Math.min(max, startRef.current.val + delta * (max - min))); + onChange?.(Math.round(next)); + }; + const up = () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); + window.removeEventListener("touchmove", move); window.removeEventListener("touchend", up); }; + window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); + window.addEventListener("touchmove", move, { passive: false }); + window.addEventListener("touchend", up); + }; + + const svgSize = size + 12; + const cx = svgSize / 2, cy = svgSize / 2, r = size / 2 + 3; + const endA = (angle - 90) * (Math.PI / 180); + const ex = cx + r * Math.cos(endA), ey = cy + r * Math.sin(endA); + + return ( +
+
+ + + {norm > 0 && 0.5 ? 1 : 0} 1 ${ex} ${ey}`} + fill="none" stroke={color} strokeWidth="2.5" strokeLinecap="round" + style={{ filter: `drop-shadow(0 0 3px ${color})` }} />} + +
+
+
+
+
{value}
+
{label}
+
+ ); +} + +// ── VU Meter ────────────────────────────────────────────────── +function VUMeter({ level = 0, height = 60, vertical = true }) { + const segs = 12; + const active = Math.round((level / 100) * segs); + const segColor = (i) => { + if (i >= 10) return T.red; + if (i >= 8) return "#E8C030"; + return T.green; + }; + if (vertical) return ( +
+ {Array.from({ length: segs }).map((_, i) => ( +
+ ))} +
+ ); + return ( +
+ {Array.from({ length: segs }).map((_, i) => ( +
+ ))} +
+ ); +} + +// ── Waveform ────────────────────────────────────────────────── +function Waveform({ width, height, color = T.amber, playPos = 0, seed = 1 }) { + const canvasRef = useRef(null); + useEffect(() => { + const c = canvasRef.current; if (!c) return; + const ctx = c.getContext("2d"); + ctx.clearRect(0, 0, width, height); + const mid = height / 2; + ctx.strokeStyle = color; ctx.lineWidth = 1; + ctx.shadowColor = color; ctx.shadowBlur = 2; + ctx.beginPath(); + for (let x = 0; x < width; x++) { + const t = x / width; + const amp = (Math.sin(t * 31 * seed + seed) * 0.4 + Math.sin(t * 97 * seed) * 0.3 + + Math.sin(t * 17 * seed + 2) * 0.2 + Math.random() * 0.1); + const h = Math.abs(amp) * (mid * 0.85); + ctx.moveTo(x, mid - h); ctx.lineTo(x, mid + h); + } + ctx.stroke(); + ctx.globalAlpha = 0.12; + ctx.fillStyle = color; + ctx.beginPath(); ctx.moveTo(0, mid); + for (let x = 0; x < width; x++) { + const t = x / width; + const amp = (Math.sin(t * 31 * seed + seed) * 0.4 + Math.sin(t * 97 * seed) * 0.3 + + Math.sin(t * 17 * seed + 2) * 0.2); + ctx.lineTo(x, mid - Math.abs(amp) * mid * 0.85); + } + ctx.lineTo(width, mid); ctx.closePath(); ctx.fill(); + ctx.globalAlpha = 1; + }, [width, height, color, seed]); + + return ( +
+ +
+
+ ); +} + +// ── Fader ────────────────────────────────────────────────────── +function Fader({ value = 75, onChange, height = 120, label, color = T.amber }) { + const trackRef = useRef(null); + const handleStart = (e) => { + e.preventDefault(); + const move = (ev) => { + const track = trackRef.current.getBoundingClientRect(); + const cy = ev.touches ? ev.touches[0].clientY : ev.clientY; + const pct = 1 - Math.max(0, Math.min(1, (cy - track.top) / track.height)); + onChange?.(Math.round(pct * 100)); + }; + const up = () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); + window.removeEventListener("touchmove", move); window.removeEventListener("touchend", up); }; + window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); + window.addEventListener("touchmove", move, { passive: false }); + window.addEventListener("touchend", up); + }; + const thumbBottom = (value / 100) * (height - 10); + + return ( +
+
+
+
+
+
+
+
{value}
+
{label}
+
+ ); +} + +// ── FX Block ────────────────────────────────────────────────── +function FXBlock({ title, type, active = true, bypassed = false, params = [], onToggle }) { + const [open, setOpen] = useState(true); + const [vals, setVals] = useState(params.map(p => p.default ?? p.default ?? 50)); + return ( +
+
setOpen(o => !o)}> +
{ e.stopPropagation(); onToggle?.(); }} /> + {title} + {type} + {open ? "▾" : "▸"} +
+ {open && ( +
+ {params.map((p, i) => ( + setVals(prev => prev.map((x, j) => j === i ? v : x))} + min={p.min ?? 0} max={p.max ?? 100} /> + ))} +
+ )} +
+ ); +} + +// ── Slide Panel ────────────────────────────────────────────── +function SlidePanel({ children, onClose }) { + return ( +
+
e.stopPropagation()}> +
+ {children} +
+
+ ); +} + +// ══════════════════════════════════════════════════════════════ +// SCREENS +// ══════════════════════════════════════════════════════════════ + +// 1. RIG SCREEN ──────────────────────────────────────────────── +function RigScreen({ state, connected }) { + const [volume, setVolume] = useState(state?.master_volume != null ? Math.round(state.master_volume * 100) : 80); + const [vuL, setVuL] = useState(45); + const [vuR, setVuR] = useState(42); + const [saving, setSaving] = useState(false); + + useEffect(() => { + if (state?.master_volume != null) setVolume(Math.round(state.master_volume * 100)); + }, [state?.master_volume]); + + // Animated VU + useEffect(() => { + const id = setInterval(() => { + setVuL(prev => Math.max(10, Math.min(95, prev + (Math.random() - 0.48) * 12))); + setVuR(prev => Math.max(10, Math.min(95, prev + (Math.random() - 0.48) * 12))); + }, 90); + return () => clearInterval(id); + }, []); + + const handleVolume = async (val) => { + setVolume(val); + try { + await apiPut('/api/volume', { volume: val / 100 }); + } catch (e) { /* ignore */ } + }; + + const handleBypass = async () => { + try { + await apiPost('/api/bypass'); + } catch (e) { /* ignore */ } + }; + + const handleTuner = async () => { + try { + const current = state?.tuner_enabled; + await apiPost('/api/tuner', { enabled: !current }); + } catch (e) { /* ignore */ } + }; + + return ( +
+
+
+
Active Rig
+
+ {state?.current_preset ? ( + + {state.current_preset.name} + + ) : ( + No preset loaded + )} + {connected ? ( + Connected + ) : ( + Offline + )} +
+
+
+ + +
+
+
+ {/* Status row */} +
+
+
Bypass
+
+
+
+
Tuner
+
+
+
+
Routing
+ {state?.routing_mode || "mono"} +
+
+ + {/* Volume */} +
+
+
Master Volume
+ handleVolume(+e.target.value)} + style={{ width: "100%", accentColor: T.amber }} /> +
+ {volume}% +
+
+
+ {state?.nam_loaded ? "NAM: Active" : "NAM: —"} +
+ {state?.ir_loaded ? "IR: Active" : "IR: —"} +
+
+ + {/* Signal chain */} +
+
Signal Chain
+
+ {["IN", state?.bypass ? "BYP" : (state?.nam_loaded ? "NAM" : "AMP"), state?.ir_loaded ? "IR" : "CAB", "OUT"].map((s, i, arr) => ( +
+
{s}
+ {i < arr.length - 1 &&
} +
+ ))} +
+
+ + {/* NAM + IR info */} +
+
+
NAM Model
+ {state?.nam_model ? ( +
{state.nam_model}
+ ) : ( +
Not loaded
+ )} +
+
+
IR
+ {state?.ir_name ? ( +
{state.ir_name}
+ ) : ( +
Not loaded
+ )} +
+
+
+
+ ); +} + +// 2. FX CHAIN SCREEN ─────────────────────────────────────────── +function FXScreen({ state, connected }) { + const [fxList, setFxList] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // In standalone mode (no pedal connected), show demo chain + if (!connected || !state?.current_preset) { + setFxList([ + { id: 1, title: "Overdrive", type: "OD", bypassed: false, params: [{ key: "drive", name: "Drive", default: 62 }, { key: "tone", name: "Tone", default: 55 }] }, + { id: 2, title: "Compressor", type: "COMP", bypassed: false, params: [{ key: "thresh", name: "Thresh", default: 40 }, { key: "ratio", name: "Ratio", default: 40 }] }, + { id: 3, title: "NAM Amp", type: "AMP", bypassed: false, params: [] }, + { id: 4, title: "Delay", type: "DELAY", bypassed: true, params: [{ key: "time", name: "Time", default: 45 }, { key: "feedback", name: "Fdbk", default: 38 }] }, + ]); + setLoading(false); + return; + } + + // Try to load from API + apiGet('/api/presets').then(data => { + const banks = data.banks || []; + if (banks.length > 0 && banks[0].presets) { + const current = banks[0].presets.find(p => p != null); + if (current?.chain) { + setFxList(current.chain.map((b, i) => ({ + id: i + 1, + title: b.fx_type.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()), + type: b.fx_type.toUpperCase(), + bypassed: b.bypass || !b.enabled, + params: [], // would load from /api/block-params + }))); + } + } + setLoading(false); + }).catch(() => { + setLoading(false); + }); + }, [connected, state]); + + const toggle = (id) => setFxList(prev => prev ? prev.map(f => f.id === id ? { ...f, bypassed: !f.bypassed } : f) : prev); + + if (loading) return
; + + return ( +
+
+
FX Chain
+ +
+
+ {/* Signal path */} +
+ {["IN", ...(fxList || []).map(f => f.type), "OUT"].map((s, i, arr) => ( +
+
{s}
+ {i < arr.length - 1 &&
} +
+ ))} +
+ {(fxList || []).map(f => ( + toggle(f.id)} /> + ))} +
+
+ ); +} + +// 3. MODELS SCREEN ───────────────────────────────────────────── +function ModelsScreen({ state, connected, refresh }) { + const [models, setModels] = useState([]); + const [current, setCurrent] = useState(null); + const [loading, setLoading] = useState(true); + const [searching, setSearching] = useState(false); + const [searchQ, setSearchQ] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [showSearch, setShowSearch] = useState(false); + const [uploading, setUploading] = useState(false); + const fileRef = useRef(null); + + const loadModels = useCallback(async () => { + if (!connected) { setLoading(false); return; } + try { + const data = await apiGet('/api/models'); + setModels(data.models || []); + setCurrent(data.current); + } catch (e) { /* ignore */ } + setLoading(false); + }, [connected]); + + useEffect(() => { loadModels(); }, [loadModels]); + + const handleLoad = async (path) => { + try { await apiPost('/api/models/load', { path }); await loadModels(); refresh(); } catch (e) { alert('Failed to load model'); } + }; + + const handleUnload = async () => { + try { await apiPost('/api/models/unload'); setCurrent(null); await loadModels(); refresh(); } catch (e) { alert('Failed to unload'); } + }; + + const handleUpload = async (e) => { + const file = e.target.files?.[0]; + if (!file) return; + setUploading(true); + try { + await apiUpload('/api/models/upload', file); + await loadModels(); + } catch (err) { alert('Upload failed'); } + setUploading(false); + }; + + const handleSearch = useCallback(async () => { + if (!searchQ.trim()) return; + setSearching(true); + try { + const data = await apiGet(`/api/models/tonedownload/search?q=${encodeURIComponent(searchQ)}`); + setSearchResults(data.results || []); + } catch (e) { alert('Search failed'); } + setSearching(false); + }, [searchQ]); + + const handleInstall = async (result) => { + try { + await apiPost('/api/models/tonedownload/install', { + download_url: result.download_url, + name: result.name || result.filename, + id: result.id, + size: result.size, + pack_name: result.pack_name, + display_name: result.name, + }); + await loadModels(); + refresh(); + } catch (e) { alert('Install failed'); } + }; + + if (loading) return
; + + return ( +
+
+
NAM Models ({models.length})
+
+ + + +
+
+ + {showSearch && ( +
+
+ 🔍 + setSearchQ(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()} /> + +
+ {searchResults.length > 0 && ( +
+ {searchResults.map(r => ( +
handleInstall(r)} style={{ borderBottom: `1px solid ${T.border}`, borderRadius: 0 }}> +
+
{r.name}
+
{r.author} · {r.size_display} · {r.architecture}
+
+ +
+ ))} +
+ )} +
+ )} + +
+ {current && ( +
+
Loaded Model
+
+
{current}
+ +
+
+ )} + + {models.length === 0 ? ( +
+ No NAM models found.
Upload a .nam file or search Tone3000. +
+ ) : ( + models.map(m => ( +
+
+
{m.name}
+
{m.architecture} · {m.size_mb} MB
+
+ {m.loaded ? ( + Loaded + ) : ( + + )} +
+ )) + )} +
+
+ ); +} + +// 4. IRS SCREEN ──────────────────────────────────────────────── +function IRsScreen({ state, connected, refresh }) { + const [irs, setIrs] = useState([]); + const [current, setCurrent] = useState(null); + const [loading, setLoading] = useState(true); + const [searching, setSearching] = useState(false); + const [searchQ, setSearchQ] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [showSearch, setShowSearch] = useState(false); + const [uploading, setUploading] = useState(false); + const fileRef = useRef(null); + + const loadIrs = useCallback(async () => { + if (!connected) { setLoading(false); return; } + try { + const data = await apiGet('/api/irs'); + setIrs(data.irs || []); + setCurrent(data.current); + } catch (e) { /* ignore */ } + setLoading(false); + }, [connected]); + + useEffect(() => { loadIrs(); }, [loadIrs]); + + const handleLoad = async (path) => { + try { await apiPost('/api/irs/load', { path }); await loadIrs(); refresh(); } catch (e) { alert('Failed to load IR'); } + }; + + const handleUnload = async () => { + try { await apiPost('/api/irs/unload'); setCurrent(null); await loadIrs(); refresh(); } catch (e) { alert('Failed to unload'); } + }; + + const handleUpload = async (e) => { + const file = e.target.files?.[0]; + if (!file) return; + setUploading(true); + try { + await apiUpload('/api/irs/upload', file); + await loadIrs(); + } catch (err) { alert('Upload failed'); } + setUploading(false); + }; + + const handleSearch = useCallback(async () => { + if (!searchQ.trim()) return; + setSearching(true); + try { + const data = await apiGet(`/api/irs/tonedownload/search?q=${encodeURIComponent(searchQ)}`); + setSearchResults(data.results || []); + } catch (e) { alert('Search failed'); } + setSearching(false); + }, [searchQ]); + + const handleInstall = async (result) => { + try { + await apiPost('/api/irs/tonedownload/install', { + download_url: result.download_url, + name: result.name || result.filename, + id: result.id, + size: result.size, + display_name: result.name, + }); + await loadIrs(); + refresh(); + } catch (e) { alert('Install failed'); } + }; + + if (loading) return
; + + return ( +
+
+
IR Files ({irs.length})
+
+ + + +
+
+ + {showSearch && ( +
+
+ 🔍 + setSearchQ(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()} /> + +
+ {searchResults.length > 0 && ( +
+ {searchResults.map(r => ( +
handleInstall(r)} style={{ borderBottom: `1px solid ${T.border}`, borderRadius: 0 }}> +
+
{r.name}
+
{r.author} · {r.size_display}
+
+ +
+ ))} +
+ )} +
+ )} + +
+ {current && ( +
+
Loaded IR
+
+
{current}
+ +
+
+ )} + + {irs.length === 0 ? ( +
+ No IR files found.
Upload a .wav file or search Tone3000. +
+ ) : ( + irs.map(ir => ( +
+
+
{ir.name}
+
{ir.sample_rate} Hz · {ir.length_ms} ms · {ir.num_taps} taps
+
+ {ir.loaded ? ( + Loaded + ) : ( + + )} +
+ )) + )} +
+
+ ); +} + +// 5. PRESETS SCREEN ──────────────────────────────────────────── +function PresetsScreen({ state, connected, refresh }) { + const [banks, setBanks] = useState([]); + const [selectedBank, setSelectedBank] = useState(0); + const [loading, setLoading] = useState(true); + const [saveName, setSaveName] = useState(''); + const [showSave, setShowSave] = useState(false); + const [deleting, setDeleting] = useState(null); + + const loadPresets = useCallback(async () => { + if (!connected) { + setBanks([{ name: "Default", number: 0, presets: [ + { name: "Edge of Breakup", bank: 0, program: 0 }, + { name: "Modern High Gain", bank: 0, program: 1 }, + null, null, + ]}]); + setLoading(false); + return; + } + try { + const data = await apiGet('/api/presets'); + setBanks(data.banks || []); + } catch (e) { /* ignore */ } + setLoading(false); + }, [connected]); + + useEffect(() => { loadPresets(); }, [loadPresets]); + + const handleActivate = async (bank, program) => { + try { + await apiPost(`/api/presets/${bank}/${program}/activate`); + await loadPresets(); + refresh(); + } catch (e) { alert('Failed to load preset'); } + }; + + const handleSave = async () => { + if (!saveName.trim()) return; + const currentBank = state?.current_preset?.bank ?? 0; + const currentProgram = state?.current_preset?.program ?? 0; + try { + await apiPut(`/api/presets/${currentBank}/${currentProgram}`, { name: saveName }); + setShowSave(false); + await loadPresets(); + } catch (e) { alert('Failed to save'); } + }; + + const handleDelete = async (bank, program) => { + try { + await apiDelete(`/api/presets/${bank}/${program}`); + setDeleting(null); + await loadPresets(); + } catch (e) { alert('Failed to delete'); } + }; + + if (loading) return
; + + const currentPreset = state?.current_preset; + const bankData = banks[selectedBank]; + const presets = bankData?.presets || []; + + return ( +
+
+
Presets
+
+ +
+
+ +
+ {/* Bank selector */} + {banks.length > 1 && ( +
+ {banks.map((b, i) => ( + + ))} +
+ )} + + {/* Current preset indicator */} + {currentPreset && ( +
+
+
Current
+
+ {currentPreset.name} + + Bank {currentPreset.bank} · Prog {currentPreset.program} + +
+
+
+ )} + + {/* Preset list */} + {presets.length === 0 ? ( +
No presets in this bank.
+ ) : ( + presets.map((p, i) => { + if (!p) return null; + const isActive = currentPreset?.bank === p.bank && currentPreset?.program === p.program; + const isDeleting = deleting === `${p.bank}-${p.program}`; + return ( +
!isDeleting && handleActivate(p.bank, p.program)}> +
{p.program + 1}
+
+
{p.name}
+
Bank {p.bank} · Program {p.program}
+
+ {isActive && } + {isDeleting ? ( +
+ + +
+ ) : ( + + )} +
+ ); + }) + )} +
+ + {/* Save dialog */} + {showSave && ( + setShowSave(false)}> +
+
Save Preset
+
+
+
+ setSaveName(e.target.value)} autoFocus + onKeyDown={e => e.key === 'Enter' && handleSave()} /> +
+
+ + +
+
+
+ )} +
+ ); +} + +// 6. SETTINGS SCREEN ─────────────────────────────────────────── +function SettingsScreen({ state, connected, refresh }) { + const [tab, setTab] = useState('wifi'); + const [wifiNetworks, setWifiNetworks] = useState([]); + const [btDevices, setBtDevices] = useState([]); + const [btPaired, setBtPaired] = useState([]); + const [wifiScanning, setWifiScanning] = useState(false); + const [btScanning, setBtScanning] = useState(false); + const [connectSsid, setConnectSsid] = useState(''); + const [connectPw, setConnectPw] = useState(''); + const [showConnect, setShowConnect] = useState(null); + const [routingMode, setRoutingMode] = useState(state?.routing_mode || 'mono'); + const [routingBp, setRoutingBp] = useState(state?.routing_breakpoint || 7); + + useEffect(() => { + if (state?.routing_mode) setRoutingMode(state.routing_mode); + if (state?.routing_breakpoint != null) setRoutingBp(state.routing_breakpoint); + }, [state?.routing_mode, state?.routing_breakpoint]); + + const scanWifi = async () => { + setWifiScanning(true); + try { + const data = await apiGet('/api/wifi/scan'); + setWifiNetworks(data.networks || []); + } catch (e) { /* ignore */ } + setWifiScanning(false); + }; + + const connectWifi = async (ssid, password) => { + try { + await apiPost('/api/wifi/connect', { ssid, password }); + setShowConnect(null); + setConnectSsid(''); + setConnectPw(''); + setTimeout(refresh, 2000); + } catch (e) { alert('Failed to connect'); } + }; + + const disconnectWifi = async () => { + try { await apiPost('/api/wifi/disconnect'); setTimeout(refresh, 2000); } catch (e) { /* ignore */ } + }; + + const toggleHotspot = async () => { + const active = state?.wifi?.hotspot_active; + try { + if (active) await apiPost('/api/wifi/hotspot/disable'); + else await apiPost('/api/wifi/hotspot/enable', { ssid: 'Pi-Pedal', password: 'pedal1234' }); + setTimeout(refresh, 2000); + } catch (e) { /* ignore */ } + }; + + const handleBtPower = async (on) => { + try { await apiPost('/api/bluetooth/power', { on }); setTimeout(refresh, 1000); } catch (e) { /* ignore */ } + }; + + const scanBt = async () => { + setBtScanning(true); + try { + const data = await apiPost('/api/bluetooth/scan'); + setBtDevices(data.devices || []); + } catch (e) { /* ignore */ } + setBtScanning(false); + }; + + const loadBtPaired = async () => { + try { + const data = await apiGet('/api/bluetooth/paired'); + setBtPaired(data.devices || []); + } catch (e) { /* ignore */ } + }; + + const pairBt = async (addr) => { + try { await apiPost('/api/bluetooth/pair', { address: addr }); await loadBtPaired(); } catch (e) { alert('Pairing failed'); } + }; + + const handleRouting = async (mode, bp) => { + try { await apiPost('/api/routing', { routing_mode: mode, routing_breakpoint: bp }); } catch (e) { /* ignore */ } + }; + + useEffect(() => { if (connected) { scanWifi(); loadBtPaired(); } }, [connected]); + + const wifiState = state?.wifi; + const btState = state?.bluetooth; + + return ( +
+
+
Settings
+
+ + {/* Settings tabs */} +
+ {[{ id: 'wifi', label: 'WiFi' }, { id: 'bt', label: 'Bluetooth' }, { id: 'routing', label: 'Routing' }].map(t => ( + + ))} +
+ +
+ {/* ── WiFi Tab ─────────────────────────────────────────────*/} + {tab === 'wifi' && ( + <> + {/* WiFi Status */} +
+
+
+
WiFi
+
{wifiState?.connected ? `Connected to ${wifiState.ssid}` : 'Disconnected'}
+
+
+
+ {wifiState?.connected && ( +
+ IP: {wifiState.ip} · Signal: {wifiState.signal}% +
+ )} + + {/* Hotspot */} +
+
+
Hotspot
+
{wifiState?.hotspot_active ? `Active: ${wifiState.hotspot_ssid}` : 'Off'}
+
+
+
+
+ + {/* Scan networks */} +
+
+
Networks
+ +
+ {wifiNetworks.length === 0 ? ( +
Scan to see available networks.
+ ) : ( + wifiNetworks.map(n => ( +
wpaState?.ssid !== n.ssid && setShowConnect(n.ssid)}> +
+
{n.ssid}
+
Signal: {n.signal}% · {n.encryption || 'Open'}
+
+ {wifiState?.ssid === n.ssid && Connected} +
+ )) + )} +
+ + {/* Connect dialog */} + {showConnect && ( +
+
Connect to {showConnect}
+
+ setConnectPw(e.target.value)} + style={{ background: T.surface, border: `1px solid ${T.border}`, borderRadius: 6, padding: "8px 12px", color: T.textPrimary, fontSize: 13, outline: "none" }} + onKeyDown={e => e.key === 'Enter' && connectWifi(showConnect, connectPw)} /> +
+ + +
+
+
+ )} + + )} + + {/* ── Bluetooth Tab ─────────────────────────────────────────*/} + {tab === 'bt' && ( + <> +
+
+
+
Bluetooth
+
{btState?.powered ? 'Powered on' : 'Off'}
+
+
handleBtPower(!btState?.powered)} /> +
+ {btState?.powered && ( + <> +
+
+
Discoverable
+
{btState?.name} ({btState?.address})
+
+
{ try { await apiPost('/api/bluetooth/discoverable', { on: !btState?.discoverable }); setTimeout(refresh, 500); } catch(e) {} }} /> +
+
+
+
Bluetooth MIDI
+
{btState?.midi_enabled ? 'Enabled' : 'Disabled'}
+
+
{ try { await (btState?.midi_enabled ? apiPost('/api/bluetooth/midi-disable') : apiPost('/api/bluetooth/midi-enable')); setTimeout(refresh, 500); } catch(e) {} }} /> +
+ + )} +
+ + {btState?.powered && ( +
+
+
Paired Devices ({btPaired.length})
+ +
+ {btPaired.length === 0 ? ( +
No paired devices.
+ ) : ( + btPaired.map(d => ( +
+
+
{d.name || d.address}
+
{d.address} · {d.connected ? 'Connected' : 'Paired'}
+
+ {!d.connected && ( + + )} +
+ )) + )} +
+ )} + + {btScanning && btDevices.length > 0 && ( +
+
Discovered
+ {btDevices.map(d => ( +
+
+
{d.name || d.address}
+
{d.address}
+
+ +
+ ))} +
+ )} + + )} + + {/* ── Routing Tab ───────────────────────────────────────────*/} + {tab === 'routing' && ( +
+
4CM Routing
+
+
+
Mode
+
Mono (normal) or 4CM (4-cable method)
+
+ +
+ {routingMode === '4cm' && ( +
+
+
Breakpoint
+
Chain position for amp send/return
+
+ { const v = +e.target.value; setRoutingBp(v); handleRouting(routingMode, v); }} + style={{ background: T.surface, border: `1px solid ${T.border}`, borderRadius: 6, padding: "6px 10px", color: T.textPrimary, fontSize: 13, width: 60, outline: "none", textAlign: "center" }} /> +
+ )} +
+ )} +
+
+ ); +} + +// 7. RECORD SCREEN ───────────────────────────────────────────── +function RecordScreen() { + const [playing, setPlaying] = useState(false); + const [recording, setRecording] = useState(false); + const [playPos, setPlayPos] = useState(0); + const [tracks, setTracks] = useState([ + { name: "Guitar 1", color: T.amber, vol: 80, pan: 50, mute: false, solo: false, level: 72 }, + { name: "Guitar 2", color: T.blue, vol: 65, pan: 35, mute: false, solo: false, level: 55 }, + { name: "Bass DI", color: T.green, vol: 75, pan: 50, mute: true, solo: false, level: 68 }, + { name: "Drum Loop", color: "#A060E0", vol: 70, pan: 52, mute: false, solo: false, level: 60 }, + ]); + + useEffect(() => { + let id; + if (playing) id = setInterval(() => setPlayPos(p => p >= 100 ? 0 : p + 0.3), 80); + return () => clearInterval(id); + }, [playing]); + + useEffect(() => { + const id = setInterval(() => { + setTracks(prev => prev.map(t => ({ + ...t, level: t.mute ? 0 : Math.max(10, Math.min(95, t.level + (Math.random() - 0.48) * 12)) + }))); + }, 90); + return () => clearInterval(id); + }, []); + + const toggleMute = (i) => setTracks(p => p.map((t, j) => j === i ? { ...t, mute: !t.mute } : t)); + const toggleSolo = (i) => setTracks(p => p.map((t, j) => j === i ? { ...t, solo: !t.solo } : t)); + const setVol = (i, v) => setTracks(p => p.map((t, j) => j === i ? { ...t, vol: v } : t)); + + return ( +
+
+
+
Multitrack
+
+ {Math.floor(playPos / 100 * 32).toString().padStart(2,"0")}: + {Math.floor(((playPos / 100 * 32) % 1) * 60).toString().padStart(2,"0")} +
+
+
+
setPlayPos(0)}>⏮
+
{ setRecording(r => !r); if (!recording) setPlaying(true); }}> +
+
+
setPlaying(p => !p)}> + {playing ? "⏸" : "▶"} +
+
+
+ +
+ {tracks.map((t, i) => ( +
+
+
+
{t.name}
+
+
toggleMute(i)} style={{ padding: "1px 4px", borderRadius: 3, fontSize: 9, + fontWeight: 700, cursor: "pointer", + background: t.mute ? `${T.red}33` : T.surface, + color: t.mute ? T.red : T.textDim, border: `1px solid ${t.mute ? T.red+"60" : T.border}` }}>M
+
toggleSolo(i)} style={{ padding: "1px 4px", borderRadius: 3, fontSize: 9, + fontWeight: 700, cursor: "pointer", + background: t.solo ? `${T.amber}33` : T.surface, + color: t.solo ? T.amber : T.textDim, border: `1px solid ${t.solo ? T.amber+"60" : T.border}` }}>S
+
+
+
+ +
+
+ + setVol(i, +e.target.value)} + style={{ writingMode: "vertical-lr", direction: "rtl", height: 40, width: 20, + accentColor: t.color, cursor: "pointer" }} /> +
+
+ ))} +
+ +
+
MASTER
+
+ +
+
-4.2 dBFS
+ +
+
+ ); +} + +// ══════════════════════════════════════════════════════════════ +// APP SHELL +// ══════════════════════════════════════════════════════════════ + +const TABS = [ + { id: "rig", label: "Rig", icon: "🎛" }, + { id: "fx", label: "FX Chain", icon: "⛓" }, + { id: "models", label: "Models", icon: "📁" }, + { id: "irs", label: "IRs", icon: "🎚" }, + { id: "presets", label: "Presets", icon: "⭐" }, + { id: "settings", label: "Settings", icon: "⚙" }, + { id: "record", label: "Record", icon: "🎙" }, +]; + +export default function App() { + const [tab, setTab] = useState("rig"); + const { state, connected, refresh } = usePedalState(); + + useEffect(() => { document.title = "Pi Multi-FX Pedal"; }, []); + + return ( + <> + +
+ + {/* Status bar */} +
+
+
+ PI MULTI-FX +
+
+ {state?.bypass && BYP} + {state?.tuner_enabled && TUNER} + {state?.nam_loaded && NAM} + {state?.ir_loaded && IR} +
+
+ + {/* Screen */} +
+ {tab === "rig" && } + {tab === "fx" && } + {tab === "models" && } + {tab === "irs" && } + {tab === "presets" && } + {tab === "settings" && } + {tab === "record" && } +
+ + {/* Tab bar */} +
+ {TABS.map(t => ( +
setTab(t.id)}> + {t.icon} + {t.label} +
+ ))} +
+
+ + ); +} diff --git a/frontend-react/src/index.css b/frontend-react/src/index.css new file mode 100644 index 0000000..4e1b41b --- /dev/null +++ b/frontend-react/src/index.css @@ -0,0 +1,2 @@ +* { margin: 0; padding: 0; box-sizing: border-box; } +body { background: #0A0A0C; color: #F0EDE6; } diff --git a/frontend-react/src/main.jsx b/frontend-react/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/frontend-react/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/frontend-react/vite.config.js b/frontend-react/vite.config.js new file mode 100644 index 0000000..5e8d157 --- /dev/null +++ b/frontend-react/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], + base: '/ui/', + build: { + outDir: '../src/web/ui-dist', + emptyOutDir: true, + }, +}) diff --git a/src/web/server.py b/src/web/server.py index ae981a2..c53c7c7 100644 --- a/src/web/server.py +++ b/src/web/server.py @@ -168,8 +168,15 @@ class WebServer: # ── HTML pages ────────────────────────────────────────────── @app.get("/", response_class=HTMLResponse) - async def dashboard(request: Request): - """Main dashboard — current preset, bypass, tuner, volume.""" + async def root(request: Request): + """Serve the React SPA (or legacy dashboard as fallback).""" + # If we have a React build, serve it at / + if UI_DIST_DIR and UI_DIST_DIR.is_dir(): + index_html = UI_DIST_DIR / "index.html" + if index_html.exists(): + content = index_html.read_text() + return HTMLResponse(content) + # Fallback: legacy dashboard state = self._gather_state() ctx = {"request": request} ctx.update(state) diff --git a/src/web/ui-dist/assets/index-3XaYhUGn.js b/src/web/ui-dist/assets/index-3XaYhUGn.js new file mode 100644 index 0000000..5f5db71 --- /dev/null +++ b/src/web/ui-dist/assets/index-3XaYhUGn.js @@ -0,0 +1,152 @@ +var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var t=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},ee=Object.prototype.hasOwnProperty;function T(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function te(e,t){return T(e.type,t,e.props)}function E(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ne(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var re=/\/+/g;function ie(e,t){return typeof e==`object`&&e&&e.key!=null?ne(``+e.key):t.toString(36)}function ae(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function oe(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,oe(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+ie(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(re,`$&/`)+`/`),oe(o,r,i,``,function(e){return e})):o!=null&&(E(o)&&(o=te(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(re,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{n.exports=t()})),r=e((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,E());else{var t=n(l);t!==null&&ie(x,t.startTime-e)}}var S=!1,C=-1,w=5,ee=-1;function T(){return g?!0:!(e.unstable_now()-eet&&T());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&ie(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?E():S=!1}}}var E;if(typeof y==`function`)E=function(){y(te)};else if(typeof MessageChannel<`u`){var ne=new MessageChannel,re=ne.port2;ne.port1.onmessage=te,E=function(){re.postMessage(null)}}else E=function(){_(te,0)};function ie(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,ie(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,E()))),r},e.unstable_shouldYield=T,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),i=e(((e,t)=>{t.exports=r()})),a=e((e=>{var t=n();function r(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=a()})),s=e((e=>{var t=i(),r=n(),a=o();function s(e){var t=`https://react.dev/errors/`+e;if(1de||(e.current=ue[de],ue[de]=null,de--)}function A(e,t){de++,ue[de]=e.current,e.current=t}var pe=fe(null),me=fe(null),he=fe(null),ge=fe(null);function _e(e,t){switch(A(he,t),A(me,e),A(pe,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}k(pe),A(pe,e)}function ve(){k(pe),k(me),k(he)}function ye(e){e.memoizedState!==null&&A(ge,e);var t=pe.current,n=Hd(t,e.type);t!==n&&(A(me,e),A(pe,n))}function be(e){me.current===e&&(k(pe),k(me)),ge.current===e&&(k(ge),Qf._currentValue=le)}var xe,Se;function Ce(e){if(xe===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);xe=t&&t[1]||``,Se=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{we=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Ce(n):``}function Ee(e,t){switch(e.tag){case 26:case 27:case 5:return Ce(e.type);case 16:return Ce(`Lazy`);case 13:return e.child!==t&&t!==null?Ce(`Suspense Fallback`):Ce(`Suspense`);case 19:return Ce(`SuspenseList`);case 0:case 15:return Te(e.type,!1);case 11:return Te(e.type.render,!1);case 1:return Te(e.type,!0);case 31:return Ce(`Activity`);default:return``}}function De(e){try{var t=``,n=null;do t+=Ee(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Oe=Object.prototype.hasOwnProperty,ke=t.unstable_scheduleCallback,Ae=t.unstable_cancelCallback,je=t.unstable_shouldYield,Me=t.unstable_requestPaint,Ne=t.unstable_now,Pe=t.unstable_getCurrentPriorityLevel,Fe=t.unstable_ImmediatePriority,Ie=t.unstable_UserBlockingPriority,Le=t.unstable_NormalPriority,Re=t.unstable_LowPriority,ze=t.unstable_IdlePriority,Be=t.log,Ve=t.unstable_setDisableYieldValue,He=null,Ue=null;function We(e){if(typeof Be==`function`&&Ve(e),Ue&&typeof Ue.setStrictMode==`function`)try{Ue.setStrictMode(He,e)}catch{}}var Ge=Math.clz32?Math.clz32:Je,Ke=Math.log,qe=Math.LN2;function Je(e){return e>>>=0,e===0?32:31-(Ke(e)/qe|0)|0}var Ye=256,Xe=262144,Ze=4194304;function Qe(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function $e(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Qe(n))):i=Qe(o):i=Qe(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Qe(n))):i=Qe(o)):i=Qe(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function et(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function tt(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function nt(){var e=Ze;return Ze<<=1,!(Ze&62914560)&&(Ze=4194304),e}function rt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function it(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function at(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),vn=!1;if(_n)try{var yn={};Object.defineProperty(yn,"passive",{get:function(){vn=!0}}),window.addEventListener(`test`,yn,yn),window.removeEventListener(`test`,yn,yn)}catch{vn=!1}var bn=null,xn=null,Sn=null;function Cn(){if(Sn)return Sn;var e,t=xn,n=t.length,r,i=`value`in bn?bn.value:bn.textContent,a=i.length;for(e=0;e=tr),ir=` `,ar=!1;function or(e,t){switch(e){case`keyup`:return $n.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function sr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var cr=!1;function lr(e,t){switch(e){case`compositionend`:return sr(t);case`keypress`:return t.which===32?(ar=!0,ir):null;case`textInput`:return e=t.data,e===ir&&ar?null:e;default:return null}}function ur(e,t){if(cr)return e===`compositionend`||!er&&or(e,t)?(e=Cn(),Sn=xn=bn=null,cr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Mr(n)}}function Pr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Pr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Fr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Wt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Wt(e.document)}return t}function Ir(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Lr=_n&&`documentMode`in document&&11>=document.documentMode,Rr=null,zr=null,Br=null,Vr=!1;function Hr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Vr||Rr==null||Rr!==Wt(r)||(r=Rr,`selectionStart`in r&&Ir(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Br&&jr(Br,r)||(Br=r,r=Ed(zr,`onSelect`),0>=o,i-=o,Pi=1<<32-Ge(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),o=a(_,o,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),M&&Ii(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(i,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(i,h),o=a(y,o,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(i,h),M&&Ii(i,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(i,v.value,l),v!==null&&(o=a(v,o,g),d===null?u=v:d.sibling=v,d=v);return M&&Ii(i,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,i,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),o=a(v,o,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(i,e)}),M&&Ii(i,g),u}function b(e,r,a,c){if(typeof a==`object`&&a&&a.type===y&&a.key===null&&(a=a.props.children),typeof a==`object`&&a){switch(a.$$typeof){case _:a:{for(var l=a.key;r!==null;){if(r.key===l){if(l=a.type,l===y){if(r.tag===7){n(e,r.sibling),c=i(r,a.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===E&&Pa(l)===r.type){n(e,r.sibling),c=i(r,a.props),Va(c,a),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}a.type===y?(c=xi(a.props.children,e.mode,c,a.key),c.return=e,e=c):(c=bi(a.type,a.key,a.props,null,e.mode,c),Va(c,a),c.return=e,e=c)}return o(e);case v:a:{for(l=a.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){n(e,r.sibling),c=i(r,a.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=wi(a,e.mode,c),c.return=e,e=c}return o(e);case E:return a=Pa(a),b(e,r,a,c)}if(ce(a))return h(e,r,a,c);if(ae(a)){if(l=ae(a),typeof l!=`function`)throw Error(s(150));return a=l.call(a),g(e,r,a,c)}if(typeof a.then==`function`)return b(e,r,Ba(a),c);if(a.$$typeof===C)return b(e,r,la(e,a),c);Ha(e,a)}return typeof a==`string`&&a!==``||typeof a==`number`||typeof a==`bigint`?(a=``+a,r!==null&&r.tag===6?(n(e,r.sibling),c=i(r,a),c.return=e,e=c):(n(e,r),c=Si(a,e.mode,c),c.return=e,e=c),o(e)):n(e,r)}return function(e,t,n,r){try{za=0;var i=b(e,t,n,r);return Ra=null,i}catch(t){if(t===Oa||t===Aa)throw t;var a=gi(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Wa=Ua(!0),Ga=Ua(!1),Ka=!1;function qa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ja(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ya(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Xa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,W&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=pi(e),fi(e,null,n),t}return li(e,r,t,n),pi(e)}function Za(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,st(e,n)}}function Qa(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var $a=!1;function eo(){if($a){var e=ya;if(e!==null)throw e}}function to(e,t,n,r){$a=!1;var i=e.updateQueue;Ka=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(q&f)===f:(r&f)===f){f!==0&&f===va&&($a=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var m=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(m=g.payload,typeof m==`function`){d=m.call(_,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=g.payload,f=typeof m==`function`?m.call(_,d,f):m,f==null)break a;d=h({},d,f);break a;case 2:Ka=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Kl|=o,e.lanes=o,e.memoizedState=d}}function no(e,t){if(typeof e!=`function`)throw Error(s(191,e));e.call(t)}function ro(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=D.T,s={};D.T=s,Rs(e,!1,t,n);try{var c=i(),l=D.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ls(e,t,Sa(c,r),pu(e)):Ls(e,t,r,pu(e))}catch(n){Ls(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{O.p=a,o!==null&&s.types!==null&&(o.types=s.types),D.T=o}}function Ds(){}function Os(e,t,n,r){if(e.tag!==5)throw Error(s(476));var i=ks(e).queue;Es(e,i,t,le,n===null?Ds:function(){return As(e),n(r)})}function ks(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:le,baseState:le,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:zo,lastRenderedState:le},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:zo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function As(e){var t=ks(e);t.next===null&&(t=e.alternate.memoizedState),Ls(e,t.next.queue,{},pu())}function js(){return ca(Qf)}function Ms(){return z().memoizedState}function Ns(){return z().memoizedState}function Ps(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Ya(n);var r=Xa(t,e,n);r!==null&&(hu(r,t,n),Za(r,t,n)),t={cache:ma()},e.payload=t;return}t=t.return}}function Fs(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},zs(e)?Bs(t,n):(n=ui(e,t,n,r),n!==null&&(hu(n,e,r),Vs(n,t,r)))}function Is(e,t,n){Ls(e,t,n,pu())}function Ls(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(zs(e))Bs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Ar(s,o))return li(e,t,i,0),G===null&&ci(),!1}catch{}if(n=ui(e,t,i,r),n!==null)return hu(n,e,r),Vs(n,t,r),!0}return!1}function Rs(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},zs(e)){if(t)throw Error(s(479))}else t=ui(e,n,r,2),t!==null&&hu(t,e,2)}function zs(e){var t=e.alternate;return e===F||t!==null&&t===F}function Bs(e,t){bo=yo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Vs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,st(e,n)}}var Hs={readContext:ca,use:Lo,useCallback:R,useContext:R,useEffect:R,useImperativeHandle:R,useLayoutEffect:R,useInsertionEffect:R,useMemo:R,useReducer:R,useRef:R,useState:R,useDebugValue:R,useDeferredValue:R,useTransition:R,useSyncExternalStore:R,useId:R,useHostTransitionStatus:R,useFormState:R,useActionState:R,useOptimistic:R,useMemoCache:R,useCacheRefresh:R};Hs.useEffectEvent=R;var Us={readContext:ca,use:Lo,useCallback:function(e,t){return Po().memoizedState=[e,t===void 0?null:t],e},useContext:ca,useEffect:ps,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),ds(4194308,4,ys.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ds(4194308,4,e,t)},useInsertionEffect:function(e,t){ds(4,2,e,t)},useMemo:function(e,t){var n=Po();t=t===void 0?null:t;var r=e();if(xo){We(!0);try{e()}finally{We(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Po();if(n!==void 0){var i=n(t);if(xo){We(!0);try{n(t)}finally{We(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Fs.bind(null,F,e),[r.memoizedState,e]},useRef:function(e){var t=Po();return e={current:e},t.memoizedState=e},useState:function(e){e=Yo(e);var t=e.queue,n=Is.bind(null,F,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:xs,useDeferredValue:function(e,t){return ws(Po(),e,t)},useTransition:function(){var e=Yo(!1);return e=Es.bind(null,F,e.queue,!0,!1),Po().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=F,i=Po();if(M){if(n===void 0)throw Error(s(407));n=n()}else{if(n=t(),G===null)throw Error(s(349));q&127||Wo(r,t,n)}i.memoizedState=n;var a={value:n,getSnapshot:t};return i.queue=a,ps(Ko.bind(null,r,a,e),[e]),r.flags|=2048,ls(9,{destroy:void 0},Go.bind(null,r,a,n,t),null),n},useId:function(){var e=Po(),t=G.identifierPrefix;if(M){var n=Fi,r=Pi;n=(r&~(1<<32-Ge(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=So++,0<\/script>`,a=a.removeChild(a.firstChild);break;case`select`:a=typeof r.is==`string`?o.createElement(`select`,{is:r.is}):o.createElement(`select`),r.multiple?a.multiple=!0:r.size&&(a.size=r.size);break;default:a=typeof r.is==`string`?o.createElement(i,{is:r.is}):o.createElement(i)}}a[mt]=t,a[ht]=r;a:for(o=t.child;o!==null;){if(o.tag===5||o.tag===6)a.appendChild(o.stateNode);else if(o.tag!==4&&o.tag!==27&&o.child!==null){o.child.return=o,o=o.child;continue}if(o===t)break a;for(;o.sibling===null;){if(o.return===null||o.return===t)break a;o=o.return}o.sibling.return=o.return,o=o.sibling}t.stateNode=a;a:switch(Pd(a,i,r),i){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Ic(t)}}return V(t),Lc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Ic(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(s(166));if(e=he.current,Ji(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,i=Vi,i!==null)switch(i.tag){case 27:case 5:r=i.memoizedProps}e[mt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Gi(t,!0)}else e=Bd(e).createTextNode(r),e[mt]=t,t.stateNode=e}return V(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Ji(t),n!==null){if(e===null){if(!r)throw Error(s(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(s(557));e[mt]=t}else Yi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;V(t),e=!1}else n=Xi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(go(t),t):(go(t),null);if(t.flags&128)throw Error(s(558))}return V(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(i=Ji(t),r!==null&&r.dehydrated!==null){if(e===null){if(!i)throw Error(s(318));if(i=t.memoizedState,i=i===null?null:i.dehydrated,!i)throw Error(s(317));i[mt]=t}else Yi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;V(t),i=!1}else i=Xi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=i),i=!0;if(!i)return t.flags&256?(go(t),t):(go(t),null)}return go(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,i=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(i=r.alternate.memoizedState.cachePool.pool),a=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(a=r.memoizedState.cachePool.pool),a!==i&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),zc(t,t.updateQueue),V(t),null);case 4:return ve(),e===null&&Sd(t.stateNode.containerInfo),V(t),null;case 10:return na(t.type),V(t),null;case 19:if(k(P),r=t.memoizedState,r===null)return V(t),null;if(i=(t.flags&128)!=0,a=r.rendering,a===null)if(i)Bc(r,!1);else{if(Y!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(a=_o(e),a!==null){for(t.flags|=128,Bc(r,!1),e=a.updateQueue,t.updateQueue=e,zc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)yi(n,e),n=n.sibling;return A(P,P.current&1|2),M&&Ii(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ne()>nu&&(t.flags|=128,i=!0,Bc(r,!1),t.lanes=4194304)}else{if(!i)if(e=_o(a),e!==null){if(t.flags|=128,i=!0,e=e.updateQueue,t.updateQueue=e,zc(t,e),Bc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!a.alternate&&!M)return V(t),null}else 2*Ne()-r.renderingStartTime>nu&&n!==536870912&&(t.flags|=128,i=!0,Bc(r,!1),t.lanes=4194304);r.isBackwards?(a.sibling=t.child,t.child=a):(e=r.last,e===null?t.child=a:e.sibling=a,r.last=a)}return r.tail===null?(V(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ne(),e.sibling=null,n=P.current,A(P,i?n&1|2:n&1),M&&Ii(t,r.treeForkCount),e);case 22:case 23:return go(t),co(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(V(t),t.subtreeFlags&6&&(t.flags|=8192)):V(t),n=t.updateQueue,n!==null&&zc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&k(wa),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),na(N),V(t),null;case 25:return null;case 30:return null}throw Error(s(156,t.tag))}function Hc(e,t){switch(zi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return na(N),ve(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return be(t),null;case 31:if(t.memoizedState!==null){if(go(t),t.alternate===null)throw Error(s(340));Yi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(go(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(s(340));Yi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return k(P),null;case 4:return ve(),null;case 10:return na(t.type),null;case 22:case 23:return go(t),co(),e!==null&&k(wa),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return na(N),null;case 25:return null;default:return null}}function Uc(e,t){switch(zi(t),t.tag){case 3:na(N),ve();break;case 26:case 27:case 5:be(t);break;case 4:ve();break;case 31:t.memoizedState!==null&&go(t);break;case 13:go(t);break;case 19:k(P);break;case 10:na(t.type);break;case 22:case 23:go(t),co(),e!==null&&k(wa);break;case 24:na(N)}}function Wc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Gc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Kc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{ro(t,n)}catch(t){Z(e,e.return,t)}}}function qc(e,t,n){n.props=Xs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Jc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function Yc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}function Xc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Zc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[ht]=t}catch(t){Z(e,e.return,t)}}function Qc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function $c(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Qc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function el(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=cn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(el(e,t,n),e=e.sibling;e!==null;)el(e,t,n),e=e.sibling}function tl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(tl(e,t,n),e=e.sibling;e!==null;)tl(e,t,n),e=e.sibling}function nl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[mt]=e,t[ht]=n}catch(t){Z(e,e.return,t)}}var rl=!1,H=!1,il=!1,al=typeof WeakSet==`function`?WeakSet:Set,ol=null;function sl(e,t){if(e=e.containerInfo,Rd=sp,e=Fr(e),Ir(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var i=r.anchorOffset,a=r.focusNode;r=r.focusOffset;try{n.nodeType,a.nodeType}catch{n=null;break a}var o=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||i!==0&&f.nodeType!==3||(c=o+i),f!==a||r!==0&&f.nodeType!==3||(l=o+r),f.nodeType===3&&(o+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===i&&(c=o),p===a&&++d===r&&(l=o),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,ol=t;ol!==null;)if(t=ol,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,ol=e;else for(;ol!==null;){switch(t=ol,a=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(a,r,n),a[mt]=e,Dt(a),r=a;break a;case`link`:var o=Vf(`link`,`href`,i).get(r+(n.href||``));if(o){for(var c=0;cg&&(o=g,g=h,h=o);var _=Nr(s,h),v=Nr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,D.T=null,n=lu,lu=null;var a=au,o=su;if(X=0,ou=au=null,su=0,W&6)throw Error(s(331));var c=W;if(W|=4,Il(a.current),Ol(a,a.current,o,n),W=c,id(0,!1),Ue&&typeof Ue.onPostCommitFiberRoot==`function`)try{Ue.onPostCommitFiberRoot(He,a)}catch{}return!0}finally{O.p=i,D.T=r,Vu(e,t)}}function Wu(e,t,n){t=Ei(n,t),t=nc(e.stateNode,t,2),e=Xa(e,t,2),e!==null&&(it(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(iu===null||!iu.has(r))){e=Ei(n,e),n=rc(2),r=Xa(t,n,2),r!==null&&(ic(n,r,t,e),it(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Bl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Wl=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,G===e&&(q&n)===n&&(Y===4||Y===3&&(q&62914560)===q&&300>Ne()-eu?!(W&2)&&Su(e,0):Jl|=n,Xl===q&&(Xl=0)),rd(e)}function qu(e,t){t===0&&(t=nt()),e=di(e,t),e!==null&&(it(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,i=e.memoizedState;i!==null&&(n=i.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(s(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return ke(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Ge(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=q,a=$e(r,r===G?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||et(r,a)||(n=!0,ld(r,a));r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Ne(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}X!==0&&X!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Kt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),Dt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Kt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Kt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Kt(n.imageSizes)+`"]`)):i+=`[href="`+Kt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),Dt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Kt(r)+`"][href="`+Kt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),Dt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=Et(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);Dt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=Et(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Dt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=Et(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),Dt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var i=(i=he.current)?gf(i):null;if(!i)throw Error(s(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=Et(i).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var a=Et(i).hoistableStyles,o=a.get(e);if(o||(i=i.ownerDocument||i,o={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},a.set(e,o),(a=i.querySelector(jf(e)))&&!a._p&&(o.instance=a,o.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),a||Nf(i,e,n,o.state))),t&&r===null)throw Error(s(528,``));return o}if(t&&r!==null)throw Error(s(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=Et(i).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(s(444,e))}}function Af(e){return`href="`+Kt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),Dt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Kt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Kt(n.href)+`"]`);if(r)return t.instance=r,Dt(r),r;var i=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),Dt(r),Pd(r,`style`,i),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:i=Af(n.href);var a=e.querySelector(jf(i));if(a)return t.state.loading|=4,t.instance=a,Dt(a),a;r=Mf(n),(i=mf.get(i))&&Rf(r,i),a=(e.ownerDocument||e).createElement(`link`),Dt(a);var o=a;return o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),t.state.loading|=4,Lf(a,n.precedence,e),t.instance=a;case`script`:return a=Pf(n.src),(i=e.querySelector(Ff(a)))?(t.instance=i,Dt(i),i):(r=n,(i=mf.get(a))&&(r=h({},n),zf(r,i)),e=e.ownerDocument||e,i=e.createElement(`script`),Dt(i),Pd(i,`link`,r),e.head.appendChild(i),t.instance=i);case`void`:return null;default:throw Error(s(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,Dt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),Dt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=s()})),l=n(),u=c(),d=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),f=e(((e,t)=>{t.exports=d()}))(),p={bg:`#0A0A0C`,panel:`#141418`,surface:`#1C1C22`,border:`#2A2A32`,amber:`#E8A030`,amberDim:`#7A5218`,blue:`#3A7BA8`,blueDim:`#1E4060`,green:`#3AB87A`,red:`#C84040`,textPrimary:`#F0EDE6`,textSec:`#8888A0`,textDim:`#444458`},m=window.location.origin,h=m.replace(/^http/,`ws`)+`/ws`;async function g(e){let t=await fetch(`${m}${e}`);if(!t.ok)throw Error(`${e} => ${t.status}`);return t.json()}async function _(e,t){let n=await fetch(`${m}${e}`,{method:`POST`,headers:{"Content-Type":`application/json`},body:t==null?void 0:JSON.stringify(t)});if(!n.ok)throw Error(`${e} => ${n.status}`);return n.json()}async function v(e,t){let n=await fetch(`${m}${e}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)});if(!n.ok)throw Error(`${e} => ${n.status}`);return n.json()}async function y(e){let t=await fetch(`${m}${e}`,{method:`DELETE`});if(!t.ok)throw Error(`${e} => ${t.status}`);return t.json()}async function b(e,t){let n=new FormData;n.append(`file`,t);let r=await fetch(`${m}${e}`,{method:`POST`,body:n});if(!r.ok)throw Error(`${e} => ${r.status}`);return r.json()}function x(){let[e,t]=(0,l.useState)(null),[n,r]=(0,l.useState)(!1),i=(0,l.useRef)(null),a=(0,l.useRef)(null);return(0,l.useEffect)(()=>{g(`/api/state`).then(e=>{t(e),r(!0)}).catch(()=>{r(!1)});let e;function n(){try{let a=new WebSocket(h);a.onmessage=e=>{try{let n=JSON.parse(e.data);(n.type===`connected`||n.type===`state`)&&(t(n.state),r(!0)),n.type===`preset_changed`&&n.state&&t(n.state),n.type===`bypass_changed`&&t(e=>e&&{...e,bypass:n.bypass}),n.type===`tuner_changed`&&t(e=>e&&{...e,tuner_enabled:n.tuner_enabled}),n.type===`routing_changed`&&t(e=>e&&{...e,routing_mode:n.routing_mode,routing_breakpoint:n.routing_breakpoint}),(n.type===`model_loaded`||n.type===`ir_loaded`)&&g(`/api/state`).then(e=>t(e))}catch{}},a.onclose=()=>{r(!1),e=setTimeout(n,3e3)},a.onerror=()=>a.close(),i.current=a}catch{e=setTimeout(n,3e3)}}return n(),a.current=setInterval(()=>{g(`/api/state`).then(e=>{t(e),r(!0)}).catch(()=>{})},5e3),()=>{clearInterval(a.current),clearTimeout(e),i.current&&i.current.close()}},[]),{state:e,connected:n,refresh:(0,l.useCallback)(()=>{g(`/api/state`).then(e=>{t(e),r(!0)}).catch(()=>{})},[])}}var S=` + @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600&display=swap'); + * { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; } + body { background: ${p.bg}; color: ${p.textPrimary}; font-family: 'Inter', sans-serif; user-select: none; } + :root { --amber: ${p.amber}; --blue: ${p.blue}; --green: ${p.green}; } + + .mono { font-family: 'JetBrains Mono', monospace; } + + ::-webkit-scrollbar { width: 4px; height: 4px; } + ::-webkit-scrollbar-track { background: ${p.panel}; } + ::-webkit-scrollbar-thumb { background: ${p.border}; border-radius: 2px; } + + input, textarea, select { font-family: inherit; } + + .knob-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; cursor: pointer; } + .knob { border-radius: 50%; position: relative; touch-action: none; } + .knob-inner { border-radius: 50%; width: 100%; height: 100%; position: relative; + background: radial-gradient(circle at 35% 30%, #3A3A48, #1A1A22); + box-shadow: 0 2px 8px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.07); } + .knob-dot { position: absolute; width: 3px; border-radius: 2px; background: var(--amber); + left: 50%; transform-origin: bottom center; box-shadow: 0 0 6px var(--amber); } + .knob-ring { position: absolute; inset: -5px; border-radius: 50%; } + .knob-label { font-size: 10px; color: ${p.textSec}; letter-spacing: .06em; text-transform: uppercase; text-align: center; } + .knob-value { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: ${p.amber}; } + + .toggle { display: flex; background: ${p.surface}; border-radius: 6px; border: 1px solid ${p.border}; overflow: hidden; } + .toggle-btn { flex: 1; padding: 7px 12px; font-size: 12px; font-weight: 500; letter-spacing: .04em; + background: none; border: none; color: ${p.textSec}; cursor: pointer; transition: all .15s; } + .toggle-btn.active { background: ${p.amber}; color: #000; } + + .vu-bar { display: flex; gap: 2px; align-items: flex-end; height: 100%; } + .vu-seg { width: 4px; border-radius: 1px; transition: opacity .05s; } + + .fader-track { width: 4px; border-radius: 2px; background: ${p.border}; position: relative; cursor: pointer; touch-action: none; } + .fader-fill { width: 100%; border-radius: 2px; position: absolute; bottom: 0; transition: height .05s; } + .fader-thumb { width: 28px; height: 10px; border-radius: 3px; position: absolute; left: 50%; transform: translateX(-50%); + background: linear-gradient(180deg, #3A3A4A, #252530); + border: 1px solid #4A4A5A; box-shadow: 0 2px 4px rgba(0,0,0,.5); + cursor: grab; touch-action: none; } + .fader-thumb::after { content: ''; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); + width: 16px; height: 2px; border-radius: 1px; background: rgba(255,255,255,.15); + box-shadow: 0 3px 0 rgba(255,255,255,.15), 0 -3px 0 rgba(255,255,255,.15); } + + .tabbar { display: flex; background: ${p.panel}; border-bottom: 1px solid ${p.border}; flex-shrink: 0; } + .tab { flex: 1; padding: 10px 4px; font-size: 10px; font-weight: 500; letter-spacing: .04em; + text-align: center; text-transform: uppercase; color: ${p.textDim}; + cursor: pointer; border-bottom: 2px solid transparent; transition: all .15s; } + .tab.active { color: ${p.amber}; border-bottom-color: ${p.amber}; } + + .card { background: ${p.panel}; border: 1px solid ${p.border}; border-radius: 10px; padding: 16px; } + .card-sm { background: ${p.surface}; border: 1px solid ${p.border}; border-radius: 8px; padding: 12px; } + + .btn { padding: 10px 18px; border-radius: 7px; font-size: 13px; font-weight: 600; + letter-spacing: .04em; border: none; cursor: pointer; transition: all .12s; } + .btn-primary { background: ${p.amber}; color: #000; } + .btn-primary:active { filter: brightness(.85); transform: scale(.97); } + .btn-ghost { background: ${p.surface}; color: ${p.textPrimary}; border: 1px solid ${p.border}; } + .btn-ghost:active { background: ${p.border}; } + .btn-danger { background: rgba(200,64,64,.2); color: ${p.red}; border: 1px solid rgba(200,64,64,.3); } + .btn-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; + justify-content: center; background: ${p.surface}; border: 1px solid ${p.border}; cursor: pointer; + font-size: 16px; transition: all .12s; } + .btn-icon:active { transform: scale(.93); } + .btn-icon.active { background: rgba(232,160,48,.15); border-color: ${p.amber}; color: ${p.amber}; } + .btn-sm { padding: 6px 12px; font-size: 12px; } + + .fx-block { background: ${p.panel}; border: 1px solid ${p.border}; border-radius: 10px; + overflow: hidden; transition: border-color .15s; } + .fx-block.active { border-color: ${p.amber}; } + .fx-block.bypassed { opacity: .45; } + .fx-header { display: flex; align-items: center; gap: 10px; padding: 10px 12px; + border-bottom: 1px solid ${p.border}; background: ${p.surface}; cursor: pointer; } + .fx-body { padding: 12px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; } + .bypass-led { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } + .led-on { background: ${p.green}; box-shadow: 0 0 8px ${p.green}; } + .led-off { background: ${p.textDim}; } + + .waveform-wrap { position: relative; overflow: hidden; border-radius: 6px; background: #0F0F14; } + .waveform-canvas { display: block; } + .playhead { position: absolute; top: 0; bottom: 0; width: 1.5px; background: ${p.amber}; + box-shadow: 0 0 8px ${p.amber}; pointer-events: none; transition: left .08s linear; } + + .nam-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; + background: rgba(58,123,168,.15); border: 1px solid rgba(58,123,168,.35); border-radius: 5px; + font-family: 'JetBrains Mono', monospace; font-size: 11px; color: ${p.blue}; } + + .section-label { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; + color: ${p.textDim}; font-weight: 600; margin-bottom: 10px; } + + .preset-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; + border-radius: 8px; cursor: pointer; transition: background .12s; border: 1px solid transparent; } + .preset-row:active, .preset-row.active { background: rgba(232,160,48,.08); border-color: rgba(232,160,48,.25); } + + .transport-btn { width: 44px; height: 44px; border-radius: 50%; display: flex; + align-items: center; justify-content: center; font-size: 16px; cursor: pointer; + border: 2px solid ${p.border}; background: ${p.surface}; transition: all .12s; } + .transport-btn:active { transform: scale(.92); } + .transport-btn.rec { border-color: ${p.red}; background: rgba(200,64,64,.15); } + .transport-btn.play { border-color: ${p.green}; background: rgba(58,184,122,.15); } + + .badge { display: inline-flex; align-items: center; justify-content: center; + padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 700; + letter-spacing: .06em; text-transform: uppercase; } + .badge-amber { background: rgba(232,160,48,.2); color: ${p.amber}; } + .badge-green { background: rgba(58,184,122,.2); color: ${p.green}; } + .badge-blue { background: rgba(58,123,168,.2); color: ${p.blue}; } + .badge-red { background: rgba(200,64,64,.2); color: ${p.red}; } + + .screen-header { padding: 12px 14px 8px; display: flex; align-items: center; + justify-content: space-between; border-bottom: 1px solid ${p.border}; flex-shrink: 0; } + .screen-title { font-size: 13px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: ${p.textSec}; } + + .screen-body { flex: 1; overflow-y: auto; padding: 12px; display: flex; + flex-direction: column; gap: 12px; } + + /* Settings lists */ + .setting-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid ${p.border}; } + .setting-label { font-size: 13px; color: ${p.textPrimary}; } + .setting-desc { font-size: 11px; color: ${p.textDim}; margin-top: 2px; } + .switch { width: 40px; height: 22px; border-radius: 11px; background: ${p.border}; cursor: pointer; position: relative; transition: background .2s; flex-shrink: 0; } + .switch.on { background: ${p.green}; } + .switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: white; transition: transform .15s; } + .switch.on::after { transform: translateX(18px); } + + .search-bar { display: flex; background: ${p.surface}; border-radius: 7px; border: 1px solid ${p.border}; + padding: 8px 12px; gap: 8px; align-items: center; } + .search-bar input { background: none; border: none; outline: none; color: ${p.textPrimary}; font-size: 13px; flex: 1; } + .search-bar input::placeholder { color: ${p.textDim}; } + + .file-drop { border: 2px dashed ${p.border}; border-radius: 8px; padding: 20px; text-align: center; + cursor: pointer; transition: all .15s; font-size: 13px; color: ${p.textDim}; } + .file-drop:hover, .file-drop.dragover { border-color: ${p.amber}; color: ${p.amber}; } + + .loader { width: 20px; height: 20px; border: 2px solid ${p.border}; border-top-color: ${p.amber}; + border-radius: 50%; animation: spin .6s linear infinite; } + @keyframes spin { to { transform: rotate(360deg); } } + + .slide-panel { position: fixed; inset: 0; background: rgba(0,0,0,.7); z-index: 100; + display: flex; align-items: flex-end; justify-content: center; } + .slide-panel-inner { background: ${p.bg}; max-width: 440px; width: 100%; max-height: 85vh; + border-radius: 16px 16px 0 0; overflow: hidden; display: flex; flex-direction: column; } + .slide-panel-handle { width: 36px; height: 4px; border-radius: 2px; background: ${p.border}; + margin: 8px auto; flex-shrink: 0; } +`;function C({label:e,value:t=50,onChange:n,size:r=52,color:i=p.amber,min:a=0,max:o=100}){let s=(0,l.useRef)(null),c=(0,l.useRef)(null),u=(t-a)/(o-a),d=-140+u*280,m=e=>{e.preventDefault(),c.current={y:e.touches?e.touches[0].clientY:e.clientY,val:t};let r=e=>{let t=e.touches?e.touches[0].clientY:e.clientY,r=(c.current.y-t)/120,i=Math.max(a,Math.min(o,c.current.val+r*(o-a)));n?.(Math.round(i))},i=()=>{window.removeEventListener(`mousemove`,r),window.removeEventListener(`mouseup`,i),window.removeEventListener(`touchmove`,r),window.removeEventListener(`touchend`,i)};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,i),window.addEventListener(`touchmove`,r,{passive:!1}),window.addEventListener(`touchend`,i)},h=r+12,g=h/2,_=h/2,v=r/2+3,y=(d-90)*(Math.PI/180),b=g+v*Math.cos(y),x=_+v*Math.sin(y);return(0,f.jsxs)(`div`,{className:`knob-wrap`,style:{width:r+12},children:[(0,f.jsxs)(`div`,{className:`knob`,style:{width:r,height:r},onMouseDown:m,onTouchStart:m,ref:s,children:[(0,f.jsxs)(`svg`,{style:{position:`absolute`,inset:-6,width:h,height:h,overflow:`visible`},children:[(0,f.jsx)(`circle`,{cx:g,cy:_,r:v,fill:`none`,stroke:p.border,strokeWidth:`2.5`,strokeLinecap:`round`,opacity:`.5`}),u>0&&(0,f.jsx)(`path`,{d:`M ${g} ${_-v} A ${v} ${v} 0 ${+(u>.5)} 1 ${b} ${x}`,fill:`none`,stroke:i,strokeWidth:`2.5`,strokeLinecap:`round`,style:{filter:`drop-shadow(0 0 3px ${i})`}})]}),(0,f.jsx)(`div`,{className:`knob-inner`,style:{"--amber":i},children:(0,f.jsx)(`div`,{className:`knob-dot`,style:{height:r*.38,bottom:r/2-2,transform:`translateX(-50%) rotate(${d}deg)`,transformOrigin:`50% ${r*.38}px`}})})]}),(0,f.jsx)(`div`,{className:`knob-value mono`,style:{color:i},children:t}),(0,f.jsx)(`div`,{className:`knob-label`,children:e})]})}function w({level:e=0,height:t=60,vertical:n=!0}){let r=Math.round(e/100*12),i=e=>e>=10?p.red:e>=8?`#E8C030`:p.green;return n?(0,f.jsx)(`div`,{style:{display:`flex`,flexDirection:`column-reverse`,gap:2,height:t,alignItems:`center`},children:Array.from({length:12}).map((e,n)=>(0,f.jsx)(`div`,{style:{width:6,height:(t-24)/12,borderRadius:1,background:n(0,f.jsx)(`div`,{style:{flex:1,height:`100%`,borderRadius:1,background:t{let r=a.current;if(!r)return;let o=r.getContext(`2d`);o.clearRect(0,0,e,t);let s=t/2;o.strokeStyle=n,o.lineWidth=1,o.shadowColor=n,o.shadowBlur=2,o.beginPath();for(let t=0;te.default??e.default??50));return(0,f.jsxs)(`div`,{className:`fx-block ${n?`active`:``} ${r?`bypassed`:``}`,children:[(0,f.jsxs)(`div`,{className:`fx-header`,onClick:()=>s(e=>!e),children:[(0,f.jsx)(`div`,{className:`bypass-led ${r?`led-off`:`led-on`}`,onClick:e=>{e.stopPropagation(),a?.()}}),(0,f.jsx)(`span`,{style:{flex:1,fontSize:13,fontWeight:600},children:e}),(0,f.jsx)(`span`,{className:`badge badge-blue`,style:{fontSize:10},children:t}),(0,f.jsx)(`span`,{style:{color:p.textDim,fontSize:18,marginLeft:6},children:o?`▾`:`▸`})]}),o&&(0,f.jsx)(`div`,{className:`fx-body`,children:i.map((e,t)=>(0,f.jsx)(C,{label:e.name,value:c[t],size:44,onChange:e=>u(n=>n.map((n,r)=>r===t?e:n)),min:e.min??0,max:e.max??100},e.key||e.name))})]})}function te({children:e,onClose:t}){return(0,f.jsx)(`div`,{className:`slide-panel`,onClick:t,children:(0,f.jsxs)(`div`,{className:`slide-panel-inner`,onClick:e=>e.stopPropagation(),children:[(0,f.jsx)(`div`,{className:`slide-panel-handle`}),e]})})}function E({state:e,connected:t}){let[n,r]=(0,l.useState)(e?.master_volume==null?80:Math.round(e.master_volume*100)),[i,a]=(0,l.useState)(45),[o,s]=(0,l.useState)(42),[c,u]=(0,l.useState)(!1);(0,l.useEffect)(()=>{e?.master_volume!=null&&r(Math.round(e.master_volume*100))},[e?.master_volume]),(0,l.useEffect)(()=>{let e=setInterval(()=>{a(e=>Math.max(10,Math.min(95,e+(Math.random()-.48)*12))),s(e=>Math.max(10,Math.min(95,e+(Math.random()-.48)*12)))},90);return()=>clearInterval(e)},[]);let d=async e=>{r(e);try{await v(`/api/volume`,{volume:e/100})}catch{}};return(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`screen-title`,children:`Active Rig`}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6,marginTop:4,flexWrap:`wrap`,alignItems:`center`},children:[e?.current_preset?(0,f.jsx)(`span`,{className:`nam-chip`,style:{color:p.amber,borderColor:`${p.amber}55`,background:`${p.amber}15`},children:e.current_preset.name}):(0,f.jsx)(`span`,{style:{fontSize:11,color:p.textDim},children:`No preset loaded`}),t?(0,f.jsx)(`span`,{className:`badge badge-green`,children:`Connected`}):(0,f.jsx)(`span`,{className:`badge badge-red`,children:`Offline`})]})]}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`},children:[(0,f.jsx)(w,{level:i,height:44}),(0,f.jsx)(w,{level:o,height:44})]})]}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[(0,f.jsxs)(`div`,{className:`card-sm`,style:{display:`flex`,gap:10,justifyContent:`space-around`},children:[(0,f.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:4},children:`Bypass`}),(0,f.jsx)(`div`,{className:`switch ${e?.bypass?`on`:``}`,onClick:async()=>{try{await _(`/api/bypass`)}catch{}},style:{margin:`0 auto`}})]}),(0,f.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:4},children:`Tuner`}),(0,f.jsx)(`div`,{className:`switch ${e?.tuner_enabled?`on`:``}`,onClick:async()=>{try{let t=e?.tuner_enabled;await _(`/api/tuner`,{enabled:!t})}catch{}},style:{margin:`0 auto`}})]}),(0,f.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:4},children:`Routing`}),(0,f.jsx)(`span`,{className:`mono`,style:{fontSize:12,color:p.amber},children:e?.routing_mode||`mono`})]})]}),(0,f.jsxs)(`div`,{className:`card`,style:{display:`flex`,gap:20,alignItems:`center`},children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{className:`section-label`,children:`Master Volume`}),(0,f.jsx)(`input`,{type:`range`,min:0,max:100,value:n,onChange:e=>d(+e.target.value),style:{width:`100%`,accentColor:p.amber}}),(0,f.jsxs)(`div`,{className:`mono`,style:{fontSize:11,color:p.amber,marginTop:4},children:[n,`%`]})]}),(0,f.jsxs)(`div`,{className:`mono`,style:{fontSize:11,color:p.textSec,textAlign:`right`},children:[e?.nam_loaded?`NAM: Active`:`NAM: —`,(0,f.jsx)(`br`,{}),e?.ir_loaded?`IR: Active`:`IR: —`]})]}),(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsx)(`div`,{className:`section-label`,children:`Signal Chain`}),(0,f.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:4,overflowX:`auto`,padding:`4px 0`},children:[`IN`,e?.bypass?`BYP`:e?.nam_loaded?`NAM`:`AMP`,e?.ir_loaded?`IR`:`CAB`,`OUT`].map((e,t,n)=>(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:4,flexShrink:0},children:[(0,f.jsx)(`div`,{style:{padding:`3px 8px`,borderRadius:4,fontSize:10,fontWeight:700,background:t===0||t===n.length-1?p.blueDim:p.amberDim,color:t===0||t===n.length-1?p.blue:p.amber,border:`1px solid ${t===0||t===n.length-1?p.blue:p.amber}60`},children:e}),t{if(!t||!e?.current_preset){r([{id:1,title:`Overdrive`,type:`OD`,bypassed:!1,params:[{key:`drive`,name:`Drive`,default:62},{key:`tone`,name:`Tone`,default:55}]},{id:2,title:`Compressor`,type:`COMP`,bypassed:!1,params:[{key:`thresh`,name:`Thresh`,default:40},{key:`ratio`,name:`Ratio`,default:40}]},{id:3,title:`NAM Amp`,type:`AMP`,bypassed:!1,params:[]},{id:4,title:`Delay`,type:`DELAY`,bypassed:!0,params:[{key:`time`,name:`Time`,default:45},{key:`feedback`,name:`Fdbk`,default:38}]}]),a(!1);return}g(`/api/presets`).then(e=>{let t=e.banks||[];if(t.length>0&&t[0].presets){let e=t[0].presets.find(e=>e!=null);e?.chain&&r(e.chain.map((e,t)=>({id:t+1,title:e.fx_type.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase()),type:e.fx_type.toUpperCase(),bypassed:e.bypass||!e.enabled,params:[]})))}a(!1)}).catch(()=>{a(!1)})},[t,e]);let o=e=>r(t=>t&&t.map(t=>t.id===e?{...t,bypassed:!t.bypassed}:t));return i?(0,f.jsx)(`div`,{style:{flex:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,f.jsx)(`div`,{className:`loader`})}):(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsx)(`div`,{className:`screen-title`,children:`FX Chain`}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,children:`+ Add Block`})]}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[(0,f.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:4,padding:`4px 2px`,overflowX:`auto`},children:[`IN`,...(n||[]).map(e=>e.type),`OUT`].map((e,t,n)=>(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:4,flexShrink:0},children:[(0,f.jsx)(`div`,{style:{padding:`3px 8px`,borderRadius:4,fontSize:10,fontWeight:700,background:e===`IN`||e===`OUT`?p.blueDim:p.amberDim,color:e===`IN`||e===`OUT`?p.blue:p.amber,border:`1px solid ${e===`IN`||e===`OUT`?p.blue:p.amber}60`},children:e}),t(0,f.jsx)(T,{...e,active:!e.bypassed,onToggle:()=>o(e.id)},e.id))]})]})}function re({state:e,connected:t,refresh:n}){let[r,i]=(0,l.useState)([]),[a,o]=(0,l.useState)(null),[s,c]=(0,l.useState)(!0),[u,d]=(0,l.useState)(!1),[m,h]=(0,l.useState)(``),[v,y]=(0,l.useState)([]),[x,S]=(0,l.useState)(!1),[C,w]=(0,l.useState)(!1),ee=(0,l.useRef)(null),T=(0,l.useCallback)(async()=>{if(!t){c(!1);return}try{let e=await g(`/api/models`);i(e.models||[]),o(e.current)}catch{}c(!1)},[t]);(0,l.useEffect)(()=>{T()},[T]);let te=async e=>{try{await _(`/api/models/load`,{path:e}),await T(),n()}catch{alert(`Failed to load model`)}},E=async()=>{try{await _(`/api/models/unload`),o(null),await T(),n()}catch{alert(`Failed to unload`)}},ne=async e=>{let t=e.target.files?.[0];if(t){w(!0);try{await b(`/api/models/upload`,t),await T()}catch{alert(`Upload failed`)}w(!1)}},re=(0,l.useCallback)(async()=>{if(m.trim()){d(!0);try{y((await g(`/api/models/tonedownload/search?q=${encodeURIComponent(m)}`)).results||[])}catch{alert(`Search failed`)}d(!1)}},[m]),ie=async e=>{try{await _(`/api/models/tonedownload/install`,{download_url:e.download_url,name:e.name||e.filename,id:e.id,size:e.size,pack_name:e.pack_name,display_name:e.name}),await T(),n()}catch{alert(`Install failed`)}};return s?(0,f.jsx)(`div`,{style:{flex:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,f.jsx)(`div`,{className:`loader`})}):(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsxs)(`div`,{className:`screen-title`,children:[`NAM Models (`,r.length,`)`]}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6},children:[(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>S(!x),children:x?`Local`:`Search`}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:()=>ee.current?.click(),children:C?`...`:`+ Upload`}),(0,f.jsx)(`input`,{ref:ee,type:`file`,accept:`.nam`,style:{display:`none`},onChange:ne})]})]}),x&&(0,f.jsxs)(`div`,{style:{padding:`8px 12px`,borderBottom:`1px solid ${p.border}`},children:[(0,f.jsxs)(`div`,{className:`search-bar`,children:[(0,f.jsx)(`span`,{style:{color:p.textDim},children:`🔍`}),(0,f.jsx)(`input`,{type:`text`,placeholder:`Search Tone3000…`,value:m,onChange:e=>h(e.target.value),onKeyDown:e=>e.key===`Enter`&&re()}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:re,disabled:u,children:u?`...`:`Go`})]}),v.length>0&&(0,f.jsx)(`div`,{style:{marginTop:8,maxHeight:240,overflow:`auto`},children:v.map(e=>(0,f.jsxs)(`div`,{className:`preset-row`,onClick:()=>ie(e),style:{borderBottom:`1px solid ${p.border}`,borderRadius:0},children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13},children:e.name}),(0,f.jsxs)(`div`,{style:{fontSize:10,color:p.textDim},children:[e.author,` · `,e.size_display,` · `,e.architecture]})]}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,children:`Get`})]},e.id))})]}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[a&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:6},children:`Loaded Model`}),(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,f.jsx)(`div`,{className:`nam-chip`,children:a}),(0,f.jsx)(`button`,{className:`btn btn-danger btn-sm`,onClick:E,children:`Unload`})]})]}),r.length===0?(0,f.jsxs)(`div`,{style:{textAlign:`center`,padding:30,color:p.textDim,fontSize:14},children:[`No NAM models found.`,(0,f.jsx)(`br`,{}),`Upload a .nam file or search Tone3000.`]}):r.map(e=>(0,f.jsxs)(`div`,{className:`preset-row ${e.loaded?`active`:``}`,children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13,fontWeight:500},children:e.name}),(0,f.jsxs)(`div`,{style:{fontSize:10,color:p.textDim},children:[e.architecture,` · `,e.size_mb,` MB`]})]}),e.loaded?(0,f.jsx)(`span`,{className:`badge badge-green`,children:`Loaded`}):(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>te(e.path),children:`Load`})]},e.name))]})]})}function ie({state:e,connected:t,refresh:n}){let[r,i]=(0,l.useState)([]),[a,o]=(0,l.useState)(null),[s,c]=(0,l.useState)(!0),[u,d]=(0,l.useState)(!1),[m,h]=(0,l.useState)(``),[v,y]=(0,l.useState)([]),[x,S]=(0,l.useState)(!1),[C,w]=(0,l.useState)(!1),ee=(0,l.useRef)(null),T=(0,l.useCallback)(async()=>{if(!t){c(!1);return}try{let e=await g(`/api/irs`);i(e.irs||[]),o(e.current)}catch{}c(!1)},[t]);(0,l.useEffect)(()=>{T()},[T]);let te=async e=>{try{await _(`/api/irs/load`,{path:e}),await T(),n()}catch{alert(`Failed to load IR`)}},E=async()=>{try{await _(`/api/irs/unload`),o(null),await T(),n()}catch{alert(`Failed to unload`)}},ne=async e=>{let t=e.target.files?.[0];if(t){w(!0);try{await b(`/api/irs/upload`,t),await T()}catch{alert(`Upload failed`)}w(!1)}},re=(0,l.useCallback)(async()=>{if(m.trim()){d(!0);try{y((await g(`/api/irs/tonedownload/search?q=${encodeURIComponent(m)}`)).results||[])}catch{alert(`Search failed`)}d(!1)}},[m]),ie=async e=>{try{await _(`/api/irs/tonedownload/install`,{download_url:e.download_url,name:e.name||e.filename,id:e.id,size:e.size,display_name:e.name}),await T(),n()}catch{alert(`Install failed`)}};return s?(0,f.jsx)(`div`,{style:{flex:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,f.jsx)(`div`,{className:`loader`})}):(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsxs)(`div`,{className:`screen-title`,children:[`IR Files (`,r.length,`)`]}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6},children:[(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>S(!x),children:x?`Local`:`Search`}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:()=>ee.current?.click(),children:C?`...`:`+ Upload`}),(0,f.jsx)(`input`,{ref:ee,type:`file`,accept:`.wav`,style:{display:`none`},onChange:ne})]})]}),x&&(0,f.jsxs)(`div`,{style:{padding:`8px 12px`,borderBottom:`1px solid ${p.border}`},children:[(0,f.jsxs)(`div`,{className:`search-bar`,children:[(0,f.jsx)(`span`,{style:{color:p.textDim},children:`🔍`}),(0,f.jsx)(`input`,{type:`text`,placeholder:`Search Tone3000 IRs…`,value:m,onChange:e=>h(e.target.value),onKeyDown:e=>e.key===`Enter`&&re()}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,onClick:re,disabled:u,children:u?`...`:`Go`})]}),v.length>0&&(0,f.jsx)(`div`,{style:{marginTop:8,maxHeight:240,overflow:`auto`},children:v.map(e=>(0,f.jsxs)(`div`,{className:`preset-row`,onClick:()=>ie(e),style:{borderBottom:`1px solid ${p.border}`,borderRadius:0},children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13},children:e.name}),(0,f.jsxs)(`div`,{style:{fontSize:10,color:p.textDim},children:[e.author,` · `,e.size_display]})]}),(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,children:`Get`})]},e.id))})]}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[a&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:6},children:`Loaded IR`}),(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,f.jsx)(`div`,{className:`nam-chip`,style:{color:p.green,borderColor:`${p.green}55`,background:`${p.green}15`},children:a}),(0,f.jsx)(`button`,{className:`btn btn-danger btn-sm`,onClick:E,children:`Unload`})]})]}),r.length===0?(0,f.jsxs)(`div`,{style:{textAlign:`center`,padding:30,color:p.textDim,fontSize:14},children:[`No IR files found.`,(0,f.jsx)(`br`,{}),`Upload a .wav file or search Tone3000.`]}):r.map(e=>(0,f.jsxs)(`div`,{className:`preset-row ${e.loaded?`active`:``}`,children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13,fontWeight:500},children:e.name}),(0,f.jsxs)(`div`,{style:{fontSize:10,color:p.textDim},children:[e.sample_rate,` Hz · `,e.length_ms,` ms · `,e.num_taps,` taps`]})]}),e.loaded?(0,f.jsx)(`span`,{className:`badge badge-green`,children:`Loaded`}):(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>te(e.path),children:`Load`})]},e.name))]})]})}function ae({state:e,connected:t,refresh:n}){let[r,i]=(0,l.useState)([]),[a,o]=(0,l.useState)(0),[s,c]=(0,l.useState)(!0),[u,d]=(0,l.useState)(``),[m,h]=(0,l.useState)(!1),[b,x]=(0,l.useState)(null),S=(0,l.useCallback)(async()=>{if(!t){i([{name:`Default`,number:0,presets:[{name:`Edge of Breakup`,bank:0,program:0},{name:`Modern High Gain`,bank:0,program:1},null,null]}]),c(!1);return}try{i((await g(`/api/presets`)).banks||[])}catch{}c(!1)},[t]);(0,l.useEffect)(()=>{S()},[S]);let C=async(e,t)=>{try{await _(`/api/presets/${e}/${t}/activate`),await S(),n()}catch{alert(`Failed to load preset`)}},w=async()=>{if(!u.trim())return;let t=e?.current_preset?.bank??0,n=e?.current_preset?.program??0;try{await v(`/api/presets/${t}/${n}`,{name:u}),h(!1),await S()}catch{alert(`Failed to save`)}},ee=async(e,t)=>{try{await y(`/api/presets/${e}/${t}`),x(null),await S()}catch{alert(`Failed to delete`)}};if(s)return(0,f.jsx)(`div`,{style:{flex:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,f.jsx)(`div`,{className:`loader`})});let T=e?.current_preset,E=r[a]?.presets||[];return(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsx)(`div`,{className:`screen-title`,children:`Presets`}),(0,f.jsx)(`div`,{style:{display:`flex`,gap:6},children:(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>h(!0),children:`Save`})})]}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[r.length>1&&(0,f.jsx)(`div`,{className:`toggle`,children:r.map((e,t)=>(0,f.jsx)(`button`,{className:`toggle-btn ${a===t?`active`:``}`,onClick:()=>o(t),children:e.name},e.number))}),T&&(0,f.jsx)(`div`,{className:`card-sm`,style:{display:`flex`,alignItems:`center`,gap:8},children:(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:11,color:p.textDim},children:`Current`}),(0,f.jsxs)(`div`,{style:{fontSize:14,fontWeight:600,color:p.amber},children:[T.name,(0,f.jsxs)(`span`,{className:`mono`,style:{fontSize:10,color:p.textDim,marginLeft:8},children:[`Bank `,T.bank,` · Prog `,T.program]})]})]})}),E.length===0?(0,f.jsx)(`div`,{style:{textAlign:`center`,padding:30,color:p.textDim,fontSize:14},children:`No presets in this bank.`}):E.map((e,t)=>{if(!e)return null;let n=T?.bank===e.bank&&T?.program===e.program,r=b===`${e.bank}-${e.program}`;return(0,f.jsxs)(`div`,{className:`preset-row ${n?`active`:``}`,onClick:()=>!r&&C(e.bank,e.program),children:[(0,f.jsx)(`div`,{className:`mono`,style:{width:28,height:28,borderRadius:6,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:12,fontWeight:700,background:n?`${p.amber}22`:p.surface,color:n?p.amber:p.textDim,border:`1px solid ${n?p.amber+`60`:p.border}`},children:e.program+1}),(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13,fontWeight:600},children:e.name}),(0,f.jsxs)(`div`,{style:{fontSize:10,color:p.textDim},children:[`Bank `,e.bank,` · Program `,e.program]})]}),n&&(0,f.jsx)(`span`,{style:{color:p.amber,fontSize:16},children:`●`}),r?(0,f.jsxs)(`div`,{style:{display:`flex`,gap:4},children:[(0,f.jsx)(`button`,{className:`btn btn-danger btn-sm`,onClick:t=>{t.stopPropagation(),ee(e.bank,e.program)},children:`Confirm`}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:e=>{e.stopPropagation(),x(null)},children:`Cancel`})]}):(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,style:{color:p.red},onClick:t=>{t.stopPropagation(),x(`${e.bank}-${e.program}`)},children:`Delete`})]},t)})]}),m&&(0,f.jsxs)(te,{onClose:()=>h(!1),children:[(0,f.jsx)(`div`,{className:`screen-header`,children:(0,f.jsx)(`div`,{className:`screen-title`,children:`Save Preset`})}),(0,f.jsxs)(`div`,{className:`screen-body`,children:[(0,f.jsx)(`div`,{className:`search-bar`,children:(0,f.jsx)(`input`,{type:`text`,placeholder:`Preset name…`,value:u,onChange:e=>d(e.target.value),autoFocus:!0,onKeyDown:e=>e.key===`Enter`&&w()})}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:8},children:[(0,f.jsx)(`button`,{className:`btn btn-primary`,style:{flex:1},onClick:w,children:`Save`}),(0,f.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>h(!1),children:`Cancel`})]})]})]})]})}function oe({state:e,connected:t,refresh:n}){let[r,i]=(0,l.useState)(`wifi`),[a,o]=(0,l.useState)([]),[s,c]=(0,l.useState)([]),[u,d]=(0,l.useState)([]),[m,h]=(0,l.useState)(!1),[v,y]=(0,l.useState)(!1),[b,x]=(0,l.useState)(``),[S,C]=(0,l.useState)(``),[w,ee]=(0,l.useState)(null),[T,te]=(0,l.useState)(e?.routing_mode||`mono`),[E,ne]=(0,l.useState)(e?.routing_breakpoint||7);(0,l.useEffect)(()=>{e?.routing_mode&&te(e.routing_mode),e?.routing_breakpoint!=null&&ne(e.routing_breakpoint)},[e?.routing_mode,e?.routing_breakpoint]);let re=async()=>{h(!0);try{o((await g(`/api/wifi/scan`)).networks||[])}catch{}h(!1)},ie=async(e,t)=>{try{await _(`/api/wifi/connect`,{ssid:e,password:t}),ee(null),x(``),C(``),setTimeout(n,2e3)}catch{alert(`Failed to connect`)}},ae=async()=>{try{await _(`/api/wifi/disconnect`),setTimeout(n,2e3)}catch{}},oe=async()=>{let t=e?.wifi?.hotspot_active;try{t?await _(`/api/wifi/hotspot/disable`):await _(`/api/wifi/hotspot/enable`,{ssid:`Pi-Pedal`,password:`pedal1234`}),setTimeout(n,2e3)}catch{}},se=async e=>{try{await _(`/api/bluetooth/power`,{on:e}),setTimeout(n,1e3)}catch{}},ce=async()=>{y(!0);try{c((await _(`/api/bluetooth/scan`)).devices||[])}catch{}y(!1)},D=async()=>{try{d((await g(`/api/bluetooth/paired`)).devices||[])}catch{}},O=async e=>{try{await _(`/api/bluetooth/pair`,{address:e}),await D()}catch{alert(`Pairing failed`)}},le=async(e,t)=>{try{await _(`/api/routing`,{routing_mode:e,routing_breakpoint:t})}catch{}};(0,l.useEffect)(()=>{t&&(re(),D())},[t]);let ue=e?.wifi,de=e?.bluetooth;return(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsx)(`div`,{className:`screen-header`,children:(0,f.jsx)(`div`,{className:`screen-title`,children:`Settings`})}),(0,f.jsx)(`div`,{className:`toggle`,style:{margin:`6px 10px`},children:[{id:`wifi`,label:`WiFi`},{id:`bt`,label:`Bluetooth`},{id:`routing`,label:`Routing`}].map(e=>(0,f.jsx)(`button`,{className:`toggle-btn ${r===e.id?`active`:``}`,onClick:()=>i(e.id),children:e.label},e.id))}),(0,f.jsxs)(`div`,{className:`screen-body`,style:{gap:4},children:[r===`wifi`&&(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsxs)(`div`,{className:`setting-row`,style:{border:`none`,paddingTop:0},children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`WiFi`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:ue?.connected?`Connected to ${ue.ssid}`:`Disconnected`})]}),(0,f.jsx)(`div`,{className:`switch ${ue?.connected?`on`:``}`,onClick:ae})]}),ue?.connected&&(0,f.jsxs)(`div`,{style:{fontSize:11,color:p.textDim},children:[`IP: `,ue.ip,` · Signal: `,ue.signal,`%`]}),(0,f.jsxs)(`div`,{className:`setting-row`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Hotspot`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:ue?.hotspot_active?`Active: ${ue.hotspot_ssid}`:`Off`})]}),(0,f.jsx)(`div`,{className:`switch ${ue?.hotspot_active?`on`:``}`,onClick:oe})]})]}),(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:8},children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:0},children:`Networks`}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:re,disabled:m,children:m?`...`:`Scan`})]}),a.length===0?(0,f.jsx)(`div`,{style:{fontSize:12,color:p.textDim,padding:`8px 0`},children:`Scan to see available networks.`}):a.map(e=>(0,f.jsxs)(`div`,{className:`preset-row`,style:{padding:`8px 0`,borderRadius:0,borderBottom:`1px solid ${p.border}`},onClick:()=>wpaState?.ssid!==e.ssid&&ee(e.ssid),children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13},children:e.ssid}),(0,f.jsxs)(`div`,{className:`mono`,style:{fontSize:10,color:p.textDim},children:[`Signal: `,e.signal,`% · `,e.encryption||`Open`]})]}),ue?.ssid===e.ssid&&(0,f.jsx)(`span`,{className:`badge badge-green`,children:`Connected`})]},e.ssid))]}),w&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsxs)(`div`,{className:`section-label`,children:[`Connect to `,w]}),(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:8},children:[(0,f.jsx)(`input`,{type:`password`,placeholder:`Password (leave blank for open network)`,value:S,onChange:e=>C(e.target.value),style:{background:p.surface,border:`1px solid ${p.border}`,borderRadius:6,padding:`8px 12px`,color:p.textPrimary,fontSize:13,outline:`none`},onKeyDown:e=>e.key===`Enter`&&ie(w,S)}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6},children:[(0,f.jsx)(`button`,{className:`btn btn-primary btn-sm`,style:{flex:1},onClick:()=>ie(w,S),children:`Connect`}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>ee(null),children:`Cancel`})]})]})]})]}),r===`bt`&&(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsxs)(`div`,{className:`setting-row`,style:{border:`none`,paddingTop:0},children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Bluetooth`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:de?.powered?`Powered on`:`Off`})]}),(0,f.jsx)(`div`,{className:`switch ${de?.powered?`on`:``}`,onClick:()=>se(!de?.powered)})]}),de?.powered&&(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`div`,{className:`setting-row`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Discoverable`}),(0,f.jsxs)(`div`,{className:`setting-desc`,children:[de?.name,` (`,de?.address,`)`]})]}),(0,f.jsx)(`div`,{className:`switch ${de?.discoverable?`on`:``}`,onClick:async()=>{try{await _(`/api/bluetooth/discoverable`,{on:!de?.discoverable}),setTimeout(n,500)}catch{}}})]}),(0,f.jsxs)(`div`,{className:`setting-row`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Bluetooth MIDI`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:de?.midi_enabled?`Enabled`:`Disabled`})]}),(0,f.jsx)(`div`,{className:`switch ${de?.midi_enabled?`on`:``}`,onClick:async()=>{try{await(de?.midi_enabled?_(`/api/bluetooth/midi-disable`):_(`/api/bluetooth/midi-enable`)),setTimeout(n,500)}catch{}}})]})]})]}),de?.powered&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:8},children:[(0,f.jsxs)(`div`,{className:`section-label`,style:{marginBottom:0},children:[`Paired Devices (`,u.length,`)`]}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:ce,disabled:v,children:v?`...`:`Scan`})]}),u.length===0?(0,f.jsx)(`div`,{style:{fontSize:12,color:p.textDim,padding:`8px 0`},children:`No paired devices.`}):u.map(e=>(0,f.jsxs)(`div`,{className:`preset-row`,style:{padding:`8px 0`,borderRadius:0,borderBottom:`1px solid ${p.border}`},children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13},children:e.name||e.address}),(0,f.jsxs)(`div`,{className:`mono`,style:{fontSize:10,color:p.textDim},children:[e.address,` · `,e.connected?`Connected`:`Paired`]})]}),!e.connected&&(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:async()=>{try{await _(`/api/bluetooth/connect`,{address:e.address})}catch{alert(`Failed`)}},children:`Connect`})]},e.address))]}),v&&s.length>0&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsx)(`div`,{className:`section-label`,style:{marginBottom:6},children:`Discovered`}),s.map(e=>(0,f.jsxs)(`div`,{className:`preset-row`,style:{padding:`8px 0`,borderRadius:0,borderBottom:`1px solid ${p.border}`},children:[(0,f.jsxs)(`div`,{style:{flex:1},children:[(0,f.jsx)(`div`,{style:{fontSize:13},children:e.name||e.address}),(0,f.jsx)(`div`,{className:`mono`,style:{fontSize:10,color:p.textDim},children:e.address})]}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,onClick:()=>O(e.address),children:`Pair`})]},e.address))]})]}),r===`routing`&&(0,f.jsxs)(`div`,{className:`card-sm`,children:[(0,f.jsx)(`div`,{className:`section-label`,children:`4CM Routing`}),(0,f.jsxs)(`div`,{className:`setting-row`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Mode`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:`Mono (normal) or 4CM (4-cable method)`})]}),(0,f.jsxs)(`select`,{value:T,onChange:e=>{te(e.target.value),le(e.target.value,E)},style:{background:p.surface,border:`1px solid ${p.border}`,borderRadius:6,padding:`6px 10px`,color:p.textPrimary,fontSize:13,outline:`none`},children:[(0,f.jsx)(`option`,{value:`mono`,children:`Mono`}),(0,f.jsx)(`option`,{value:`4cm`,children:`4CM`})]})]}),T===`4cm`&&(0,f.jsxs)(`div`,{className:`setting-row`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`setting-label`,children:`Breakpoint`}),(0,f.jsx)(`div`,{className:`setting-desc`,children:`Chain position for amp send/return`})]}),(0,f.jsx)(`input`,{type:`number`,min:1,max:15,value:E,onChange:e=>{let t=+e.target.value;ne(t),le(T,t)},style:{background:p.surface,border:`1px solid ${p.border}`,borderRadius:6,padding:`6px 10px`,color:p.textPrimary,fontSize:13,width:60,outline:`none`,textAlign:`center`}})]})]})]})]})}function se(){let[e,t]=(0,l.useState)(!1),[n,r]=(0,l.useState)(!1),[i,a]=(0,l.useState)(0),[o,s]=(0,l.useState)([{name:`Guitar 1`,color:p.amber,vol:80,pan:50,mute:!1,solo:!1,level:72},{name:`Guitar 2`,color:p.blue,vol:65,pan:35,mute:!1,solo:!1,level:55},{name:`Bass DI`,color:p.green,vol:75,pan:50,mute:!0,solo:!1,level:68},{name:`Drum Loop`,color:`#A060E0`,vol:70,pan:52,mute:!1,solo:!1,level:60}]);(0,l.useEffect)(()=>{let t;return e&&(t=setInterval(()=>a(e=>e>=100?0:e+.3),80)),()=>clearInterval(t)},[e]),(0,l.useEffect)(()=>{let e=setInterval(()=>{s(e=>e.map(e=>({...e,level:e.mute?0:Math.max(10,Math.min(95,e.level+(Math.random()-.48)*12))})))},90);return()=>clearInterval(e)},[]);let c=e=>s(t=>t.map((t,n)=>n===e?{...t,mute:!t.mute}:t)),u=e=>s(t=>t.map((t,n)=>n===e?{...t,solo:!t.solo}:t)),d=(e,t)=>s(n=>n.map((n,r)=>r===e?{...n,vol:t}:n));return(0,f.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,f.jsxs)(`div`,{className:`screen-header`,children:[(0,f.jsxs)(`div`,{children:[(0,f.jsx)(`div`,{className:`screen-title`,children:`Multitrack`}),(0,f.jsxs)(`div`,{className:`mono`,style:{fontSize:12,color:p.textSec,marginTop:2},children:[Math.floor(i/100*32).toString().padStart(2,`0`),`:`,Math.floor(i/100*32%1*60).toString().padStart(2,`0`)]})]}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:8,alignItems:`center`},children:[(0,f.jsx)(`div`,{className:`transport-btn`,onClick:()=>a(0),children:`⏮`}),(0,f.jsx)(`div`,{className:`transport-btn ${n?`rec`:``}`,onClick:()=>{r(e=>!e),n||t(!0)},children:(0,f.jsx)(`div`,{style:{width:14,height:14,borderRadius:n?3:`50%`,background:n?p.red:p.textSec,boxShadow:n?`0 0 12px ${p.red}`:`none`}})}),(0,f.jsx)(`div`,{className:`transport-btn ${e?`play`:``}`,onClick:()=>t(e=>!e),children:e?`⏸`:`▶`})]})]}),(0,f.jsx)(`div`,{style:{flex:1,overflow:`hidden`,display:`flex`,flexDirection:`column`},children:o.map((e,t)=>(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6,padding:`6px 10px`,borderBottom:`1px solid ${p.border}`,alignItems:`center`},children:[(0,f.jsx)(`div`,{style:{width:4,alignSelf:`stretch`,borderRadius:2,background:e.mute?p.textDim:e.color,flexShrink:0,opacity:e.mute?.4:1}}),(0,f.jsxs)(`div`,{style:{width:60,flexShrink:0},children:[(0,f.jsx)(`div`,{style:{fontSize:11,fontWeight:600,color:e.mute?p.textDim:p.textPrimary,marginBottom:2,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`},children:e.name}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:3},children:[(0,f.jsx)(`div`,{onClick:()=>c(t),style:{padding:`1px 4px`,borderRadius:3,fontSize:9,fontWeight:700,cursor:`pointer`,background:e.mute?`${p.red}33`:p.surface,color:e.mute?p.red:p.textDim,border:`1px solid ${e.mute?p.red+`60`:p.border}`},children:`M`}),(0,f.jsx)(`div`,{onClick:()=>u(t),style:{padding:`1px 4px`,borderRadius:3,fontSize:9,fontWeight:700,cursor:`pointer`,background:e.solo?`${p.amber}33`:p.surface,color:e.solo?p.amber:p.textDim,border:`1px solid ${e.solo?p.amber+`60`:p.border}`},children:`S`})]})]}),(0,f.jsx)(`div`,{style:{flex:1,overflow:`hidden`},children:(0,f.jsx)(ee,{width:120,height:36,color:e.mute?p.textDim:e.color,playPos:i,seed:t+1})}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:4,alignItems:`center`,flexShrink:0},children:[(0,f.jsx)(w,{level:e.level,height:36}),(0,f.jsx)(`input`,{type:`range`,min:0,max:100,value:e.vol,onChange:e=>d(t,+e.target.value),style:{writingMode:`vertical-lr`,direction:`rtl`,height:40,width:20,accentColor:e.color,cursor:`pointer`}})]})]},t))}),(0,f.jsxs)(`div`,{style:{padding:`8px 10px`,borderTop:`1px solid ${p.border}`,display:`flex`,gap:10,alignItems:`center`,background:p.panel},children:[(0,f.jsx)(`div`,{style:{fontSize:10,fontWeight:600,color:p.textSec,width:44},children:`MASTER`}),(0,f.jsx)(`div`,{style:{flex:1},children:(0,f.jsx)(w,{level:68,vertical:!1,height:120})}),(0,f.jsx)(`div`,{className:`mono`,style:{fontSize:10,color:p.green},children:`-4.2 dBFS`}),(0,f.jsx)(`button`,{className:`btn btn-ghost btn-sm`,children:`Export`})]})]})}var ce=[{id:`rig`,label:`Rig`,icon:`🎛`},{id:`fx`,label:`FX Chain`,icon:`⛓`},{id:`models`,label:`Models`,icon:`📁`},{id:`irs`,label:`IRs`,icon:`🎚`},{id:`presets`,label:`Presets`,icon:`⭐`},{id:`settings`,label:`Settings`,icon:`⚙`},{id:`record`,label:`Record`,icon:`🎙`}];function D(){let[e,t]=(0,l.useState)(`rig`),{state:n,connected:r,refresh:i}=x();return(0,l.useEffect)(()=>{document.title=`Pi Multi-FX Pedal`},[]),(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(`style`,{children:S}),(0,f.jsxs)(`div`,{style:{width:`100%`,maxWidth:440,margin:`0 auto`,height:`100dvh`,display:`flex`,flexDirection:`column`,background:p.bg,overflow:`hidden`,fontFamily:`'Inter', sans-serif`},children:[(0,f.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`6px 12px 4px`,background:p.panel,borderBottom:`1px solid ${p.border}`,flexShrink:0},children:[(0,f.jsxs)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`},children:[(0,f.jsx)(`div`,{style:{width:6,height:6,borderRadius:`50%`,background:r?p.green:p.red,boxShadow:r?`0 0 6px ${p.green}`:`none`}}),(0,f.jsx)(`span`,{className:`mono`,style:{fontSize:9,color:p.textSec},children:`PI MULTI-FX`})]}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:10,alignItems:`center`},children:[n?.bypass&&(0,f.jsx)(`span`,{className:`badge badge-red`,children:`BYP`}),n?.tuner_enabled&&(0,f.jsx)(`span`,{className:`badge badge-amber`,children:`TUNER`}),n?.nam_loaded&&(0,f.jsx)(`span`,{className:`badge badge-blue`,children:`NAM`}),n?.ir_loaded&&(0,f.jsx)(`span`,{className:`badge badge-green`,children:`IR`})]})]}),(0,f.jsxs)(`div`,{style:{flex:1,overflow:`hidden`,display:`flex`,flexDirection:`column`},children:[e===`rig`&&(0,f.jsx)(E,{state:n,connected:r}),e===`fx`&&(0,f.jsx)(ne,{state:n,connected:r}),e===`models`&&(0,f.jsx)(re,{state:n,connected:r,refresh:i}),e===`irs`&&(0,f.jsx)(ie,{state:n,connected:r,refresh:i}),e===`presets`&&(0,f.jsx)(ae,{state:n,connected:r,refresh:i}),e===`settings`&&(0,f.jsx)(oe,{state:n,connected:r,refresh:i}),e===`record`&&(0,f.jsx)(se,{})]}),(0,f.jsx)(`div`,{className:`tabbar`,children:ce.map(n=>(0,f.jsxs)(`div`,{className:`tab ${e===n.id?`active`:``}`,onClick:()=>t(n.id),children:[(0,f.jsx)(`span`,{style:{fontSize:14,display:`block`},children:n.icon}),n.label]},n.id))})]})]})}(0,u.createRoot)(document.getElementById(`root`)).render((0,f.jsx)(l.StrictMode,{children:(0,f.jsx)(D,{})})); \ No newline at end of file diff --git a/src/web/ui-dist/assets/index-CuJgR-s6.css b/src/web/ui-dist/assets/index-CuJgR-s6.css new file mode 100644 index 0000000..7d048c4 --- /dev/null +++ b/src/web/ui-dist/assets/index-CuJgR-s6.css @@ -0,0 +1 @@ +*{box-sizing:border-box;margin:0;padding:0}body{color:#f0ede6;background:#0a0a0c} diff --git a/src/web/ui-dist/favicon.svg b/src/web/ui-dist/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/src/web/ui-dist/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/web/ui-dist/icons.svg b/src/web/ui-dist/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/src/web/ui-dist/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/web/ui-dist/index.html b/src/web/ui-dist/index.html new file mode 100644 index 0000000..1fe185a --- /dev/null +++ b/src/web/ui-dist/index.html @@ -0,0 +1,14 @@ + + + + + + + Pi Multi-FX Pedal + + + + +
+ +