diff --git a/web_app/.eslintrc.cjs b/web_app/.eslintrc.cjs
new file mode 100644
index 0000000..d6c9537
--- /dev/null
+++ b/web_app/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parser: '@typescript-eslint/parser',
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/web_app/.gitignore b/web_app/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/web_app/.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/web_app/README.md b/web_app/README.md
new file mode 100644
index 0000000..0d6babe
--- /dev/null
+++ b/web_app/README.md
@@ -0,0 +1,30 @@
+# React + TypeScript + 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/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
+
+- Configure the top-level `parserOptions` property like this:
+
+```js
+export default {
+ // other rules...
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ project: ['./tsconfig.json', './tsconfig.node.json'],
+ tsconfigRootDir: __dirname,
+ },
+}
+```
+
+- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
+- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
+- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
diff --git a/web_app/components.json b/web_app/components.json
new file mode 100644
index 0000000..0cc3425
--- /dev/null
+++ b/web_app/components.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "app/globals.css",
+ "baseColor": "gray",
+ "cssVariables": true
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils"
+ }
+}
\ No newline at end of file
diff --git a/web_app/index.html b/web_app/index.html
new file mode 100644
index 0000000..e4b78ea
--- /dev/null
+++ b/web_app/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React + TS
+
+
+
+
+
+
diff --git a/web_app/package-lock.json b/web_app/package-lock.json
new file mode 100644
index 0000000..90627ca
--- /dev/null
+++ b/web_app/package-lock.json
@@ -0,0 +1,5775 @@
+{
+ "name": "web_app",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "web_app",
+ "version": "0.0.0",
+ "dependencies": {
+ "@heroicons/react": "^2.0.18",
+ "@radix-ui/react-accordion": "^1.1.2",
+ "@radix-ui/react-dialog": "^1.0.5",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.0.7",
+ "@radix-ui/react-scroll-area": "^1.0.5",
+ "@radix-ui/react-select": "^2.0.0",
+ "@radix-ui/react-slider": "^1.1.2",
+ "@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-switch": "^1.0.3",
+ "@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toast": "^1.1.5",
+ "@radix-ui/react-toggle": "^1.0.3",
+ "@radix-ui/react-tooltip": "^1.0.7",
+ "@uidotdev/usehooks": "^2.4.1",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.0.0",
+ "flexsearch": "^0.7.21",
+ "lodash": "^4.17.21",
+ "lucide-react": "^0.292.0",
+ "mitt": "^3.0.1",
+ "next-themes": "^0.2.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hotkeys-hook": "^4.4.1",
+ "react-photo-album": "^2.3.0",
+ "react-use": "^17.4.0",
+ "react-zoom-pan-pinch": "^3.3.0",
+ "recoil": "^0.7.7",
+ "tailwind-merge": "^2.0.0",
+ "tailwindcss-animate": "^1.0.7"
+ },
+ "devDependencies": {
+ "@types/flexsearch": "^0.7.3",
+ "@types/lodash": "^4.14.201",
+ "@types/node": "^20.9.2",
+ "@types/react": "^18.2.37",
+ "@types/react-dom": "^18.2.15",
+ "@typescript-eslint/eslint-plugin": "^6.10.0",
+ "@typescript-eslint/parser": "^6.10.0",
+ "@vitejs/plugin-react": "^4.2.0",
+ "@vitejs/plugin-react-swc": "^3.5.0",
+ "autoprefixer": "^10.4.16",
+ "eslint": "^8.53.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.4",
+ "postcss": "^8.4.31",
+ "tailwindcss": "^3.3.5",
+ "typescript": "^5.2.2",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+ "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz",
+ "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz",
+ "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.3",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.23.3",
+ "@babel/helpers": "^7.23.2",
+ "@babel/parser": "^7.23.3",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.3",
+ "@babel/types": "^7.23.3",
+ "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/core/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,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz",
+ "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.23.3",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+ "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.22.9",
+ "@babel/helper-validator-option": "^7.22.15",
+ "browserslist": "^4.21.9",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/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,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/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,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.22.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.22.15"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
+ "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-simple-access": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/helper-validator-identifier": "^7.22.20"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
+ "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+ "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.22.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.22.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+ "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
+ "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
+ "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz",
+ "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.22.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz",
+ "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.22.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
+ "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz",
+ "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.3",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.3",
+ "@babel/types": "^7.23.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz",
+ "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.6.tgz",
+ "integrity": "sha512-muPzBqXJKCbMYoNbb1JpZh/ynl0xS6/+pLjrofcR3Nad82SbsCogYzUE6Aq9QT3cLP0jR/IVK/NHC9b90mSHtg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.6.tgz",
+ "integrity": "sha512-KQ/hbe9SJvIJ4sR+2PcZ41IBV+LPJyYp6V1K1P1xcMRup9iYsBoQn4MzE3mhMLOld27Au2eDcLlIREeKGUXpHQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.6.tgz",
+ "integrity": "sha512-VVJVZQ7p5BBOKoNxd0Ly3xUM78Y4DyOoFKdkdAe2m11jbh0LEU4bPles4e/72EMl4tapko8o915UalN/5zhspg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.6.tgz",
+ "integrity": "sha512-91LoRp/uZAKx6ESNspL3I46ypwzdqyDLXZH7x2QYCLgtnaU08+AXEbabY2yExIz03/am0DivsTtbdxzGejfXpA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.6.tgz",
+ "integrity": "sha512-QCGHw770ubjBU1J3ZkFJh671MFajGTYMZumPs9E/rqU52md6lIil97BR0CbPq6U+vTh3xnTNDHKRdR8ggHnmxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.6.tgz",
+ "integrity": "sha512-J53d0jGsDcLzWk9d9SPmlyF+wzVxjXpOH7jVW5ae7PvrDst4kiAz6sX+E8btz0GB6oH12zC+aHRD945jdjF2Vg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.6.tgz",
+ "integrity": "sha512-hn9qvkjHSIB5Z9JgCCjED6YYVGCNpqB7dEGavBdG6EjBD8S/UcNUIlGcB35NCkMETkdYwfZSvD9VoDJX6VeUVA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.6.tgz",
+ "integrity": "sha512-G8IR5zFgpXad/Zp7gr7ZyTKyqZuThU6z1JjmRyN1vSF8j0bOlGzUwFSMTbctLAdd7QHpeyu0cRiuKrqK1ZTwvQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.6.tgz",
+ "integrity": "sha512-HQCOrk9XlH3KngASLaBfHpcoYEGUt829A9MyxaI8RMkfRA8SakG6YQEITAuwmtzFdEu5GU4eyhKcpv27dFaOBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.6.tgz",
+ "integrity": "sha512-22eOR08zL/OXkmEhxOfshfOGo8P69k8oKHkwkDrUlcB12S/sw/+COM4PhAPT0cAYW/gpqY2uXp3TpjQVJitz7w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.6.tgz",
+ "integrity": "sha512-82RvaYAh/SUJyjWA8jDpyZCHQjmEggL//sC7F3VKYcBMumQjUL3C5WDl/tJpEiKtt7XrWmgjaLkrk205zfvwTA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.6.tgz",
+ "integrity": "sha512-8tvnwyYJpR618vboIv2l8tK2SuK/RqUIGMfMENkeDGo3hsEIrpGldMGYFcWxWeEILe5Fi72zoXLmhZ7PR23oQA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.6.tgz",
+ "integrity": "sha512-Qt+D7xiPajxVNk5tQiEJwhmarNnLPdjXAoA5uWMpbfStZB0+YU6a3CtbWYSy+sgAsnyx4IGZjWsTzBzrvg/fMA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.6.tgz",
+ "integrity": "sha512-lxRdk0iJ9CWYDH1Wpnnnc640ajF4RmQ+w6oHFZmAIYu577meE9Ka/DCtpOrwr9McMY11ocbp4jirgGgCi7Ls/g==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.6.tgz",
+ "integrity": "sha512-MopyYV39vnfuykHanRWHGRcRC3AwU7b0QY4TI8ISLfAGfK+tMkXyFuyT1epw/lM0pflQlS53JoD22yN83DHZgA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.6.tgz",
+ "integrity": "sha512-UWcieaBzsN8WYbzFF5Jq7QULETPcQvlX7KL4xWGIB54OknXJjBO37sPqk7N82WU13JGWvmDzFBi1weVBajPovg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.6.tgz",
+ "integrity": "sha512-EpWiLX0fzvZn1wxtLxZrEW+oQED9Pwpnh+w4Ffv8ZLuMhUoqR9q9rL4+qHW8F4Mg5oQEKxAoT0G+8JYNqCiR6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.6.tgz",
+ "integrity": "sha512-fFqTVEktM1PGs2sLKH4M5mhAVEzGpeZJuasAMRnvDZNCV0Cjvm1Hu35moL2vC0DOrAQjNTvj4zWrol/lwQ8Deg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.6.tgz",
+ "integrity": "sha512-M+XIAnBpaNvaVAhbe3uBXtgWyWynSdlww/JNZws0FlMPSBy+EpatPXNIlKAdtbFVII9OpX91ZfMb17TU3JKTBA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.6.tgz",
+ "integrity": "sha512-2DchFXn7vp/B6Tc2eKdTsLzE0ygqKkNUhUBCNtMx2Llk4POIVMUq5rUYjdcedFlGLeRe1uLCpVvCmE+G8XYybA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.6.tgz",
+ "integrity": "sha512-PBo/HPDQllyWdjwAVX+Gl2hH0dfBydL97BAH/grHKC8fubqp02aL4S63otZ25q3sBdINtOBbz1qTZQfXbP4VBg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.6.tgz",
+ "integrity": "sha512-OE7yIdbDif2kKfrGa+V0vx/B3FJv2L4KnIiLlvtibPyO9UkgO3rzYE0HhpREo2vmJ1Ixq1zwm9/0er+3VOSZJA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
+ "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
+ "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
+ "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@floating-ui/core": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz",
+ "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==",
+ "dependencies": {
+ "@floating-ui/utils": "^0.1.3"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz",
+ "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==",
+ "dependencies": {
+ "@floating-ui/core": "^1.4.2",
+ "@floating-ui/utils": "^0.1.3"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz",
+ "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==",
+ "dependencies": {
+ "@floating-ui/dom": "^1.5.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz",
+ "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A=="
+ },
+ "node_modules/@heroicons/react": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz",
+ "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==",
+ "peerDependencies": {
+ "react": ">= 16"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.13",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
+ "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.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,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
+ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+ "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.20",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
+ "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.3.tgz",
+ "integrity": "sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA==",
+ "peer": true
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.3.tgz",
+ "integrity": "sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz",
+ "integrity": "sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz",
+ "integrity": "sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz",
+ "integrity": "sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz",
+ "integrity": "sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz",
+ "integrity": "sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz",
+ "integrity": "sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-ia32-msvc": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz",
+ "integrity": "sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz",
+ "integrity": "sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@radix-ui/number": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
+ "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ }
+ },
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
+ "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ }
+ },
+ "node_modules/@radix-ui/react-accordion": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz",
+ "integrity": "sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collapsible": "1.0.3",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz",
+ "integrity": "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collapsible": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz",
+ "integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
+ "integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
+ "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
+ "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
+ "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
+ "integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz",
+ "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-escape-keydown": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
+ "integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz",
+ "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-icons": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
+ "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==",
+ "peerDependencies": {
+ "react": "^16.x || ^17.x || ^18.x"
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
+ "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
+ "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popover": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.7.tgz",
+ "integrity": "sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-popper": "1.1.3",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz",
+ "integrity": "sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-use-rect": "1.0.1",
+ "@radix-ui/react-use-size": "1.0.1",
+ "@radix-ui/rect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz",
+ "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
+ "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
+ "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-slot": "1.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
+ "integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.5.tgz",
+ "integrity": "sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/number": "1.0.1",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-select": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.0.0.tgz",
+ "integrity": "sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/number": "1.0.1",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-popper": "1.1.3",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-use-previous": "1.0.1",
+ "@radix-ui/react-visually-hidden": "1.0.3",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slider": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz",
+ "integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/number": "1.0.1",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-use-previous": "1.0.1",
+ "@radix-ui/react-use-size": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
+ "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-switch": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.3.tgz",
+ "integrity": "sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-previous": "1.0.1",
+ "@radix-ui/react-use-size": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tabs": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz",
+ "integrity": "sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-roving-focus": "1.0.4",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz",
+ "integrity": "sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-visually-hidden": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
+ "integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tooltip": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
+ "integrity": "sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-popper": "1.1.3",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-visually-hidden": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
+ "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
+ "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz",
+ "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
+ "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-previous": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz",
+ "integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz",
+ "integrity": "sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/rect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz",
+ "integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz",
+ "integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/rect": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
+ "integrity": "sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.0.tgz",
+ "integrity": "sha512-OINaBGY+Wc++U0rdr7BLuFClxcoWaVW3vQYqmQq6B3bqQ/2olkaoz+K8+af/Mmka/C2yN5j+L9scBkv4BtKsDA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.0.tgz",
+ "integrity": "sha512-UdMf1pOQc4ZmUA/NTmKhgJTBimbSKnhPS2zJqucqFyBRFPnPDtwA8MzrGNTjDeQbIAWfpJVAlxejw+/lQyBK/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.0.tgz",
+ "integrity": "sha512-L0/CA5p/idVKI+c9PcAPGorH6CwXn6+J0Ys7Gg1axCbTPgI8MeMlhA6fLM9fK+ssFhqogMHFC8HDvZuetOii7w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.0.tgz",
+ "integrity": "sha512-QZCbVqU26mNlLn8zi/XDDquNmvcr4ON5FYAHQQsyhrHx8q+sQi/6xduoznYXwk/KmKIXG5dLfR0CvY+NAWpFYQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.0.tgz",
+ "integrity": "sha512-VpSQ+xm93AeV33QbYslgf44wc5eJGYfYitlQzAi3OObu9iwrGXEnmu5S3ilkqE3Pr/FkgOiJKV/2p0ewf4Hrtg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.0.tgz",
+ "integrity": "sha512-OrEyIfpxSsMal44JpEVx9AEcGpdBQG1ZuWISAanaQTSMeStBW+oHWwOkoqR54bw3x8heP8gBOyoJiGg+fLY8qQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.0.tgz",
+ "integrity": "sha512-1H7wBbQuE6igQdxMSTjtFfD+DGAudcYWhp106z/9zBA8OQhsJRnemO4XGavdzHpGhRtRxbgmUGdO3YQgrWf2RA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.0.tgz",
+ "integrity": "sha512-FVyFI13tXw5aE65sZdBpNjPVIi4Q5mARnL/39UIkxvSgRAIqCo5sCpCELk0JtXHGee2owZz5aNLbWNfBHzr71Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.0.tgz",
+ "integrity": "sha512-eBPYl2sLpH/o8qbSz6vPwWlDyThnQjJfcDOGFbNjmjb44XKC1F5dQfakOsADRVrXCNzM6ZsSIPDG5dc6HHLNFg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.0.tgz",
+ "integrity": "sha512-xaOHIfLOZypoQ5U2I6rEaugS4IYtTgP030xzvrBf5js7p9WI9wik07iHmsKaej8Z83ZDxN5GyypfoyKV5O5TJA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.0.tgz",
+ "integrity": "sha512-Al6quztQUrHwcOoU2TuFblUQ5L+/AmPBXFR6dUvyo4nRj2yQRK0WIUaGMF/uwKulvRcXkpHe3k9A8Vf93VDktA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.0.tgz",
+ "integrity": "sha512-8kdW+brNhI/NzJ4fxDufuJUjepzINqJKLGHuxyAtpPG9bMbn8P5mtaCcbOm0EzLJ+atg+kF9dwg8jpclkVqx5w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@swc/core": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.96.tgz",
+ "integrity": "sha512-zwE3TLgoZwJfQygdv2SdCK9mRLYluwDOM53I+dT6Z5ZvrgVENmY3txvWDvduzkV+/8IuvrRbVezMpxcojadRdQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@swc/counter": "^0.1.1",
+ "@swc/types": "^0.1.5"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.3.96",
+ "@swc/core-darwin-x64": "1.3.96",
+ "@swc/core-linux-arm-gnueabihf": "1.3.96",
+ "@swc/core-linux-arm64-gnu": "1.3.96",
+ "@swc/core-linux-arm64-musl": "1.3.96",
+ "@swc/core-linux-x64-gnu": "1.3.96",
+ "@swc/core-linux-x64-musl": "1.3.96",
+ "@swc/core-win32-arm64-msvc": "1.3.96",
+ "@swc/core-win32-ia32-msvc": "1.3.96",
+ "@swc/core-win32-x64-msvc": "1.3.96"
+ },
+ "peerDependencies": {
+ "@swc/helpers": "^0.5.0"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.96.tgz",
+ "integrity": "sha512-8hzgXYVd85hfPh6mJ9yrG26rhgzCmcLO0h1TIl8U31hwmTbfZLzRitFQ/kqMJNbIBCwmNH1RU2QcJnL3d7f69A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.96.tgz",
+ "integrity": "sha512-mFp9GFfuPg+43vlAdQZl0WZpZSE8sEzqL7sr/7Reul5McUHP0BaLsEzwjvD035ESfkY8GBZdLpMinblIbFNljQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.96.tgz",
+ "integrity": "sha512-8UEKkYJP4c8YzYIY/LlbSo8z5Obj4hqcv/fUTHiEePiGsOddgGf7AWjh56u7IoN/0uEmEro59nc1ChFXqXSGyg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.96.tgz",
+ "integrity": "sha512-c/IiJ0s1y3Ymm2BTpyC/xr6gOvoqAVETrivVXHq68xgNms95luSpbYQ28rqaZC8bQC8M5zdXpSc0T8DJu8RJGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.96.tgz",
+ "integrity": "sha512-i5/UTUwmJLri7zhtF6SAo/4QDQJDH2fhYJaBIUhrICmIkRO/ltURmpejqxsM/ye9Jqv5zG7VszMC0v/GYn/7BQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.96.tgz",
+ "integrity": "sha512-USdaZu8lTIkm4Yf9cogct/j5eqtdZqTgcTib4I+NloUW0E/hySou3eSyp3V2UAA1qyuC72ld1otXuyKBna0YKQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.96.tgz",
+ "integrity": "sha512-QYErutd+G2SNaCinUVobfL7jWWjGTI0QEoQ6hqTp7PxCJS/dmKmj3C5ZkvxRYcq7XcZt7ovrYCTwPTHzt6lZBg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.96.tgz",
+ "integrity": "sha512-hjGvvAduA3Un2cZ9iNP4xvTXOO4jL3G9iakhFsgVhpkU73SGmK7+LN8ZVBEu4oq2SUcHO6caWvnZ881cxGuSpg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.96.tgz",
+ "integrity": "sha512-Far2hVFiwr+7VPCM2GxSmbh3ikTpM3pDombE+d69hkedvYHYZxtTF+2LTKl/sXtpbUnsoq7yV/32c9R/xaaWfw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.3.96",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.96.tgz",
+ "integrity": "sha512-4VbSAniIu0ikLf5mBX81FsljnfqjoVGleEkCQv4+zRlyZtO3FHoDPkeLVoy6WRlj7tyrRcfUJ4mDdPkbfTO14g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
+ "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==",
+ "dev": true
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
+ "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@swc/types": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz",
+ "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==",
+ "dev": true
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz",
+ "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.6.7",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz",
+ "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.20.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz",
+ "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.20.7"
+ }
+ },
+ "node_modules/@types/flexsearch": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/@types/flexsearch/-/flexsearch-0.7.6.tgz",
+ "integrity": "sha512-H5IXcRn96/gaDmo+rDl2aJuIJsob8dgOXDqf8K0t8rWZd1AFNaaspmRsElESiU+EWE33qfbFPgI0OC/B1g9FCA==",
+ "dev": true
+ },
+ "node_modules/@types/js-cookie": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
+ "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
+ },
+ "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
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.14.201",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.201.tgz",
+ "integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "20.9.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
+ "integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.10",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz",
+ "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==",
+ "devOptional": true
+ },
+ "node_modules/@types/react": {
+ "version": "18.2.37",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz",
+ "integrity": "sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==",
+ "devOptional": true,
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.2.15",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz",
+ "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==",
+ "devOptional": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/scheduler": {
+ "version": "0.16.6",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz",
+ "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==",
+ "devOptional": true
+ },
+ "node_modules/@types/semver": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
+ "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
+ "dev": true
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
+ "integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.5.1",
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/type-utils": "6.11.0",
+ "@typescript-eslint/utils": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
+ "debug": "^4.3.4",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.4",
+ "natural-compare": "^1.4.0",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
+ "integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
+ "integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
+ "integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/utils": "6.11.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
+ "integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
+ "dev": true,
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
+ "integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
+ "integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@types/json-schema": "^7.0.12",
+ "@types/semver": "^7.5.0",
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.11.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
+ "integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.11.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@uidotdev/usehooks": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz",
+ "integrity": "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==",
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz",
+ "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.23.3",
+ "@babel/plugin-transform-react-jsx-self": "^7.23.3",
+ "@babel/plugin-transform-react-jsx-source": "^7.23.3",
+ "@types/babel__core": "^7.20.4",
+ "react-refresh": "^0.14.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react-swc": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz",
+ "integrity": "sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==",
+ "dev": true,
+ "dependencies": {
+ "@swc/core": "^1.3.96"
+ },
+ "peerDependencies": {
+ "vite": "^4 || ^5"
+ }
+ },
+ "node_modules/@xobotyi/scrollbar-width": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz",
+ "integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="
+ },
+ "node_modules/acorn": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
+ "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
+ "dev": true,
+ "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,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/aria-hidden": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz",
+ "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.16",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
+ "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.21.10",
+ "caniuse-lite": "^1.0.30001538",
+ "fraction.js": "^4.3.6",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.0",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
+ "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==",
+ "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"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001541",
+ "electron-to-chromium": "^1.4.535",
+ "node-releases": "^2.0.13",
+ "update-browserslist-db": "^1.0.13"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "peer": true,
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001563",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz",
+ "integrity": "sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==",
+ "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"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/class-variance-authority": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz",
+ "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==",
+ "dependencies": {
+ "clsx": "2.0.0"
+ },
+ "funding": {
+ "url": "https://joebell.co.uk"
+ }
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "peer": true
+ },
+ "node_modules/clsx": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+ "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "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
+ },
+ "node_modules/copy-to-clipboard": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+ "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+ "dependencies": {
+ "toggle-selection": "^1.0.6"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-in-js-utils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+ "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+ "dependencies": {
+ "hyphenate-style-name": "^1.0.3"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+ "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+ "dependencies": {
+ "mdn-data": "2.0.14",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "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
+ },
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.588",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz",
+ "integrity": "sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w==",
+ "dev": true
+ },
+ "node_modules/error-stack-parser": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+ "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
+ "dependencies": {
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.19.6",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.6.tgz",
+ "integrity": "sha512-Xl7dntjA2OEIvpr9j0DVxxnog2fyTGnyVoQXAMQI6eR3mf9zCQds7VIKUDCotDgE/p4ncTgeRqgX8t5d6oP4Gw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.19.6",
+ "@esbuild/android-arm64": "0.19.6",
+ "@esbuild/android-x64": "0.19.6",
+ "@esbuild/darwin-arm64": "0.19.6",
+ "@esbuild/darwin-x64": "0.19.6",
+ "@esbuild/freebsd-arm64": "0.19.6",
+ "@esbuild/freebsd-x64": "0.19.6",
+ "@esbuild/linux-arm": "0.19.6",
+ "@esbuild/linux-arm64": "0.19.6",
+ "@esbuild/linux-ia32": "0.19.6",
+ "@esbuild/linux-loong64": "0.19.6",
+ "@esbuild/linux-mips64el": "0.19.6",
+ "@esbuild/linux-ppc64": "0.19.6",
+ "@esbuild/linux-riscv64": "0.19.6",
+ "@esbuild/linux-s390x": "0.19.6",
+ "@esbuild/linux-x64": "0.19.6",
+ "@esbuild/netbsd-x64": "0.19.6",
+ "@esbuild/openbsd-x64": "0.19.6",
+ "@esbuild/sunos-x64": "0.19.6",
+ "@esbuild/win32-arm64": "0.19.6",
+ "@esbuild/win32-ia32": "0.19.6",
+ "@esbuild/win32-x64": "0.19.6"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "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,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
+ "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.3",
+ "@eslint/js": "8.54.0",
+ "@humanwhocodes/config-array": "^0.11.13",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
+ "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.4.tgz",
+ "integrity": "sha512-eD83+65e8YPVg6603Om2iCIwcQJf/y7++MWm4tACtEswFLYMwxwVWAfwN+e19f5Ad/FOyyNg9Dfi5lXhH3Y3rA==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=7"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "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,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "dev": true,
+ "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,
+ "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,
+ "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,
+ "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=="
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "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
+ },
+ "node_modules/fast-loops": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz",
+ "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g=="
+ },
+ "node_modules/fast-shallow-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz",
+ "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw=="
+ },
+ "node_modules/fastest-stable-stringify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz",
+ "integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q=="
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "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": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.9",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
+ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
+ "dev": true
+ },
+ "node_modules/flexsearch": {
+ "version": "0.7.31",
+ "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.31.tgz",
+ "integrity": "sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA=="
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "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==",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "peer": true
+ },
+ "node_modules/globals": {
+ "version": "13.23.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
+ "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "peer": true
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "node_modules/hamt_plus": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
+ "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA=="
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
+ "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hyphenate-style-name": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
+ "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
+ },
+ "node_modules/ignore": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
+ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/inline-style-prefixer": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.0.tgz",
+ "integrity": "sha512-I7GEdScunP1dQ6IM2mQWh6v0mOYdYmH3Bp31UecKdrcUgcURTcctSe1IECdUznSHKSmsHtjrT3CwCPI1pyxfUQ==",
+ "dependencies": {
+ "css-in-js-utils": "^3.1.0",
+ "fast-loops": "^1.1.3"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "dependencies": {
+ "hasown": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "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==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/jiti": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
+ "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/js-cookie": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
+ "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+ },
+ "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=="
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "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
+ },
+ "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,
+ "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,
+ "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,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+ },
+ "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,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lucide-react": {
+ "version": "0.292.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.292.0.tgz",
+ "integrity": "sha512-rRgUkpEHWpa5VCT66YscInCQmQuPCB1RFRzkkxMxg4b+jaL0V12E3riWWR2Sh5OIiUhCwGW/ZExuEO4Az32E6Q==",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nano-css": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.4.0.tgz",
+ "integrity": "sha512-QIbVsMMMsC+RQKJPxFDM70kf31A/JxNLE0D9tX9nwq4tcigY/vpvOJKphcQo55/RbriTnFSgrGnFhb8Y/6hs5g==",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "css-tree": "^1.1.2",
+ "csstype": "^3.1.2",
+ "fastest-stable-stringify": "^2.0.2",
+ "inline-style-prefixer": "^7.0.0",
+ "rtl-css-js": "^1.16.1",
+ "stacktrace-js": "^2.0.2",
+ "stylis": "^4.3.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "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
+ },
+ "node_modules/next": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/next/-/next-14.0.3.tgz",
+ "integrity": "sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw==",
+ "peer": true,
+ "dependencies": {
+ "@next/env": "14.0.3",
+ "@swc/helpers": "0.5.2",
+ "busboy": "1.6.0",
+ "caniuse-lite": "^1.0.30001406",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.1",
+ "watchpack": "2.4.0"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": ">=18.17.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "14.0.3",
+ "@next/swc-darwin-x64": "14.0.3",
+ "@next/swc-linux-arm64-gnu": "14.0.3",
+ "@next/swc-linux-arm64-musl": "14.0.3",
+ "@next/swc-linux-x64-gnu": "14.0.3",
+ "@next/swc-linux-x64-musl": "14.0.3",
+ "@next/swc-win32-arm64-msvc": "14.0.3",
+ "@next/swc-win32-ia32-msvc": "14.0.3",
+ "@next/swc-win32-x64-msvc": "14.0.3"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/next-themes": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
+ "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==",
+ "peerDependencies": {
+ "next": "*",
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "dev": true,
+ "dependencies": {
+ "@aashutoshrathi/word-wrap": "^1.2.3",
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0"
+ },
+ "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,
+ "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,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "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"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+ "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "lilconfig": "^3.0.0",
+ "yaml": "^2.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/lilconfig": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
+ "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.11"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.13",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+ "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
+ "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,
+ "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,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0"
+ }
+ },
+ "node_modules/react-hotkeys-hook": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz",
+ "integrity": "sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==",
+ "peerDependencies": {
+ "react": ">=16.8.1",
+ "react-dom": ">=16.8.1"
+ }
+ },
+ "node_modules/react-photo-album": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/react-photo-album/-/react-photo-album-2.3.0.tgz",
+ "integrity": "sha512-CU+UMK4ZQHIoPZ672TSst9loKE5bxy6w0+bf7bY4XOw1g1C7+VdDWCW+wD8wPpbg2ve38QBTS73HVe6xYLAQ3w==",
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-remove-scroll": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
+ "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.3",
+ "react-style-singleton": "^2.2.1",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.0",
+ "use-sidecar": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz",
+ "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==",
+ "dependencies": {
+ "react-style-singleton": "^2.2.1",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
+ "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "invariant": "^2.2.4",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-universal-interface": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
+ "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==",
+ "peerDependencies": {
+ "react": "*",
+ "tslib": "*"
+ }
+ },
+ "node_modules/react-use": {
+ "version": "17.4.0",
+ "resolved": "https://registry.npmjs.org/react-use/-/react-use-17.4.0.tgz",
+ "integrity": "sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q==",
+ "dependencies": {
+ "@types/js-cookie": "^2.2.6",
+ "@xobotyi/scrollbar-width": "^1.9.5",
+ "copy-to-clipboard": "^3.3.1",
+ "fast-deep-equal": "^3.1.3",
+ "fast-shallow-equal": "^1.0.0",
+ "js-cookie": "^2.2.1",
+ "nano-css": "^5.3.1",
+ "react-universal-interface": "^0.6.2",
+ "resize-observer-polyfill": "^1.5.1",
+ "screenfull": "^5.1.0",
+ "set-harmonic-interval": "^1.0.1",
+ "throttle-debounce": "^3.0.1",
+ "ts-easing": "^0.2.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/react-zoom-pan-pinch": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.3.0.tgz",
+ "integrity": "sha512-vy1h8aenDzXye+HRqANZaSA8IPHoqOiuDPFBkswoyPUH8uMfsmbeH6gFI4r4BhEJa0xIlcA+FbvhidRWKGUrOg==",
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/recoil": {
+ "version": "0.7.7",
+ "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz",
+ "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==",
+ "dependencies": {
+ "hamt_plus": "1.0.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.13.1"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
+ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
+ },
+ "node_modules/resize-observer-polyfill": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.5.0.tgz",
+ "integrity": "sha512-41xsWhzxqjMDASCxH5ibw1mXk+3c4TNI2UjKbLxe6iEzrSQnqOzmmK8/3mufCPbzHNJ2e04Fc1ddI35hHy+8zg==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.5.0",
+ "@rollup/rollup-android-arm64": "4.5.0",
+ "@rollup/rollup-darwin-arm64": "4.5.0",
+ "@rollup/rollup-darwin-x64": "4.5.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.5.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.5.0",
+ "@rollup/rollup-linux-arm64-musl": "4.5.0",
+ "@rollup/rollup-linux-x64-gnu": "4.5.0",
+ "@rollup/rollup-linux-x64-musl": "4.5.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.5.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.5.0",
+ "@rollup/rollup-win32-x64-msvc": "4.5.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/rtl-css-js": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
+ "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==",
+ "dependencies": {
+ "@babel/runtime": "^7.1.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/screenfull": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
+ "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/set-harmonic-interval": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz",
+ "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==",
+ "engines": {
+ "node": ">=6.9"
+ }
+ },
+ "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,
+ "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,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stack-generator": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz",
+ "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==",
+ "dependencies": {
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/stackframe": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+ "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
+ },
+ "node_modules/stacktrace-gps": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz",
+ "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==",
+ "dependencies": {
+ "source-map": "0.5.6",
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/stacktrace-gps/node_modules/source-map": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stacktrace-js": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz",
+ "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==",
+ "dependencies": {
+ "error-stack-parser": "^2.0.6",
+ "stack-generator": "^2.0.5",
+ "stacktrace-gps": "^3.0.4"
+ }
+ },
+ "node_modules/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "peer": true,
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/styled-jsx": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
+ "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
+ "peer": true,
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/stylis": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz",
+ "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ=="
+ },
+ "node_modules/sucrase": {
+ "version": "3.34.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
+ "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "7.1.6",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwind-merge": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.0.0.tgz",
+ "integrity": "sha512-WO8qghn9yhsldLSg80au+3/gY9E4hFxIvQ3qOmlpXnqpDKoMruKfi/56BbbMg6fHTQJ9QD3cc79PoWqlaQE4rw==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
+ "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.0",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.19.1",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tailwindcss-animate": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
+ "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || insiders"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/throttle-debounce": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
+ "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toggle-selection": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+ },
+ "node_modules/ts-api-utils": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
+ "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.13.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
+ "node_modules/ts-easing": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz",
+ "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ=="
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
+ },
+ "node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+ },
+ "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,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
+ "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+ "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"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ },
+ "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,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/use-callback-ref": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz",
+ "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sidecar": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
+ "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/vite": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.0.tgz",
+ "integrity": "sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.19.3",
+ "postcss": "^8.4.31",
+ "rollup": "^4.2.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/watchpack": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+ "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+ "peer": true,
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yaml": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
+ "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "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,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/web_app/package.json b/web_app/package.json
new file mode 100644
index 0000000..9ef38e3
--- /dev/null
+++ b/web_app/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "web_app",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@heroicons/react": "^2.0.18",
+ "@radix-ui/react-accordion": "^1.1.2",
+ "@radix-ui/react-dialog": "^1.0.5",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.0.7",
+ "@radix-ui/react-scroll-area": "^1.0.5",
+ "@radix-ui/react-select": "^2.0.0",
+ "@radix-ui/react-slider": "^1.1.2",
+ "@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-switch": "^1.0.3",
+ "@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toast": "^1.1.5",
+ "@radix-ui/react-toggle": "^1.0.3",
+ "@radix-ui/react-tooltip": "^1.0.7",
+ "@uidotdev/usehooks": "^2.4.1",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.0.0",
+ "flexsearch": "^0.7.21",
+ "lodash": "^4.17.21",
+ "lucide-react": "^0.292.0",
+ "mitt": "^3.0.1",
+ "next-themes": "^0.2.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hotkeys-hook": "^4.4.1",
+ "react-photo-album": "^2.3.0",
+ "react-use": "^17.4.0",
+ "react-zoom-pan-pinch": "^3.3.0",
+ "recoil": "^0.7.7",
+ "tailwind-merge": "^2.0.0",
+ "tailwindcss-animate": "^1.0.7"
+ },
+ "devDependencies": {
+ "@types/flexsearch": "^0.7.3",
+ "@types/lodash": "^4.14.201",
+ "@types/node": "^20.9.2",
+ "@types/react": "^18.2.37",
+ "@types/react-dom": "^18.2.15",
+ "@typescript-eslint/eslint-plugin": "^6.10.0",
+ "@typescript-eslint/parser": "^6.10.0",
+ "@vitejs/plugin-react": "^4.2.0",
+ "@vitejs/plugin-react-swc": "^3.5.0",
+ "autoprefixer": "^10.4.16",
+ "eslint": "^8.53.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.4",
+ "postcss": "^8.4.31",
+ "tailwindcss": "^3.3.5",
+ "typescript": "^5.2.2",
+ "vite": "^5.0.0"
+ }
+}
diff --git a/web_app/postcss.config.js b/web_app/postcss.config.js
new file mode 100644
index 0000000..2e7af2b
--- /dev/null
+++ b/web_app/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/web_app/src/App.tsx b/web_app/src/App.tsx
new file mode 100644
index 0000000..f845013
--- /dev/null
+++ b/web_app/src/App.tsx
@@ -0,0 +1,173 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from "react"
+import { nanoid } from "nanoid"
+import { useRecoilState, useSetRecoilState } from "recoil"
+import { fileState, serverConfigState } from "@/lib/store"
+import useInputImage from "@/hooks/useInputImage"
+import { keepGUIAlive } from "@/lib/utils"
+import { getServerConfig, isDesktop } from "@/lib/api"
+import Header from "@/components/Header"
+import Workspace from "@/components/Workspace"
+import FileSelect from "@/components/FileSelect"
+import { Toaster } from "./components/ui/toaster"
+
+const SUPPORTED_FILE_TYPE = [
+ "image/jpeg",
+ "image/png",
+ "image/webp",
+ "image/bmp",
+ "image/tiff",
+]
+function Home() {
+ const [file, setFile] = useRecoilState(fileState)
+ const userInputImage = useInputImage()
+ const setServerConfigState = useSetRecoilState(serverConfigState)
+
+ // Set Input Image
+ useEffect(() => {
+ setFile(userInputImage)
+ }, [userInputImage, setFile])
+
+ // Keeping GUI Window Open
+ useEffect(() => {
+ const fetchData = async () => {
+ const isRunDesktop = await isDesktop().then((res) => res.text())
+ if (isRunDesktop === "True") {
+ keepGUIAlive()
+ }
+ }
+ fetchData()
+ }, [])
+
+ useEffect(() => {
+ const fetchServerConfig = async () => {
+ const serverConfig = await getServerConfig().then((res) => res.json())
+ console.log(serverConfig)
+ setServerConfigState(serverConfig)
+ }
+ fetchServerConfig()
+ }, [])
+
+ const workspaceId = useMemo(() => {
+ return nanoid()
+ }, [file])
+
+ const [isDragging, setIsDragging] = useState(false)
+ const dragCounter = useRef(0)
+
+ const handleDrag = useCallback((event: any) => {
+ event.preventDefault()
+ event.stopPropagation()
+ }, [])
+
+ const handleDragIn = useCallback((event: any) => {
+ event.preventDefault()
+ event.stopPropagation()
+ dragCounter.current += 1
+ if (event.dataTransfer.items && event.dataTransfer.items.length > 0) {
+ setIsDragging(true)
+ }
+ }, [])
+
+ const handleDragOut = useCallback((event: any) => {
+ event.preventDefault()
+ event.stopPropagation()
+ dragCounter.current -= 1
+ if (dragCounter.current > 0) return
+ setIsDragging(false)
+ }, [])
+
+ const handleDrop = useCallback((event: any) => {
+ event.preventDefault()
+ event.stopPropagation()
+ setIsDragging(false)
+ if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
+ if (event.dataTransfer.files.length > 1) {
+ // setToastState({
+ // open: true,
+ // desc: "Please drag and drop only one file",
+ // state: "error",
+ // duration: 3000,
+ // })
+ } else {
+ const dragFile = event.dataTransfer.files[0]
+ const fileType = dragFile.type
+ if (SUPPORTED_FILE_TYPE.includes(fileType)) {
+ setFile(dragFile)
+ } else {
+ // setToastState({
+ // open: true,
+ // desc: "Please drag and drop an image file",
+ // state: "error",
+ // duration: 3000,
+ // })
+ }
+ }
+ event.dataTransfer.clearData()
+ }
+ }, [])
+
+ const onPaste = useCallback((event: any) => {
+ // TODO: when sd side panel open, ctrl+v not work
+ // https://htmldom.dev/paste-an-image-from-the-clipboard/
+ if (!event.clipboardData) {
+ return
+ }
+ const clipboardItems = event.clipboardData.items
+ const items: DataTransferItem[] = [].slice
+ .call(clipboardItems)
+ .filter((item: DataTransferItem) => {
+ // Filter the image items only
+ return item.type.indexOf("image") !== -1
+ })
+
+ if (items.length === 0) {
+ return
+ }
+
+ event.preventDefault()
+ event.stopPropagation()
+
+ // TODO: add confirm dialog
+
+ const item = items[0]
+ // Get the blob of image
+ const blob = item.getAsFile()
+ if (blob) {
+ setFile(blob)
+ }
+ }, [])
+
+ useEffect(() => {
+ window.addEventListener("dragenter", handleDragIn)
+ window.addEventListener("dragleave", handleDragOut)
+ window.addEventListener("dragover", handleDrag)
+ window.addEventListener("drop", handleDrop)
+ window.addEventListener("paste", onPaste)
+ return function cleanUp() {
+ window.removeEventListener("dragenter", handleDragIn)
+ window.removeEventListener("dragleave", handleDragOut)
+ window.removeEventListener("dragover", handleDrag)
+ window.removeEventListener("drop", handleDrop)
+ window.removeEventListener("paste", onPaste)
+ }
+ })
+
+ return (
+
+
+
+
+ {!file ? (
+ {
+ setFile(f)
+ }}
+ />
+ ) : (
+ <>>
+ )}
+
+ )
+}
+
+export default Home
diff --git a/web_app/src/components/Editor.tsx b/web_app/src/components/Editor.tsx
new file mode 100644
index 0000000..2de8d1a
--- /dev/null
+++ b/web_app/src/components/Editor.tsx
@@ -0,0 +1,1704 @@
+import React, {
+ SyntheticEvent,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from "react"
+import {
+ CursorArrowRaysIcon,
+ ArrowsPointingOutIcon,
+ ArrowDownTrayIcon,
+} from "@heroicons/react/24/outline"
+import {
+ ReactZoomPanPinchRef,
+ TransformComponent,
+ TransformWrapper,
+} from "react-zoom-pan-pinch"
+import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"
+import { useWindowSize } from "react-use"
+// import { useWindowSize, useKey, useKeyPressEvent } from "@uidotdev/usehooks"
+import inpaint, { downloadToOutput, runPlugin } from "@/lib/api"
+import { Button, IconButton } from "@/components/ui/button"
+import {
+ askWritePermission,
+ copyCanvasImage,
+ downloadImage,
+ isMidClick,
+ isRightClick,
+ loadImage,
+ srcToFile,
+} from "@/lib/utils"
+import { Eraser, Eye, Redo, Undo } from "lucide-react"
+import {
+ appState,
+ brushSizeState,
+ croperState,
+ enableFileManagerState,
+ fileState,
+ imageHeightState,
+ imageWidthState,
+ interactiveSegClicksState,
+ isDiffusionModelsState,
+ isEnableAutoSavingState,
+ isInpaintingState,
+ isInteractiveSegRunningState,
+ isInteractiveSegState,
+ isPix2PixState,
+ isPluginRunningState,
+ isProcessingState,
+ negativePropmtState,
+ propmtState,
+ runManuallyState,
+ seedState,
+ settingState,
+ toastState,
+} from "@/lib/store"
+// import Croper from "../Croper/Croper"
+import emitter, {
+ EVENT_PROMPT,
+ EVENT_CUSTOM_MASK,
+ EVENT_PAINT_BY_EXAMPLE,
+ RERUN_LAST_MASK,
+ DREAM_BUTTON_MOUSE_ENTER,
+ DREAM_BUTTON_MOUSE_LEAVE,
+} from "@/lib/event"
+import { useImage } from "@/hooks/useImage"
+import { Slider } from "./ui/slider"
+// import FileSelect from "../FileSelect/FileSelect"
+// import InteractiveSeg from "../InteractiveSeg/InteractiveSeg"
+// import InteractiveSegConfirmActions from "../InteractiveSeg/ConfirmActions"
+// import InteractiveSegReplaceModal from "../InteractiveSeg/ReplaceModal"
+import { PluginName } from "@/lib/types"
+import { useHotkeys } from "react-hotkeys-hook"
+// import MakeGIF from "./MakeGIF"
+
+const TOOLBAR_SIZE = 200
+const MIN_BRUSH_SIZE = 10
+const MAX_BRUSH_SIZE = 200
+const BRUSH_COLOR = "#ffcc00bb"
+
+interface Line {
+ size?: number
+ pts: { x: number; y: number }[]
+}
+
+type LineGroup = Array
+
+function drawLines(
+ ctx: CanvasRenderingContext2D,
+ lines: LineGroup,
+ color = BRUSH_COLOR
+) {
+ ctx.strokeStyle = color
+ ctx.lineCap = "round"
+ ctx.lineJoin = "round"
+
+ lines.forEach((line) => {
+ if (!line?.pts.length || !line.size) {
+ return
+ }
+ ctx.lineWidth = line.size
+ ctx.beginPath()
+ ctx.moveTo(line.pts[0].x, line.pts[0].y)
+ line.pts.forEach((pt) => ctx.lineTo(pt.x, pt.y))
+ ctx.stroke()
+ })
+}
+
+function mouseXY(ev: SyntheticEvent) {
+ const mouseEvent = ev.nativeEvent as MouseEvent
+ return { x: mouseEvent.offsetX, y: mouseEvent.offsetY }
+}
+
+export default function Editor() {
+ const [file, setFile] = useRecoilState(fileState)
+ const promptVal = useRecoilValue(propmtState)
+ const negativePromptVal = useRecoilValue(negativePropmtState)
+ const settings = useRecoilValue(settingState)
+ const [seedVal, setSeed] = useRecoilState(seedState)
+ const croperRect = useRecoilValue(croperState)
+ const setToastState = useSetRecoilState(toastState)
+ const [isInpainting, setIsInpainting] = useRecoilState(isInpaintingState)
+ const setIsPluginRunning = useSetRecoilState(isPluginRunningState)
+ const isProcessing = useRecoilValue(isProcessingState)
+ const runMannually = useRecoilValue(runManuallyState)
+ const isDiffusionModels = useRecoilValue(isDiffusionModelsState)
+ const isPix2Pix = useRecoilValue(isPix2PixState)
+ const [isInteractiveSeg, setIsInteractiveSeg] = useRecoilState(
+ isInteractiveSegState
+ )
+ const setIsInteractiveSegRunning = useSetRecoilState(
+ isInteractiveSegRunningState
+ )
+
+ const [showInteractiveSegModal, setShowInteractiveSegModal] = useState(false)
+ const [interactiveSegMask, setInteractiveSegMask] = useState<
+ HTMLImageElement | null | undefined
+ >(null)
+ // only used while interactive segmentation is on
+ const [tmpInteractiveSegMask, setTmpInteractiveSegMask] = useState<
+ HTMLImageElement | null | undefined
+ >(null)
+ const [prevInteractiveSegMask, setPrevInteractiveSegMask] = useState<
+ HTMLImageElement | null | undefined
+ >(null)
+
+ // 仅用于在 dream button hover 时显示提示
+ const [dreamButtonHoverSegMask, setDreamButtonHoverSegMask] = useState<
+ HTMLImageElement | null | undefined
+ >(null)
+ const [dreamButtonHoverLineGroup, setDreamButtonHoverLineGroup] =
+ useState([])
+
+ const [clicks, setClicks] = useRecoilState(interactiveSegClicksState)
+
+ const [brushSize, setBrushSize] = useRecoilState(brushSizeState)
+
+ const [original, isOriginalLoaded] = useImage(file)
+ const [renders, setRenders] = useState([])
+ const [context, setContext] = useState()
+ const [maskCanvas] = useState(() => {
+ return document.createElement("canvas")
+ })
+ const [lineGroups, setLineGroups] = useState([])
+ const [lastLineGroup, setLastLineGroup] = useState([])
+ const [curLineGroup, setCurLineGroup] = useState([])
+ const [{ x, y }, setCoords] = useState({ x: -1, y: -1 })
+ const [showBrush, setShowBrush] = useState(false)
+ const [showRefBrush, setShowRefBrush] = useState(false)
+ const [isPanning, setIsPanning] = useState(false)
+ const [isChangingBrushSizeByMouse, setIsChangingBrushSizeByMouse] =
+ useState(false)
+ const [changeBrushSizeByMouseInit, setChangeBrushSizeByMouseInit] = useState({
+ x: -1,
+ y: -1,
+ brushSize: 20,
+ })
+
+ const [showOriginal, setShowOriginal] = useState(false)
+ const [scale, setScale] = useState(1)
+ const [panned, setPanned] = useState(false)
+ const [minScale, setMinScale] = useState(1.0)
+ const windowSize = useWindowSize()
+ const windowCenterX = windowSize.width / 2
+ const windowCenterY = windowSize.height / 2
+ const viewportRef = useRef(null)
+ // Indicates that the image has been loaded and is centered on first load
+ const [initialCentered, setInitialCentered] = useState(false)
+
+ const [isDraging, setIsDraging] = useState(false)
+ const [isMultiStrokeKeyPressed, setIsMultiStrokeKeyPressed] = useState(false)
+
+ const [sliderPos, setSliderPos] = useState(0)
+
+ // redo 相关
+ const [redoRenders, setRedoRenders] = useState([])
+ const [redoCurLines, setRedoCurLines] = useState([])
+ const [redoLineGroups, setRedoLineGroups] = useState([])
+ const enableFileManager = useRecoilValue(enableFileManagerState)
+ const isEnableAutoSaving = useRecoilValue(isEnableAutoSavingState)
+
+ const [imageWidth, setImageWidth] = useRecoilState(imageWidthState)
+ const [imageHeight, setImageHeight] = useRecoilState(imageHeightState)
+ const app = useRecoilValue(appState)
+
+ const draw = useCallback(
+ (render: HTMLImageElement, lineGroup: LineGroup) => {
+ if (!context) {
+ return
+ }
+ console.log(
+ `[draw] render size: ${render.width}x${render.height} image size: ${imageWidth}x${imageHeight} canvas size: ${context.canvas.width}x${context.canvas.height}`
+ )
+
+ context.clearRect(0, 0, context.canvas.width, context.canvas.height)
+ context.drawImage(render, 0, 0, imageWidth, imageHeight)
+ if (isInteractiveSeg && tmpInteractiveSegMask) {
+ context.drawImage(tmpInteractiveSegMask, 0, 0, imageWidth, imageHeight)
+ }
+ if (!isInteractiveSeg && interactiveSegMask) {
+ context.drawImage(interactiveSegMask, 0, 0, imageWidth, imageHeight)
+ }
+ if (dreamButtonHoverSegMask) {
+ context.drawImage(
+ dreamButtonHoverSegMask,
+ 0,
+ 0,
+ imageWidth,
+ imageHeight
+ )
+ }
+ drawLines(context, lineGroup)
+ drawLines(context, dreamButtonHoverLineGroup)
+ },
+ [
+ context,
+ isInteractiveSeg,
+ tmpInteractiveSegMask,
+ dreamButtonHoverSegMask,
+ interactiveSegMask,
+ imageHeight,
+ imageWidth,
+ dreamButtonHoverLineGroup,
+ ]
+ )
+
+ const drawLinesOnMask = useCallback(
+ (_lineGroups: LineGroup[], maskImage?: HTMLImageElement | null) => {
+ if (!context?.canvas.width || !context?.canvas.height) {
+ throw new Error("canvas has invalid size")
+ }
+ maskCanvas.width = context?.canvas.width
+ maskCanvas.height = context?.canvas.height
+ const ctx = maskCanvas.getContext("2d")
+ if (!ctx) {
+ throw new Error("could not retrieve mask canvas")
+ }
+
+ if (maskImage !== undefined && maskImage !== null) {
+ // TODO: check whether draw yellow mask works on backend
+ ctx.drawImage(maskImage, 0, 0, imageWidth, imageHeight)
+ }
+
+ _lineGroups.forEach((lineGroup) => {
+ drawLines(ctx, lineGroup, "white")
+ })
+
+ if (
+ (maskImage === undefined || maskImage === null) &&
+ _lineGroups.length === 1 &&
+ _lineGroups[0].length === 0 &&
+ isPix2Pix
+ ) {
+ // For InstructPix2Pix without mask
+ drawLines(
+ ctx,
+ [
+ {
+ size: 9999999999,
+ pts: [
+ { x: 0, y: 0 },
+ { x: imageWidth, y: 0 },
+ { x: imageWidth, y: imageHeight },
+ { x: 0, y: imageHeight },
+ ],
+ },
+ ],
+ "white"
+ )
+ }
+ },
+ [context, maskCanvas, isPix2Pix, imageWidth, imageHeight]
+ )
+
+ const hadDrawSomething = useCallback(() => {
+ if (isPix2Pix) {
+ return true
+ }
+ return curLineGroup.length !== 0
+ }, [curLineGroup, isPix2Pix])
+
+ const drawOnCurrentRender = useCallback(
+ (lineGroup: LineGroup) => {
+ console.log("[drawOnCurrentRender] draw on current render")
+ if (renders.length === 0) {
+ draw(original, lineGroup)
+ } else {
+ draw(renders[renders.length - 1], lineGroup)
+ }
+ },
+ [original, renders, draw]
+ )
+
+ const runInpainting = useCallback(
+ async (
+ useLastLineGroup?: boolean,
+ customMask?: File,
+ maskImage?: HTMLImageElement | null,
+ paintByExampleImage?: File
+ ) => {
+ // customMask: mask uploaded by user
+ // maskImage: mask from interactive segmentation
+ if (file === undefined) {
+ return
+ }
+ const useCustomMask = customMask !== undefined && customMask !== null
+ const useMaskImage = maskImage !== undefined && maskImage !== null
+ // useLastLineGroup 的影响
+ // 1. 使用上一次的 mask
+ // 2. 结果替换当前 render
+ console.log("runInpainting")
+ console.log({
+ useCustomMask,
+ useMaskImage,
+ })
+
+ let maskLineGroup: LineGroup = []
+ if (useLastLineGroup === true) {
+ if (lastLineGroup.length === 0) {
+ return
+ }
+ maskLineGroup = lastLineGroup
+ } else if (!useCustomMask) {
+ if (!hadDrawSomething() && !useMaskImage) {
+ return
+ }
+
+ setLastLineGroup(curLineGroup)
+ maskLineGroup = curLineGroup
+ }
+
+ const newLineGroups = [...lineGroups, maskLineGroup]
+
+ setCurLineGroup([])
+ setIsDraging(false)
+ setIsInpainting(true)
+ if (settings.graduallyInpainting) {
+ drawLinesOnMask([maskLineGroup], maskImage)
+ } else {
+ drawLinesOnMask(newLineGroups)
+ }
+
+ let targetFile = file
+ if (settings.graduallyInpainting === true) {
+ if (useLastLineGroup === true) {
+ // renders.length == 1 还是用原来的
+ if (renders.length > 1) {
+ const lastRender = renders[renders.length - 2]
+ targetFile = await srcToFile(
+ lastRender.currentSrc,
+ file.name,
+ file.type
+ )
+ }
+ } else if (renders.length > 0) {
+ console.info("gradually inpainting on last result")
+
+ const lastRender = renders[renders.length - 1]
+ targetFile = await srcToFile(
+ lastRender.currentSrc,
+ file.name,
+ file.type
+ )
+ }
+ }
+
+ try {
+ console.log("before run inpaint")
+ const res = await inpaint(
+ targetFile,
+ settings,
+ croperRect,
+ promptVal,
+ negativePromptVal,
+ seedVal,
+ useCustomMask ? undefined : maskCanvas.toDataURL(),
+ useCustomMask ? customMask : undefined,
+ paintByExampleImage
+ )
+ if (!res) {
+ throw new Error("Something went wrong on server side.")
+ }
+ const { blob, seed } = res
+ if (seed) {
+ setSeed(parseInt(seed, 10))
+ }
+ const newRender = new Image()
+ await loadImage(newRender, blob)
+
+ if (useLastLineGroup === true) {
+ const prevRenders = renders.slice(0, -1)
+ const newRenders = [...prevRenders, newRender]
+ setRenders(newRenders)
+ } else {
+ const newRenders = [...renders, newRender]
+ setRenders(newRenders)
+ }
+
+ draw(newRender, [])
+ // Only append new LineGroup after inpainting success
+ setLineGroups(newLineGroups)
+
+ // clear redo stack
+ resetRedoState()
+ } catch (e: any) {
+ setToastState({
+ open: true,
+ desc: e.message ? e.message : e.toString(),
+ state: "error",
+ duration: 4000,
+ })
+ drawOnCurrentRender([])
+ }
+ setIsInpainting(false)
+ setPrevInteractiveSegMask(maskImage)
+ setTmpInteractiveSegMask(null)
+ setInteractiveSegMask(null)
+ },
+ [
+ lineGroups,
+ curLineGroup,
+ maskCanvas,
+ settings.graduallyInpainting,
+ settings,
+ croperRect,
+ promptVal,
+ negativePromptVal,
+ drawOnCurrentRender,
+ hadDrawSomething,
+ drawLinesOnMask,
+ seedVal,
+ ]
+ )
+
+ useEffect(() => {
+ emitter.on(EVENT_PROMPT, () => {
+ if (hadDrawSomething() || interactiveSegMask) {
+ runInpainting(false, undefined, interactiveSegMask)
+ } else if (lastLineGroup.length !== 0) {
+ // 使用上一次手绘的 mask 生成
+ runInpainting(true, undefined, prevInteractiveSegMask)
+ } else if (prevInteractiveSegMask) {
+ // 使用上一次 IS 的 mask 生成
+ runInpainting(false, undefined, prevInteractiveSegMask)
+ } else if (isPix2Pix) {
+ runInpainting(false, undefined, null)
+ } else {
+ setToastState({
+ open: true,
+ desc: "Please draw mask on picture",
+ state: "error",
+ duration: 1500,
+ })
+ }
+ emitter.emit(DREAM_BUTTON_MOUSE_LEAVE)
+ })
+
+ return () => {
+ emitter.off(EVENT_PROMPT)
+ }
+ }, [
+ hadDrawSomething,
+ runInpainting,
+ promptVal,
+ interactiveSegMask,
+ prevInteractiveSegMask,
+ ])
+
+ useEffect(() => {
+ emitter.on(DREAM_BUTTON_MOUSE_ENTER, () => {
+ // 当前 canvas 上没有手绘 mask 或者 interactiveSegMask 时,显示上一次的 mask
+ if (!hadDrawSomething() && !interactiveSegMask) {
+ if (prevInteractiveSegMask) {
+ setDreamButtonHoverSegMask(prevInteractiveSegMask)
+ }
+ let lineGroup2Show: LineGroup = []
+ if (redoLineGroups.length !== 0) {
+ lineGroup2Show = redoLineGroups[redoLineGroups.length - 1]
+ } else if (lineGroups.length !== 0) {
+ lineGroup2Show = lineGroups[lineGroups.length - 1]
+ }
+ console.log(
+ `[DREAM_BUTTON_MOUSE_ENTER], prevInteractiveSegMask: ${prevInteractiveSegMask} lineGroup2Show: ${lineGroup2Show.length}`
+ )
+ if (lineGroup2Show) {
+ setDreamButtonHoverLineGroup(lineGroup2Show)
+ }
+ }
+ })
+ return () => {
+ emitter.off(DREAM_BUTTON_MOUSE_ENTER)
+ }
+ }, [
+ hadDrawSomething,
+ interactiveSegMask,
+ prevInteractiveSegMask,
+ drawOnCurrentRender,
+ lineGroups,
+ redoLineGroups,
+ ])
+
+ useEffect(() => {
+ emitter.on(DREAM_BUTTON_MOUSE_LEAVE, () => {
+ // 当前 canvas 上没有手绘 mask 或者 interactiveSegMask 时,显示上一次的 mask
+ if (!hadDrawSomething() && !interactiveSegMask) {
+ setDreamButtonHoverSegMask(null)
+ setDreamButtonHoverLineGroup([])
+ drawOnCurrentRender([])
+ }
+ })
+ return () => {
+ emitter.off(DREAM_BUTTON_MOUSE_LEAVE)
+ }
+ }, [hadDrawSomething, interactiveSegMask, drawOnCurrentRender])
+
+ useEffect(() => {
+ emitter.on(EVENT_CUSTOM_MASK, (data: any) => {
+ // TODO: not work with paint by example
+ runInpainting(false, data.mask)
+ })
+
+ return () => {
+ emitter.off(EVENT_CUSTOM_MASK)
+ }
+ }, [runInpainting])
+
+ useEffect(() => {
+ emitter.on(EVENT_PAINT_BY_EXAMPLE, (data: any) => {
+ if (hadDrawSomething() || interactiveSegMask) {
+ runInpainting(false, undefined, interactiveSegMask, data.image)
+ } else if (lastLineGroup.length !== 0) {
+ // 使用上一次手绘的 mask 生成
+ runInpainting(true, undefined, prevInteractiveSegMask, data.image)
+ } else if (prevInteractiveSegMask) {
+ // 使用上一次 IS 的 mask 生成
+ runInpainting(false, undefined, prevInteractiveSegMask, data.image)
+ } else {
+ setToastState({
+ open: true,
+ desc: "Please draw mask on picture",
+ state: "error",
+ duration: 1500,
+ })
+ }
+ })
+
+ return () => {
+ emitter.off(EVENT_PAINT_BY_EXAMPLE)
+ }
+ }, [runInpainting])
+
+ useEffect(() => {
+ emitter.on(RERUN_LAST_MASK, () => {
+ if (lastLineGroup.length !== 0) {
+ // 使用上一次手绘的 mask 生成
+ runInpainting(true, undefined, prevInteractiveSegMask)
+ } else if (prevInteractiveSegMask) {
+ // 使用上一次 IS 的 mask 生成
+ runInpainting(false, undefined, prevInteractiveSegMask)
+ } else {
+ setToastState({
+ open: true,
+ desc: "No mask to reuse",
+ state: "error",
+ duration: 1500,
+ })
+ }
+ })
+ return () => {
+ emitter.off(RERUN_LAST_MASK)
+ }
+ }, [runInpainting])
+
+ const getCurrentRender = useCallback(async () => {
+ let targetFile = file
+ if (renders.length > 0) {
+ const lastRender = renders[renders.length - 1]
+ targetFile = await srcToFile(lastRender.currentSrc, file.name, file.type)
+ }
+ return targetFile
+ }, [file, renders])
+
+ useEffect(() => {
+ emitter.on(PluginName.InteractiveSeg, () => {
+ setIsInteractiveSeg(true)
+ if (interactiveSegMask !== null) {
+ setShowInteractiveSegModal(true)
+ }
+ })
+ return () => {
+ emitter.off(PluginName.InteractiveSeg)
+ }
+ })
+
+ const runRenderablePlugin = useCallback(
+ async (name: string, data?: any) => {
+ if (isProcessing) {
+ return
+ }
+ try {
+ // TODO 要不要加 undoCurrentLine??
+ const start = new Date()
+ setIsPluginRunning(true)
+ const targetFile = await getCurrentRender()
+ const res = await runPlugin(name, targetFile, data?.upscale)
+ if (!res) {
+ throw new Error("Something went wrong on server side.")
+ }
+ const { blob } = res
+ const newRender = new Image()
+ await loadImage(newRender, blob)
+ setImageHeight(newRender.height)
+ setImageWidth(newRender.width)
+ const newRenders = [...renders, newRender]
+ setRenders(newRenders)
+ const newLineGroups = [...lineGroups, []]
+ setLineGroups(newLineGroups)
+
+ const end = new Date()
+ const time = end.getTime() - start.getTime()
+
+ setToastState({
+ open: true,
+ desc: `Run ${name} successfully in ${time / 1000}s`,
+ state: "success",
+ duration: 3000,
+ })
+
+ const rW = windowSize.width / newRender.width
+ const rH = (windowSize.height - TOOLBAR_SIZE) / newRender.height
+ let s = 1.0
+ if (rW < 1 || rH < 1) {
+ s = Math.min(rW, rH)
+ }
+ setMinScale(s)
+ setScale(s)
+ viewportRef.current?.centerView(s, 1)
+ } catch (e: any) {
+ setToastState({
+ open: true,
+ desc: e.message ? e.message : e.toString(),
+ state: "error",
+ duration: 3000,
+ })
+ } finally {
+ setIsPluginRunning(false)
+ }
+ },
+ [
+ renders,
+ setRenders,
+ getCurrentRender,
+ setIsPluginRunning,
+ isProcessing,
+ setImageHeight,
+ setImageWidth,
+ lineGroups,
+ viewportRef,
+ windowSize,
+ setLineGroups,
+ ]
+ )
+
+ useEffect(() => {
+ emitter.on(PluginName.RemoveBG, () => {
+ runRenderablePlugin(PluginName.RemoveBG)
+ })
+ return () => {
+ emitter.off(PluginName.RemoveBG)
+ }
+ }, [runRenderablePlugin])
+
+ useEffect(() => {
+ emitter.on(PluginName.AnimeSeg, () => {
+ runRenderablePlugin(PluginName.AnimeSeg)
+ })
+ return () => {
+ emitter.off(PluginName.AnimeSeg)
+ }
+ }, [runRenderablePlugin])
+
+ useEffect(() => {
+ emitter.on(PluginName.GFPGAN, () => {
+ runRenderablePlugin(PluginName.GFPGAN)
+ })
+ return () => {
+ emitter.off(PluginName.GFPGAN)
+ }
+ }, [runRenderablePlugin])
+
+ useEffect(() => {
+ emitter.on(PluginName.RestoreFormer, () => {
+ runRenderablePlugin(PluginName.RestoreFormer)
+ })
+ return () => {
+ emitter.off(PluginName.RestoreFormer)
+ }
+ }, [runRenderablePlugin])
+
+ useEffect(() => {
+ emitter.on(PluginName.RealESRGAN, (data: any) => {
+ runRenderablePlugin(PluginName.RealESRGAN, data)
+ })
+ return () => {
+ emitter.off(PluginName.RealESRGAN)
+ }
+ }, [runRenderablePlugin])
+
+ const hadRunInpainting = () => {
+ return renders.length !== 0
+ }
+
+ const getCurrentWidthHeight = useCallback(() => {
+ let width = 512
+ let height = 512
+ if (!isOriginalLoaded) {
+ return [width, height]
+ }
+ if (renders.length === 0) {
+ width = original.naturalWidth
+ height = original.naturalHeight
+ } else if (renders.length !== 0) {
+ width = renders[renders.length - 1].width
+ height = renders[renders.length - 1].height
+ }
+
+ return [width, height]
+ }, [original, isOriginalLoaded, renders])
+
+ // Draw once the original image is loaded
+ useEffect(() => {
+ if (!isOriginalLoaded) {
+ return
+ }
+
+ const [width, height] = getCurrentWidthHeight()
+ setImageWidth(width)
+ setImageHeight(height)
+
+ const rW = windowSize.width / width
+ const rH = (windowSize.height - TOOLBAR_SIZE) / height
+
+ let s = 1.0
+ if (rW < 1 || rH < 1) {
+ s = Math.min(rW, rH)
+ }
+ setMinScale(s)
+ setScale(s)
+
+ console.log(
+ `[on file load] image size: ${width}x${height}, canvas size: ${context?.canvas.width}x${context?.canvas.height} scale: ${s}, initialCentered: ${initialCentered}`
+ )
+
+ if (context?.canvas) {
+ context.canvas.width = width
+ context.canvas.height = height
+ console.log("[on file load] set canvas size && drawOnCurrentRender")
+ drawOnCurrentRender([])
+ }
+
+ if (!initialCentered) {
+ // 防止每次擦除以后图片 zoom 还原
+ viewportRef.current?.centerView(s, 1)
+ console.log("[on file load] centerView")
+ setInitialCentered(true)
+ }
+ }, [
+ // context?.canvas,
+ viewportRef,
+ original,
+ isOriginalLoaded,
+ windowSize,
+ initialCentered,
+ drawOnCurrentRender,
+ getCurrentWidthHeight,
+ ])
+
+ useEffect(() => {
+ console.log("[useEffect] centerView")
+ // render 改变尺寸以后,undo/redo 重新 center
+ viewportRef?.current?.centerView(minScale, 1)
+ }, [context?.canvas.height, context?.canvas.width, viewportRef, minScale])
+
+ // Zoom reset
+ const resetZoom = useCallback(() => {
+ if (!minScale || !windowSize) {
+ return
+ }
+ const viewport = viewportRef.current
+ if (!viewport) {
+ return
+ }
+ const offsetX = (windowSize.width - imageWidth * minScale) / 2
+ const offsetY = (windowSize.height - imageHeight * minScale) / 2
+ viewport.setTransform(offsetX, offsetY, minScale, 200, "easeOutQuad")
+ if (viewport.state) {
+ viewport.state.scale = minScale
+ }
+
+ setScale(minScale)
+ setPanned(false)
+ }, [
+ viewportRef,
+ windowSize,
+ imageHeight,
+ imageWidth,
+ windowSize.height,
+ minScale,
+ ])
+
+ const resetRedoState = () => {
+ setRedoCurLines([])
+ setRedoLineGroups([])
+ setRedoRenders([])
+ }
+
+ useEffect(() => {
+ window.addEventListener("resize", () => {
+ resetZoom()
+ })
+ return () => {
+ window.removeEventListener("resize", () => {
+ resetZoom()
+ })
+ }
+ }, [windowSize, resetZoom])
+
+ useEffect(() => {
+ window.addEventListener("blur", () => {
+ setIsChangingBrushSizeByMouse(false)
+ })
+ return () => {
+ window.removeEventListener("blur", () => {
+ setIsChangingBrushSizeByMouse(false)
+ })
+ }
+ }, [])
+
+ const onInteractiveCancel = useCallback(() => {
+ setIsInteractiveSeg(false)
+ setIsInteractiveSegRunning(false)
+ setClicks([])
+ setTmpInteractiveSegMask(null)
+ }, [])
+
+ const handleEscPressed = () => {
+ if (isProcessing) {
+ return
+ }
+
+ if (isInteractiveSeg) {
+ onInteractiveCancel()
+ return
+ }
+
+ if (isDraging || isMultiStrokeKeyPressed) {
+ setIsDraging(false)
+ setCurLineGroup([])
+ drawOnCurrentRender([])
+ } else {
+ resetZoom()
+ }
+ }
+
+ useHotkeys("Escape", handleEscPressed, [
+ isDraging,
+ isInpainting,
+ isMultiStrokeKeyPressed,
+ isInteractiveSeg,
+ onInteractiveCancel,
+ resetZoom,
+ drawOnCurrentRender,
+ ])
+
+ const onMouseMove = (ev: SyntheticEvent) => {
+ const mouseEvent = ev.nativeEvent as MouseEvent
+ setCoords({ x: mouseEvent.pageX, y: mouseEvent.pageY })
+ }
+
+ const onMouseDrag = (ev: SyntheticEvent) => {
+ if (isChangingBrushSizeByMouse) {
+ const initX = changeBrushSizeByMouseInit.x
+ // move right: increase brush size
+ const newSize = changeBrushSizeByMouseInit.brushSize + (x - initX)
+ if (newSize <= MAX_BRUSH_SIZE && newSize >= MIN_BRUSH_SIZE) {
+ setBrushSize(newSize)
+ }
+ return
+ }
+ if (isInteractiveSeg) {
+ return
+ }
+ if (isPanning) {
+ return
+ }
+ if (!isDraging) {
+ return
+ }
+ if (curLineGroup.length === 0) {
+ return
+ }
+ const lineGroup = [...curLineGroup]
+ lineGroup[lineGroup.length - 1].pts.push(mouseXY(ev))
+ setCurLineGroup(lineGroup)
+ drawOnCurrentRender(lineGroup)
+ }
+
+ const runInteractiveSeg = async (newClicks: number[][]) => {
+ if (!file) {
+ return
+ }
+
+ setIsInteractiveSegRunning(true)
+ const targetFile = await getCurrentRender()
+ const prevMask = null
+ try {
+ const res = await runPlugin(
+ PluginName.InteractiveSeg,
+ targetFile,
+ undefined,
+ prevMask,
+ newClicks
+ )
+ if (!res) {
+ throw new Error("Something went wrong on server side.")
+ }
+ const { blob } = res
+ const img = new Image()
+ img.onload = () => {
+ setTmpInteractiveSegMask(img)
+ }
+ img.src = blob
+ } catch (e: any) {
+ setToastState({
+ open: true,
+ desc: e.message ? e.message : e.toString(),
+ state: "error",
+ duration: 4000,
+ })
+ }
+ setIsInteractiveSegRunning(false)
+ }
+
+ const onPointerUp = (ev: SyntheticEvent) => {
+ if (isMidClick(ev)) {
+ setIsPanning(false)
+ }
+ if (isInteractiveSeg) {
+ return
+ }
+
+ if (isPanning) {
+ return
+ }
+ if (!original.src) {
+ return
+ }
+ const canvas = context?.canvas
+ if (!canvas) {
+ return
+ }
+ if (isInpainting) {
+ return
+ }
+ if (!isDraging) {
+ return
+ }
+
+ if (isMultiStrokeKeyPressed) {
+ setIsDraging(false)
+ return
+ }
+
+ if (runMannually) {
+ setIsDraging(false)
+ } else {
+ runInpainting()
+ }
+ }
+
+ const isOutsideCroper = (clickPnt: { x: number; y: number }) => {
+ if (clickPnt.x < croperRect.x) {
+ return true
+ }
+ if (clickPnt.y < croperRect.y) {
+ return true
+ }
+ if (clickPnt.x > croperRect.x + croperRect.width) {
+ return true
+ }
+ if (clickPnt.y > croperRect.y + croperRect.height) {
+ return true
+ }
+ return false
+ }
+
+ const onCanvasMouseUp = (ev: SyntheticEvent) => {
+ if (isInteractiveSeg) {
+ const xy = mouseXY(ev)
+ const isX = xy.x
+ const isY = xy.y
+ const newClicks: number[][] = [...clicks]
+ if (isRightClick(ev)) {
+ newClicks.push([isX, isY, 0, newClicks.length])
+ } else {
+ newClicks.push([isX, isY, 1, newClicks.length])
+ }
+ // runInteractiveSeg(newClicks)
+ setClicks(newClicks)
+ }
+ }
+
+ const onMouseDown = (ev: SyntheticEvent) => {
+ if (isProcessing) {
+ return
+ }
+ if (isInteractiveSeg) {
+ return
+ }
+ if (isChangingBrushSizeByMouse) {
+ return
+ }
+ if (isPanning) {
+ return
+ }
+ if (!original.src) {
+ return
+ }
+ const canvas = context?.canvas
+ if (!canvas) {
+ return
+ }
+
+ if (isRightClick(ev)) {
+ return
+ }
+
+ if (isMidClick(ev)) {
+ setIsPanning(true)
+ return
+ }
+
+ if (
+ isDiffusionModels &&
+ settings.showCroper &&
+ isOutsideCroper(mouseXY(ev))
+ ) {
+ return
+ }
+
+ setIsDraging(true)
+
+ let lineGroup: LineGroup = []
+ if (isMultiStrokeKeyPressed || runMannually) {
+ lineGroup = [...curLineGroup]
+ }
+ lineGroup.push({ size: brushSize, pts: [mouseXY(ev)] })
+ setCurLineGroup(lineGroup)
+ drawOnCurrentRender(lineGroup)
+ }
+
+ const undoStroke = useCallback(() => {
+ if (curLineGroup.length === 0) {
+ return
+ }
+ setLastLineGroup([])
+
+ const lastLine = curLineGroup.pop()!
+ const newRedoCurLines = [...redoCurLines, lastLine]
+ setRedoCurLines(newRedoCurLines)
+
+ const newLineGroup = [...curLineGroup]
+ setCurLineGroup(newLineGroup)
+ drawOnCurrentRender(newLineGroup)
+ }, [curLineGroup, redoCurLines, drawOnCurrentRender])
+
+ const undoRender = useCallback(() => {
+ if (!renders.length) {
+ return
+ }
+
+ // save line Group
+ const latestLineGroup = lineGroups.pop()!
+ setRedoLineGroups([...redoLineGroups, latestLineGroup])
+ // If render is undo, clear strokes
+ setRedoCurLines([])
+
+ setLineGroups([...lineGroups])
+ setCurLineGroup([])
+ setIsDraging(false)
+
+ // save render
+ const lastRender = renders.pop()!
+ setRedoRenders([...redoRenders, lastRender])
+
+ const newRenders = [...renders]
+ setRenders(newRenders)
+ // if (newRenders.length === 0) {
+ // draw(original, [])
+ // } else {
+ // draw(newRenders[newRenders.length - 1], [])
+ // }
+ }, [
+ draw,
+ renders,
+ redoRenders,
+ redoLineGroups,
+ lineGroups,
+ original,
+ context,
+ ])
+
+ const undo = () => {
+ // TODO: prevent default event
+ console.log("undo")
+ if (runMannually && curLineGroup.length !== 0) {
+ undoStroke()
+ } else {
+ undoRender()
+ }
+ }
+
+ useHotkeys("meta+z,ctrl+z", undo, undefined, [
+ undoStroke,
+ undoRender,
+ runMannually,
+ curLineGroup,
+ context?.canvas,
+ renders,
+ ])
+
+ const disableUndo = () => {
+ if (isProcessing) {
+ return true
+ }
+ if (renders.length > 0) {
+ return false
+ }
+
+ if (runMannually) {
+ if (curLineGroup.length === 0) {
+ return true
+ }
+ } else if (renders.length === 0) {
+ return true
+ }
+
+ return false
+ }
+
+ const redoStroke = useCallback(() => {
+ if (redoCurLines.length === 0) {
+ return
+ }
+ const line = redoCurLines.pop()!
+ setRedoCurLines([...redoCurLines])
+
+ const newLineGroup = [...curLineGroup, line]
+ setCurLineGroup(newLineGroup)
+ drawOnCurrentRender(newLineGroup)
+ }, [curLineGroup, redoCurLines, drawOnCurrentRender])
+
+ const redoRender = useCallback(() => {
+ if (redoRenders.length === 0) {
+ return
+ }
+ const lineGroup = redoLineGroups.pop()!
+ setRedoLineGroups([...redoLineGroups])
+
+ setLineGroups([...lineGroups, lineGroup])
+ setCurLineGroup([])
+ setIsDraging(false)
+
+ const render = redoRenders.pop()!
+ const newRenders = [...renders, render]
+ setRenders(newRenders)
+ // draw(newRenders[newRenders.length - 1], [])
+ }, [draw, renders, redoRenders, redoLineGroups, lineGroups, original])
+
+ const redo = () => {
+ if (runMannually && redoCurLines.length !== 0) {
+ redoStroke()
+ } else {
+ redoRender()
+ }
+ }
+
+ // Handle Cmd+shift+Z
+ const redoPredicate = (event: KeyboardEvent) => {
+ const isCmdZ =
+ (event.metaKey || event.ctrlKey) &&
+ event.shiftKey &&
+ event.key.toLowerCase() === "z"
+ // Handle tab switch
+ if (event.key === "Tab") {
+ event.preventDefault()
+ }
+ if (isCmdZ) {
+ event.preventDefault()
+ return true
+ }
+ return false
+ }
+
+ // useKey(redoPredicate, redo, undefined, [
+ // redoStroke,
+ // redoRender,
+ // runMannually,
+ // redoCurLines,
+ // ])
+
+ const disableRedo = () => {
+ if (isProcessing) {
+ return true
+ }
+ if (redoRenders.length > 0) {
+ return false
+ }
+
+ if (runMannually) {
+ if (redoCurLines.length === 0) {
+ return true
+ }
+ } else if (redoRenders.length === 0) {
+ return true
+ }
+
+ return false
+ }
+
+ // useKeyPressEvent(
+ // "Tab",
+ // (ev) => {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // if (hadRunInpainting()) {
+ // setShowOriginal(() => {
+ // window.setTimeout(() => {
+ // setSliderPos(100)
+ // }, 10)
+ // return true
+ // })
+ // }
+ // },
+ // (ev) => {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // if (hadRunInpainting()) {
+ // setSliderPos(0)
+ // window.setTimeout(() => {
+ // setShowOriginal(false)
+ // }, 350)
+ // }
+ // }
+ // )
+
+ function download() {
+ if (file === undefined) {
+ return
+ }
+ if ((enableFileManager || isEnableAutoSaving) && renders.length > 0) {
+ try {
+ downloadToOutput(renders[renders.length - 1], file.name, file.type)
+ setToastState({
+ open: true,
+ desc: `Save image success`,
+ state: "success",
+ duration: 2000,
+ })
+ } catch (e: any) {
+ setToastState({
+ open: true,
+ desc: e.message ? e.message : e.toString(),
+ state: "error",
+ duration: 2000,
+ })
+ }
+ return
+ }
+
+ // TODO: download to output directory
+ const name = file.name.replace(/(\.[\w\d_-]+)$/i, "_cleanup$1")
+ const curRender = renders[renders.length - 1]
+ downloadImage(curRender.currentSrc, name)
+ if (settings.downloadMask) {
+ let maskFileName = file.name.replace(/(\.[\w\d_-]+)$/i, "_mask$1")
+ maskFileName = maskFileName.replace(/\.[^/.]+$/, ".jpg")
+
+ drawLinesOnMask(lineGroups)
+ // Create a link
+ const aDownloadLink = document.createElement("a")
+ // Add the name of the file to the link
+ aDownloadLink.download = maskFileName
+ // Attach the data to the link
+ aDownloadLink.href = maskCanvas.toDataURL("image/jpeg")
+ // Get the code to click the download link
+ aDownloadLink.click()
+ }
+ }
+
+ const toggleShowBrush = (newState: boolean) => {
+ if (newState !== showBrush && !isPanning) {
+ setShowBrush(newState)
+ }
+ }
+
+ const getCursor = useCallback(() => {
+ if (isPanning) {
+ return "grab"
+ }
+ if (showBrush) {
+ return "none"
+ }
+ return undefined
+ }, [showBrush, isPanning])
+
+ // Standard Hotkeys for Brush Size
+ // useHotKey("[", () => {
+ // setBrushSize((currentBrushSize: number) => {
+ // if (currentBrushSize > 10) {
+ // return currentBrushSize - 10
+ // }
+ // if (currentBrushSize <= 10 && currentBrushSize > 0) {
+ // return currentBrushSize - 5
+ // }
+ // return currentBrushSize
+ // })
+ // })
+
+ // useHotKey("]", () => {
+ // setBrushSize((currentBrushSize: number) => {
+ // return currentBrushSize + 10
+ // })
+ // })
+
+ // // Manual Inpainting Hotkey
+ // useHotKey(
+ // "shift+r",
+ // () => {
+ // if (runMannually && hadDrawSomething()) {
+ // runInpainting()
+ // }
+ // },
+ // {},
+ // [runMannually, runInpainting, hadDrawSomething]
+ // )
+
+ // useHotKey(
+ // "ctrl+c, cmd+c",
+ // async () => {
+ // const hasPermission = await askWritePermission()
+ // if (hasPermission && renders.length > 0) {
+ // if (context?.canvas) {
+ // await copyCanvasImage(context?.canvas)
+ // setToastState({
+ // open: true,
+ // desc: "Copy inpainting result to clipboard",
+ // state: "success",
+ // duration: 3000,
+ // })
+ // }
+ // }
+ // },
+ // {},
+ // [renders, context]
+ // )
+
+ // Toggle clean/zoom tool on spacebar.
+ // useKeyPressEvent(
+ // " ",
+ // (ev) => {
+ // if (!app.disableShortCuts) {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // setShowBrush(false)
+ // setIsPanning(true)
+ // }
+ // },
+ // (ev) => {
+ // if (!app.disableShortCuts) {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // setShowBrush(true)
+ // setIsPanning(false)
+ // }
+ // }
+ // )
+
+ // useKeyPressEvent(
+ // "Alt",
+ // (ev) => {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // setIsChangingBrushSizeByMouse(true)
+ // setChangeBrushSizeByMouseInit({ x, y, brushSize })
+ // },
+ // (ev) => {
+ // ev?.preventDefault()
+ // ev?.stopPropagation()
+ // setIsChangingBrushSizeByMouse(false)
+ // }
+ // )
+
+ const getCurScale = (): number => {
+ let s = minScale
+ if (viewportRef.current?.state?.scale !== undefined) {
+ s = viewportRef.current?.state.scale
+ }
+ return s!
+ }
+
+ const getBrushStyle = (_x: number, _y: number) => {
+ const curScale = getCurScale()
+ return {
+ width: `${brushSize * curScale}px`,
+ height: `${brushSize * curScale}px`,
+ left: `${_x}px`,
+ top: `${_y}px`,
+ transform: "translate(-50%, -50%)",
+ }
+ }
+
+ const handleSliderChange = (value: number) => {
+ setBrushSize(value)
+
+ if (!showRefBrush) {
+ setShowRefBrush(true)
+ window.setTimeout(() => {
+ setShowRefBrush(false)
+ }, 10000)
+ }
+ }
+
+ const renderInteractiveSegCursor = () => {
+ return (
+
+
+
+ )
+ }
+
+ const renderCanvas = () => {
+ return (
+ {
+ if (!panned) {
+ setPanned(true)
+ }
+ }}
+ onZoom={(ref) => {
+ setScale(ref.state.scale)
+ }}
+ >
+
+
+
+
+ {/* */}
+
+ {/* {isInteractiveSeg ? : <>>} */}
+
+
+ )
+ }
+
+ const onInteractiveAccept = () => {
+ setInteractiveSegMask(tmpInteractiveSegMask)
+ setTmpInteractiveSegMask(null)
+
+ if (!runMannually && tmpInteractiveSegMask) {
+ runInpainting(false, undefined, tmpInteractiveSegMask)
+ }
+ }
+
+ return (
+
+ {/*
*/}
+ {/*
*/}
+ {renderCanvas()}
+
+ {showBrush &&
+ !isInpainting &&
+ !isPanning &&
+ (isInteractiveSeg ? (
+ renderInteractiveSegCursor()
+ ) : (
+
+ ))}
+
+ {showRefBrush && (
+
+ )}
+
+
+
handleSliderChange(vals[0])}
+ onClick={() => setShowRefBrush(false)}
+ />
+
+
+
+
+
+
+
+
+
+
+
{
+ // ev.preventDefault()
+ // setShowOriginal(() => {
+ // window.setTimeout(() => {
+ // setSliderPos(100)
+ // }, 10)
+ // return true
+ // })
+ // }}
+ // onUp={() => {
+ // setSliderPos(0)
+ // window.setTimeout(() => {
+ // setShowOriginal(false)
+ // }, 300)
+ // }}
+ disabled={renders.length === 0}
+ >
+
+
+
+
+
+
+ {settings.runInpaintingManually && !isDiffusionModels && (
+
{
+ // ensured by disabled
+ runInpainting(false, undefined, interactiveSegMask)
+ }}
+ >
+
+
+ )}
+
+
+ {/*
{
+ onInteractiveCancel()
+ setShowInteractiveSegModal(false)
+ }}
+ onCleanClick={() => {
+ onInteractiveCancel()
+ setInteractiveSegMask(null)
+ }}
+ onReplaceClick={() => {
+ setShowInteractiveSegModal(false)
+ setIsInteractiveSeg(true)
+ }}
+ /> */}
+
+ )
+}
diff --git a/web_app/src/components/FileManager.tsx b/web_app/src/components/FileManager.tsx
new file mode 100644
index 0000000..51e1496
--- /dev/null
+++ b/web_app/src/components/FileManager.tsx
@@ -0,0 +1,321 @@
+import {
+ SyntheticEvent,
+ useEffect,
+ useState,
+ useCallback,
+ useRef,
+ FormEvent,
+} from "react"
+import _ from "lodash"
+import { useRecoilState } from "recoil"
+import PhotoAlbum from "react-photo-album"
+import {
+ BarsArrowDownIcon,
+ BarsArrowUpIcon,
+ FolderIcon,
+} from "@heroicons/react/24/outline"
+import {
+ MagnifyingGlassIcon,
+ ViewHorizontalIcon,
+ ViewGridIcon,
+} from "@radix-ui/react-icons"
+import { useDebounce, useToggle } from "react-use"
+import FlexSearch from "flexsearch/dist/flexsearch.bundle.js"
+import {
+ fileManagerLayout,
+ fileManagerSearchText,
+ fileManagerSortBy,
+ fileManagerSortOrder,
+ SortBy,
+ SortOrder,
+} from "@/lib/store"
+import { useToast } from "@/components/ui/use-toast"
+import { API_ENDPOINT, getMedias } from "@/lib/api"
+import { IconButton } from "./ui/button"
+import { Input } from "./ui/input"
+import { Dialog, DialogContent, DialogTitle } from "./ui/dialog"
+import { Tabs, TabsList, TabsTrigger } from "./ui/tabs"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "./ui/select"
+import { ScrollArea } from "./ui/scroll-area"
+import { DialogTrigger } from "@radix-ui/react-dialog"
+import { useHotkeys } from "react-hotkeys-hook"
+
+interface Photo {
+ src: string
+ height: number
+ width: number
+ name: string
+}
+
+interface Filename {
+ name: string
+ height: number
+ width: number
+ ctime: number
+ mtime: number
+}
+
+const SORT_BY_NAME = "Name"
+const SORT_BY_CREATED_TIME = "Created time"
+const SORT_BY_MODIFIED_TIME = "Modified time"
+
+const IMAGE_TAB = "image"
+const OUTPUT_TAB = "output"
+
+const SortByMap = {
+ [SortBy.NAME]: SORT_BY_NAME,
+ [SortBy.CTIME]: SORT_BY_CREATED_TIME,
+ [SortBy.MTIME]: SORT_BY_MODIFIED_TIME,
+}
+
+interface Props {
+ onPhotoClick(tab: string, filename: string): void
+ photoWidth: number
+}
+
+export default function FileManager(props: Props) {
+ const { onPhotoClick, photoWidth } = props
+ const [open, toggleOpen] = useToggle(false)
+
+ useHotkeys("f", () => {
+ toggleOpen()
+ })
+
+ const { toast } = useToast()
+ const [scrollTop, setScrollTop] = useState(0)
+ const [closeScrollTop, setCloseScrollTop] = useState(0)
+
+ const [sortBy, setSortBy] = useRecoilState(fileManagerSortBy)
+ const [sortOrder, setSortOrder] = useRecoilState(fileManagerSortOrder)
+ const [layout, setLayout] = useRecoilState(fileManagerLayout)
+ const [debouncedSearchText, setDebouncedSearchText] = useRecoilState(
+ fileManagerSearchText
+ )
+ const ref = useRef(null)
+ const [searchText, setSearchText] = useState(debouncedSearchText)
+ const [tab, setTab] = useState(IMAGE_TAB)
+ const [photos, setPhotos] = useState([])
+
+ const [, cancel] = useDebounce(
+ () => {
+ setDebouncedSearchText(searchText)
+ },
+ 300,
+ [searchText]
+ )
+
+ useEffect(() => {
+ if (!open) {
+ setCloseScrollTop(scrollTop)
+ }
+ }, [open, scrollTop])
+
+ const onRefChange = useCallback(
+ (node: HTMLDivElement) => {
+ if (node !== null) {
+ if (open) {
+ setTimeout(() => {
+ // TODO: without timeout, scrollTo not work, why?
+ node.scrollTo({ top: closeScrollTop, left: 0 })
+ }, 100)
+ }
+ }
+ },
+ [open, closeScrollTop]
+ )
+
+ useEffect(() => {
+ if (!open) {
+ return
+ }
+ const fetchData = async () => {
+ try {
+ const filenames = await getMedias(tab)
+ let filteredFilenames = filenames
+ if (debouncedSearchText) {
+ const index = new FlexSearch.Index({
+ tokenize: "forward",
+ minlength: 1,
+ })
+ filenames.forEach((filename: Filename, id: number) =>
+ index.add(id, filename.name)
+ )
+ const results: FlexSearch.IndexSearchResult =
+ index.search(debouncedSearchText)
+ filteredFilenames = results.map(
+ (id: FlexSearch.Id) => filenames[id as number]
+ )
+ }
+
+ filteredFilenames = _.orderBy(filteredFilenames, sortBy, sortOrder)
+
+ const newPhotos = filteredFilenames.map((filename: Filename) => {
+ const width = photoWidth
+ const height = filename.height * (width / filename.width)
+ const src = `${API_ENDPOINT}/media_thumbnail/${tab}/${filename.name}?width=${width}&height=${height}`
+ return { src, height, width, name: filename.name }
+ })
+ setPhotos(newPhotos)
+ } catch (e: any) {
+ toast({
+ variant: "destructive",
+ title: "Uh oh! Something went wrong.",
+ description: e.message ? e.message : e.toString(),
+ })
+ }
+ }
+ fetchData()
+ }, [tab, debouncedSearchText, sortBy, sortOrder, photoWidth, open])
+
+ const onScroll = (event: SyntheticEvent) => {
+ setScrollTop(event.currentTarget.scrollTop)
+ }
+
+ const onClick = ({ index }: { index: number }) => {
+ toggleOpen()
+ onPhotoClick(tab, photos[index].name)
+ }
+
+ const renderTitle = () => {
+ return (
+
+
{`Images (${photos.length})`}
+
+ {
+ setLayout("rows")
+ }}
+ >
+
+
+ {
+ setLayout("masonry")
+ }}
+ className={layout !== "masonry" ? "opacity-50" : ""}
+ >
+
+
+
+
+ )
+ }
+
+ return (
+
+ )
+}
diff --git a/web_app/src/components/FileSelect.tsx b/web_app/src/components/FileSelect.tsx
new file mode 100644
index 0000000..8f78b73
--- /dev/null
+++ b/web_app/src/components/FileSelect.tsx
@@ -0,0 +1,71 @@
+import React, { useState } from "react"
+import useResolution from "@/hooks/useResolution"
+
+type FileSelectProps = {
+ onSelection: (file: File) => void
+}
+
+export default function FileSelect(props: FileSelectProps) {
+ const { onSelection } = props
+
+ const [uploadElemId] = useState(`file-upload-${Math.random().toString()}`)
+
+ const resolution = useResolution()
+
+ function onFileSelected(file: File) {
+ if (!file) {
+ return
+ }
+ // Skip non-image files
+ const isImage = file.type.match("image.*")
+ if (!isImage) {
+ return
+ }
+ try {
+ // Check if file is larger than 20mb
+ if (file.size > 20 * 1024 * 1024) {
+ throw new Error("file too large")
+ }
+ onSelection(file)
+ } catch (e) {
+ // eslint-disable-next-line
+ alert(`error: ${(e as any).message}`)
+ }
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/web_app/src/components/Header.tsx b/web_app/src/components/Header.tsx
new file mode 100644
index 0000000..f84fe60
--- /dev/null
+++ b/web_app/src/components/Header.tsx
@@ -0,0 +1,173 @@
+import { FolderIcon, PhotoIcon } from "@heroicons/react/24/outline"
+import { PlayIcon } from "@radix-ui/react-icons"
+import React, { useCallback, useState } from "react"
+import { useRecoilState, useRecoilValue } from "recoil"
+import { useHotkeys } from "react-hotkeys-hook"
+import {
+ enableFileManagerState,
+ fileState,
+ isInpaintingState,
+ isPix2PixState,
+ isSDState,
+ maskState,
+ runManuallyState,
+ showFileManagerState,
+} from "@/lib/store"
+import { Button, IconButton, ImageUploadButton } from "@/components/ui/button"
+import Shortcuts from "@/components/Shortcuts"
+// import SettingIcon from "../Settings/SettingIcon"
+// import PromptInput from "./PromptInput"
+// import CoffeeIcon from '../CoffeeIcon/CoffeeIcon'
+import emitter, {
+ DREAM_BUTTON_MOUSE_ENTER,
+ DREAM_BUTTON_MOUSE_LEAVE,
+ EVENT_CUSTOM_MASK,
+ RERUN_LAST_MASK,
+} from "@/lib/event"
+import { useImage } from "@/hooks/useImage"
+
+import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"
+import PromptInput from "./PromptInput"
+import { RotateCw } from "lucide-react"
+import FileManager from "./FileManager"
+import { getMediaFile } from "@/lib/api"
+
+const Header = () => {
+ const isInpainting = useRecoilValue(isInpaintingState)
+ const [file, setFile] = useRecoilState(fileState)
+ const [mask, setMask] = useRecoilState(maskState)
+ const [maskImage, maskImageLoaded] = useImage(mask)
+ const isSD = useRecoilValue(isSDState)
+ const isPix2Pix = useRecoilValue(isPix2PixState)
+ const runManually = useRecoilValue(runManuallyState)
+ const [openMaskPopover, setOpenMaskPopover] = useState(false)
+ const enableFileManager = useRecoilValue(enableFileManagerState)
+
+ const handleRerunLastMask = useCallback(() => {
+ emitter.emit(RERUN_LAST_MASK)
+ }, [])
+
+ const onRerunMouseEnter = () => {
+ emitter.emit(DREAM_BUTTON_MOUSE_ENTER)
+ }
+
+ const onRerunMouseLeave = () => {
+ emitter.emit(DREAM_BUTTON_MOUSE_LEAVE)
+ }
+
+ useHotkeys(
+ "r",
+ () => {
+ if (!isInpainting) {
+ handleRerunLastMask()
+ }
+ },
+ {},
+ [isInpainting, handleRerunLastMask]
+ )
+
+ return (
+
+ )
+}
+
+export default Header
diff --git a/web_app/src/components/PromptInput.tsx b/web_app/src/components/PromptInput.tsx
new file mode 100644
index 0000000..67e9585
--- /dev/null
+++ b/web_app/src/components/PromptInput.tsx
@@ -0,0 +1,66 @@
+import React, { FormEvent } from "react"
+import { useRecoilState, useRecoilValue } from "recoil"
+import emitter, {
+ DREAM_BUTTON_MOUSE_ENTER,
+ DREAM_BUTTON_MOUSE_LEAVE,
+ EVENT_PROMPT,
+} from "@/lib/event"
+import { appState, isInpaintingState, propmtState } from "@/lib/store"
+import { Button } from "./ui/button"
+import { Input } from "./ui/input"
+
+const PromptInput = () => {
+ const app = useRecoilValue(appState)
+ const [prompt, setPrompt] = useRecoilState(propmtState)
+ const isInpainting = useRecoilValue(isInpaintingState)
+
+ const handleOnInput = (evt: FormEvent) => {
+ evt.preventDefault()
+ evt.stopPropagation()
+ const target = evt.target as HTMLInputElement
+ setPrompt(target.value)
+ }
+
+ const handleRepaintClick = () => {
+ if (prompt.length !== 0 && !app.isInpainting) {
+ emitter.emit(EVENT_PROMPT)
+ }
+ }
+
+ const onKeyUp = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter" && !isInpainting) {
+ handleRepaintClick()
+ }
+ }
+
+ const onMouseEnter = () => {
+ emitter.emit(DREAM_BUTTON_MOUSE_ENTER)
+ }
+
+ const onMouseLeave = () => {
+ emitter.emit(DREAM_BUTTON_MOUSE_LEAVE)
+ }
+
+ return (
+
+
+
+
+ )
+}
+
+export default PromptInput
diff --git a/web_app/src/components/Shortcuts.tsx b/web_app/src/components/Shortcuts.tsx
new file mode 100644
index 0000000..a08ad3f
--- /dev/null
+++ b/web_app/src/components/Shortcuts.tsx
@@ -0,0 +1,97 @@
+import { Keyboard } from "lucide-react"
+import useHotKey from "@/hooks/useHotkey"
+import { IconButton } from "@/components/ui/button"
+import { useToggle } from "@uidotdev/usehooks"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "./ui/dialog"
+
+interface ShortcutProps {
+ content: string
+ keys: string[]
+}
+
+function ShortCut(props: ShortcutProps) {
+ const { content, keys } = props
+
+ return (
+
+
{content}
+
+ {keys.map((k) => (
+ // TODO: 优化快捷键显示
+
+ {k}
+
+ ))}
+
+
+ )
+}
+
+const isMac = function () {
+ return /macintosh|mac os x/i.test(navigator.userAgent)
+}
+
+const isWindows = function () {
+ return /windows|win32/i.test(navigator.userAgent)
+}
+
+const CmdOrCtrl = () => {
+ return isMac() ? "Cmd" : "Ctrl"
+}
+
+export function Shortcuts() {
+ const [open, toggleOpen] = useToggle(false)
+
+ useHotKey("h", () => {
+ toggleOpen()
+ })
+
+ return (
+
+ )
+}
+
+export default Shortcuts
diff --git a/web_app/src/components/Workspace.tsx b/web_app/src/components/Workspace.tsx
new file mode 100644
index 0000000..56d96a0
--- /dev/null
+++ b/web_app/src/components/Workspace.tsx
@@ -0,0 +1,114 @@
+import React, { useEffect } from "react"
+import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"
+import Editor from "./Editor"
+// import SettingModal from "./Settings/SettingsModal"
+// import Toast from "./shared/Toast"
+import {
+ AIModel,
+ fileState,
+ isPaintByExampleState,
+ isPix2PixState,
+ isSDState,
+ settingState,
+ showFileManagerState,
+ toastState,
+} from "@/lib/store"
+import {
+ currentModel,
+ getMediaFile,
+ modelDownloaded,
+ switchModel,
+} from "@/lib/api"
+// import SidePanel from "./SidePanel/SidePanel"
+// import PESidePanel from "./SidePanel/PESidePanel"
+// import FileManager from "./FileManager/FileManager"
+// import P2PSidePanel from "./SidePanel/P2PSidePanel"
+// import Plugins from "./Plugins/Plugins"
+// import Flex from "./shared/Layout"
+// import ImageSize from "./ImageSize/ImageSize"
+
+const Workspace = () => {
+ const setFile = useSetRecoilState(fileState)
+ const [settings, setSettingState] = useRecoilState(settingState)
+ const [toastVal, setToastState] = useRecoilState(toastState)
+ const isSD = useRecoilValue(isSDState)
+ const isPaintByExample = useRecoilValue(isPaintByExampleState)
+ const isPix2Pix = useRecoilValue(isPix2PixState)
+
+ const onSettingClose = async () => {
+ const curModel = await currentModel().then((res) => res.text())
+ if (curModel === settings.model) {
+ return
+ }
+ const downloaded = await modelDownloaded(settings.model).then((res) =>
+ res.text()
+ )
+
+ const { model } = settings
+
+ let loadingMessage = `Switching to ${model} model`
+ let loadingDuration = 3000
+ if (downloaded === "False") {
+ loadingMessage = `Downloading ${model} model, this may take a while`
+ loadingDuration = 9999999999
+ }
+
+ setToastState({
+ open: true,
+ desc: loadingMessage,
+ state: "loading",
+ duration: loadingDuration,
+ })
+
+ switchModel(model)
+ .then((res) => {
+ if (res.ok) {
+ setToastState({
+ open: true,
+ desc: `Switch to ${model} model success`,
+ state: "success",
+ duration: 3000,
+ })
+ } else {
+ throw new Error("Server error")
+ }
+ })
+ .catch(() => {
+ setToastState({
+ open: true,
+ desc: `Switch to ${model} model failed`,
+ state: "error",
+ duration: 3000,
+ })
+ setSettingState((old) => {
+ return { ...old, model: curModel as AIModel }
+ })
+ })
+ }
+
+ useEffect(() => {
+ currentModel()
+ .then((res) => res.text())
+ .then((model) => {
+ setSettingState((old) => {
+ return { ...old, model: model as AIModel }
+ })
+ })
+ }, [setSettingState])
+
+ return (
+ <>
+ {/* {isSD ? : <>>}
+ {isPaintByExample ? : <>>}
+ {isPix2Pix ? : <>>}
+
+
+
+
+ {/* */}
+
+ >
+ )
+}
+
+export default Workspace
diff --git a/web_app/src/components/theme-provider.tsx b/web_app/src/components/theme-provider.tsx
new file mode 100644
index 0000000..d89a82e
--- /dev/null
+++ b/web_app/src/components/theme-provider.tsx
@@ -0,0 +1,73 @@
+import { createContext, useContext, useEffect, useState } from "react"
+
+type Theme = "dark" | "light" | "system"
+
+type ThemeProviderProps = {
+ children: React.ReactNode
+ defaultTheme?: Theme
+ storageKey?: string
+}
+
+type ThemeProviderState = {
+ theme: Theme
+ setTheme: (theme: Theme) => void
+}
+
+const initialState: ThemeProviderState = {
+ theme: "system",
+ setTheme: () => null,
+}
+
+const ThemeProviderContext = createContext(initialState)
+
+export function ThemeProvider({
+ children,
+ defaultTheme = "system",
+ storageKey = "vite-ui-theme",
+ ...props
+}: ThemeProviderProps) {
+ const [theme, setTheme] = useState(
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
+ )
+
+ useEffect(() => {
+ const root = window.document.documentElement
+
+ root.classList.remove("light", "dark")
+
+ if (theme === "system") {
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
+ .matches
+ ? "dark"
+ : "light"
+
+ root.classList.add(systemTheme)
+ return
+ }
+
+ root.classList.add(theme)
+ }, [theme])
+
+ const value = {
+ theme,
+ setTheme: (theme: Theme) => {
+ localStorage.setItem(storageKey, theme)
+ setTheme(theme)
+ },
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
+export const useTheme = () => {
+ const context = useContext(ThemeProviderContext)
+
+ if (context === undefined)
+ throw new Error("useTheme must be used within a ThemeProvider")
+
+ return context
+}
diff --git a/web_app/src/components/ui/accordion.tsx b/web_app/src/components/ui/accordion.tsx
new file mode 100644
index 0000000..7e84c32
--- /dev/null
+++ b/web_app/src/components/ui/accordion.tsx
@@ -0,0 +1,55 @@
+import * as React from "react"
+import * as AccordionPrimitive from "@radix-ui/react-accordion"
+import { ChevronDownIcon } from "@radix-ui/react-icons"
+
+import { cn } from "@/lib/utils"
+
+const Accordion = AccordionPrimitive.Root
+
+const AccordionItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AccordionItem.displayName = "AccordionItem"
+
+const AccordionTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ svg]:rotate-180",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+))
+AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
+
+const AccordionContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ {children}
+
+))
+AccordionContent.displayName = AccordionPrimitive.Content.displayName
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/web_app/src/components/ui/button.tsx b/web_app/src/components/ui/button.tsx
new file mode 100644
index 0000000..657eb5e
--- /dev/null
+++ b/web_app/src/components/ui/button.tsx
@@ -0,0 +1,123 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+import { Input } from "./input"
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "./tooltip"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ outline:
+ "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-10 rounded-md px-8",
+ icon: "h-9 w-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export interface IconButtonProps extends ButtonProps {
+ tooltip: string
+}
+
+const IconButton = (props: IconButtonProps) => {
+ const { tooltip, children, ...rest } = props
+ return (
+ <>
+
+
+
+
+
+
+ {tooltip}
+
+
+
+ >
+ )
+}
+
+export interface UploadButtonProps extends IconButtonProps {
+ onFileUpload: (file: File) => void
+}
+
+const ImageUploadButton = (props: UploadButtonProps) => {
+ const { onFileUpload, children, ...rest } = props
+
+ const [uploadElemId] = React.useState(
+ `file-upload-${Math.random().toString()}`
+ )
+
+ const handleChange = (ev: React.ChangeEvent) => {
+ const newFile = ev.currentTarget.files?.[0]
+ if (newFile) {
+ onFileUpload(newFile)
+ }
+ }
+
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export { Button, IconButton, ImageUploadButton, buttonVariants }
diff --git a/web_app/src/components/ui/dialog.tsx b/web_app/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..f642998
--- /dev/null
+++ b/web_app/src/components/ui/dialog.tsx
@@ -0,0 +1,120 @@
+import * as React from "react"
+import * as DialogPrimitive from "@radix-ui/react-dialog"
+import { Cross2Icon } from "@radix-ui/react-icons"
+
+import { cn } from "@/lib/utils"
+
+const Dialog = DialogPrimitive.Root
+
+const DialogTrigger = DialogPrimitive.Trigger
+
+const DialogPortal = DialogPrimitive.Portal
+
+const DialogClose = DialogPrimitive.Close
+
+const DialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
+
+const DialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+))
+DialogContent.displayName = DialogPrimitive.Content.displayName
+
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+DialogHeader.displayName = "DialogHeader"
+
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+DialogFooter.displayName = "DialogFooter"
+
+const DialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogTitle.displayName = DialogPrimitive.Title.displayName
+
+const DialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+DialogDescription.displayName = DialogPrimitive.Description.displayName
+
+export {
+ Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogTrigger,
+ DialogClose,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+}
diff --git a/web_app/src/components/ui/input.tsx b/web_app/src/components/ui/input.tsx
new file mode 100644
index 0000000..a92b8e0
--- /dev/null
+++ b/web_app/src/components/ui/input.tsx
@@ -0,0 +1,25 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+export interface InputProps
+ extends React.InputHTMLAttributes {}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Input.displayName = "Input"
+
+export { Input }
diff --git a/web_app/src/components/ui/label.tsx b/web_app/src/components/ui/label.tsx
new file mode 100644
index 0000000..683faa7
--- /dev/null
+++ b/web_app/src/components/ui/label.tsx
@@ -0,0 +1,24 @@
+import * as React from "react"
+import * as LabelPrimitive from "@radix-ui/react-label"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+)
+
+const Label = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, ...props }, ref) => (
+
+))
+Label.displayName = LabelPrimitive.Root.displayName
+
+export { Label }
diff --git a/web_app/src/components/ui/popover.tsx b/web_app/src/components/ui/popover.tsx
new file mode 100644
index 0000000..bbba7e0
--- /dev/null
+++ b/web_app/src/components/ui/popover.tsx
@@ -0,0 +1,29 @@
+import * as React from "react"
+import * as PopoverPrimitive from "@radix-ui/react-popover"
+
+import { cn } from "@/lib/utils"
+
+const Popover = PopoverPrimitive.Root
+
+const PopoverTrigger = PopoverPrimitive.Trigger
+
+const PopoverContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+
+
+))
+PopoverContent.displayName = PopoverPrimitive.Content.displayName
+
+export { Popover, PopoverTrigger, PopoverContent }
diff --git a/web_app/src/components/ui/scroll-area.tsx b/web_app/src/components/ui/scroll-area.tsx
new file mode 100644
index 0000000..cf253cf
--- /dev/null
+++ b/web_app/src/components/ui/scroll-area.tsx
@@ -0,0 +1,46 @@
+import * as React from "react"
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+
+import { cn } from "@/lib/utils"
+
+const ScrollArea = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+ {children}
+
+
+
+
+))
+ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
+
+const ScrollBar = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, orientation = "vertical", ...props }, ref) => (
+
+
+
+))
+ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
+
+export { ScrollArea, ScrollBar }
diff --git a/web_app/src/components/ui/select.tsx b/web_app/src/components/ui/select.tsx
new file mode 100644
index 0000000..cdfb8ce
--- /dev/null
+++ b/web_app/src/components/ui/select.tsx
@@ -0,0 +1,162 @@
+import * as React from "react"
+import {
+ CaretSortIcon,
+ CheckIcon,
+ ChevronDownIcon,
+ ChevronUpIcon,
+} from "@radix-ui/react-icons"
+import * as SelectPrimitive from "@radix-ui/react-select"
+
+import { cn } from "@/lib/utils"
+
+const Select = SelectPrimitive.Root
+
+const SelectGroup = SelectPrimitive.Group
+
+const SelectValue = SelectPrimitive.Value
+
+const SelectTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+ span]:line-clamp-1",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+
+))
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+
+const SelectScrollUpButton = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
+
+const SelectScrollDownButton = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+SelectScrollDownButton.displayName =
+ SelectPrimitive.ScrollDownButton.displayName
+
+const SelectContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, position = "popper", ...props }, ref) => (
+
+
+
+
+ {children}
+
+
+
+
+))
+SelectContent.displayName = SelectPrimitive.Content.displayName
+
+const SelectLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SelectLabel.displayName = SelectPrimitive.Label.displayName
+
+const SelectItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+))
+SelectItem.displayName = SelectPrimitive.Item.displayName
+
+const SelectSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName
+
+export {
+ Select,
+ SelectGroup,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
+ SelectLabel,
+ SelectItem,
+ SelectSeparator,
+ SelectScrollUpButton,
+ SelectScrollDownButton,
+}
diff --git a/web_app/src/components/ui/slider.tsx b/web_app/src/components/ui/slider.tsx
new file mode 100644
index 0000000..9398b33
--- /dev/null
+++ b/web_app/src/components/ui/slider.tsx
@@ -0,0 +1,26 @@
+import * as React from "react"
+import * as SliderPrimitive from "@radix-ui/react-slider"
+
+import { cn } from "@/lib/utils"
+
+const Slider = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+
+
+))
+Slider.displayName = SliderPrimitive.Root.displayName
+
+export { Slider }
diff --git a/web_app/src/components/ui/switch.tsx b/web_app/src/components/ui/switch.tsx
new file mode 100644
index 0000000..455c23b
--- /dev/null
+++ b/web_app/src/components/ui/switch.tsx
@@ -0,0 +1,27 @@
+import * as React from "react"
+import * as SwitchPrimitives from "@radix-ui/react-switch"
+
+import { cn } from "@/lib/utils"
+
+const Switch = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+Switch.displayName = SwitchPrimitives.Root.displayName
+
+export { Switch }
diff --git a/web_app/src/components/ui/tabs.tsx b/web_app/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..85d83be
--- /dev/null
+++ b/web_app/src/components/ui/tabs.tsx
@@ -0,0 +1,53 @@
+import * as React from "react"
+import * as TabsPrimitive from "@radix-ui/react-tabs"
+
+import { cn } from "@/lib/utils"
+
+const Tabs = TabsPrimitive.Root
+
+const TabsList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+TabsList.displayName = TabsPrimitive.List.displayName
+
+const TabsTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
+
+const TabsContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+TabsContent.displayName = TabsPrimitive.Content.displayName
+
+export { Tabs, TabsList, TabsTrigger, TabsContent }
diff --git a/web_app/src/components/ui/textarea.tsx b/web_app/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..d1258e4
--- /dev/null
+++ b/web_app/src/components/ui/textarea.tsx
@@ -0,0 +1,24 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+export interface TextareaProps
+ extends React.TextareaHTMLAttributes {}
+
+const Textarea = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Textarea.displayName = "Textarea"
+
+export { Textarea }
diff --git a/web_app/src/components/ui/toast.tsx b/web_app/src/components/ui/toast.tsx
new file mode 100644
index 0000000..f79747a
--- /dev/null
+++ b/web_app/src/components/ui/toast.tsx
@@ -0,0 +1,127 @@
+import * as React from "react"
+import { Cross2Icon } from "@radix-ui/react-icons"
+import * as ToastPrimitives from "@radix-ui/react-toast"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const ToastProvider = ToastPrimitives.Provider
+
+const ToastViewport = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastViewport.displayName = ToastPrimitives.Viewport.displayName
+
+const toastVariants = cva(
+ "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
+ {
+ variants: {
+ variant: {
+ default: "border bg-background text-foreground",
+ destructive:
+ "destructive group border-destructive bg-destructive text-destructive-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Toast = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, variant, ...props }, ref) => {
+ return (
+
+ )
+})
+Toast.displayName = ToastPrimitives.Root.displayName
+
+const ToastAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastAction.displayName = ToastPrimitives.Action.displayName
+
+const ToastClose = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+ToastClose.displayName = ToastPrimitives.Close.displayName
+
+const ToastTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastTitle.displayName = ToastPrimitives.Title.displayName
+
+const ToastDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastDescription.displayName = ToastPrimitives.Description.displayName
+
+type ToastProps = React.ComponentPropsWithoutRef
+
+type ToastActionElement = React.ReactElement
+
+export {
+ type ToastProps,
+ type ToastActionElement,
+ ToastProvider,
+ ToastViewport,
+ Toast,
+ ToastTitle,
+ ToastDescription,
+ ToastClose,
+ ToastAction,
+}
diff --git a/web_app/src/components/ui/toaster.tsx b/web_app/src/components/ui/toaster.tsx
new file mode 100644
index 0000000..a2209ba
--- /dev/null
+++ b/web_app/src/components/ui/toaster.tsx
@@ -0,0 +1,33 @@
+import {
+ Toast,
+ ToastClose,
+ ToastDescription,
+ ToastProvider,
+ ToastTitle,
+ ToastViewport,
+} from "@/components/ui/toast"
+import { useToast } from "@/components/ui/use-toast"
+
+export function Toaster() {
+ const { toasts } = useToast()
+
+ return (
+
+ {toasts.map(function ({ id, title, description, action, ...props }) {
+ return (
+
+
+ {title && {title}}
+ {description && (
+ {description}
+ )}
+
+ {action}
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/web_app/src/components/ui/toggle.tsx b/web_app/src/components/ui/toggle.tsx
new file mode 100644
index 0000000..9923548
--- /dev/null
+++ b/web_app/src/components/ui/toggle.tsx
@@ -0,0 +1,43 @@
+import * as React from "react"
+import * as TogglePrimitive from "@radix-ui/react-toggle"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const toggleVariants = cva(
+ "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
+ {
+ variants: {
+ variant: {
+ default: "bg-transparent",
+ outline:
+ "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
+ },
+ size: {
+ default: "h-9 px-3",
+ sm: "h-8 px-2",
+ lg: "h-10 px-3",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+const Toggle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, variant, size, ...props }, ref) => (
+
+))
+
+Toggle.displayName = TogglePrimitive.Root.displayName
+
+export { Toggle, toggleVariants }
diff --git a/web_app/src/components/ui/tooltip.tsx b/web_app/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..a9c71ba
--- /dev/null
+++ b/web_app/src/components/ui/tooltip.tsx
@@ -0,0 +1,28 @@
+import * as React from "react"
+import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+
+import { cn } from "@/lib/utils"
+
+const TooltipProvider = TooltipPrimitive.Provider
+
+const Tooltip = TooltipPrimitive.Root
+
+const TooltipTrigger = TooltipPrimitive.Trigger
+
+const TooltipContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, sideOffset = 4, ...props }, ref) => (
+
+))
+TooltipContent.displayName = TooltipPrimitive.Content.displayName
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/web_app/src/components/ui/use-toast.ts b/web_app/src/components/ui/use-toast.ts
new file mode 100644
index 0000000..90d8959
--- /dev/null
+++ b/web_app/src/components/ui/use-toast.ts
@@ -0,0 +1,192 @@
+// Inspired by react-hot-toast library
+import * as React from "react"
+
+import type {
+ ToastActionElement,
+ ToastProps,
+} from "@/components/ui/toast"
+
+const TOAST_LIMIT = 1
+const TOAST_REMOVE_DELAY = 1000000
+
+type ToasterToast = ToastProps & {
+ id: string
+ title?: React.ReactNode
+ description?: React.ReactNode
+ action?: ToastActionElement
+}
+
+const actionTypes = {
+ ADD_TOAST: "ADD_TOAST",
+ UPDATE_TOAST: "UPDATE_TOAST",
+ DISMISS_TOAST: "DISMISS_TOAST",
+ REMOVE_TOAST: "REMOVE_TOAST",
+} as const
+
+let count = 0
+
+function genId() {
+ count = (count + 1) % Number.MAX_VALUE
+ return count.toString()
+}
+
+type ActionType = typeof actionTypes
+
+type Action =
+ | {
+ type: ActionType["ADD_TOAST"]
+ toast: ToasterToast
+ }
+ | {
+ type: ActionType["UPDATE_TOAST"]
+ toast: Partial
+ }
+ | {
+ type: ActionType["DISMISS_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
+ | {
+ type: ActionType["REMOVE_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
+
+interface State {
+ toasts: ToasterToast[]
+}
+
+const toastTimeouts = new Map>()
+
+const addToRemoveQueue = (toastId: string) => {
+ if (toastTimeouts.has(toastId)) {
+ return
+ }
+
+ const timeout = setTimeout(() => {
+ toastTimeouts.delete(toastId)
+ dispatch({
+ type: "REMOVE_TOAST",
+ toastId: toastId,
+ })
+ }, TOAST_REMOVE_DELAY)
+
+ toastTimeouts.set(toastId, timeout)
+}
+
+export const reducer = (state: State, action: Action): State => {
+ switch (action.type) {
+ case "ADD_TOAST":
+ return {
+ ...state,
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
+ }
+
+ case "UPDATE_TOAST":
+ return {
+ ...state,
+ toasts: state.toasts.map((t) =>
+ t.id === action.toast.id ? { ...t, ...action.toast } : t
+ ),
+ }
+
+ case "DISMISS_TOAST": {
+ const { toastId } = action
+
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
+ // but I'll keep it here for simplicity
+ if (toastId) {
+ addToRemoveQueue(toastId)
+ } else {
+ state.toasts.forEach((toast) => {
+ addToRemoveQueue(toast.id)
+ })
+ }
+
+ return {
+ ...state,
+ toasts: state.toasts.map((t) =>
+ t.id === toastId || toastId === undefined
+ ? {
+ ...t,
+ open: false,
+ }
+ : t
+ ),
+ }
+ }
+ case "REMOVE_TOAST":
+ if (action.toastId === undefined) {
+ return {
+ ...state,
+ toasts: [],
+ }
+ }
+ return {
+ ...state,
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
+ }
+ }
+}
+
+const listeners: Array<(state: State) => void> = []
+
+let memoryState: State = { toasts: [] }
+
+function dispatch(action: Action) {
+ memoryState = reducer(memoryState, action)
+ listeners.forEach((listener) => {
+ listener(memoryState)
+ })
+}
+
+type Toast = Omit
+
+function toast({ ...props }: Toast) {
+ const id = genId()
+
+ const update = (props: ToasterToast) =>
+ dispatch({
+ type: "UPDATE_TOAST",
+ toast: { ...props, id },
+ })
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
+
+ dispatch({
+ type: "ADD_TOAST",
+ toast: {
+ ...props,
+ id,
+ open: true,
+ onOpenChange: (open) => {
+ if (!open) dismiss()
+ },
+ },
+ })
+
+ return {
+ id: id,
+ dismiss,
+ update,
+ }
+}
+
+function useToast() {
+ const [state, setState] = React.useState(memoryState)
+
+ React.useEffect(() => {
+ listeners.push(setState)
+ return () => {
+ const index = listeners.indexOf(setState)
+ if (index > -1) {
+ listeners.splice(index, 1)
+ }
+ }
+ }, [state])
+
+ return {
+ ...state,
+ toast,
+ dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
+ }
+}
+
+export { useToast, toast }
diff --git a/web_app/src/globals.css b/web_app/src/globals.css
new file mode 100644
index 0000000..da0b251
--- /dev/null
+++ b/web_app/src/globals.css
@@ -0,0 +1,100 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+.react-transform-wrapper {
+ display: grid !important;
+ width: 100% !important;
+ height: 100% !important;
+}
+
+.react-photo-album {
+ padding: 8px;
+}
+
+.react-photo-album--photo {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ border-radius: 8px;
+
+ transition: transform 0.25s, visibility 0.25s ease-in;
+}
+
+.react-photo-album--photo:hover {
+ border: 1px solid var(--border);
+ transform: scale(1.03);
+}
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 224 71.4% 4.1%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 224 71.4% 4.1%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 224 71.4% 4.1%;
+
+ --primary: 220.9 39.3% 11%;
+ --primary-foreground: 210 20% 98%;
+
+ --secondary: 220 14.3% 95.9%;
+ --secondary-foreground: 220.9 39.3% 11%;
+
+ --muted: 220 14.3% 95.9%;
+ --muted-foreground: 220 8.9% 46.1%;
+
+ --accent: 220 14.3% 95.9%;
+ --accent-foreground: 220.9 39.3% 11%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 20% 98%;
+
+ --border: 220 13% 91%;
+ --input: 220 13% 91%;
+ --ring: 224 71.4% 4.1%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 224 71.4% 4.1%;
+ --foreground: 210 20% 98%;
+
+ --card: 224 71.4% 4.1%;
+ --card-foreground: 210 20% 98%;
+
+ --popover: 224 71.4% 4.1%;
+ --popover-foreground: 210 20% 98%;
+
+ --primary: 210 20% 98%;
+ --primary-foreground: 220.9 39.3% 11%;
+
+ --secondary: 215 27.9% 16.9%;
+ --secondary-foreground: 210 20% 98%;
+
+ --muted: 215 27.9% 16.9%;
+ --muted-foreground: 217.9 10.6% 64.9%;
+
+ --accent: 215 27.9% 16.9%;
+ --accent-foreground: 210 20% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 20% 98%;
+
+ --border: 215 27.9% 16.9%;
+ --input: 215 27.9% 16.9%;
+ --ring: 216 12.2% 83.9%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
\ No newline at end of file
diff --git a/web_app/src/hooks/useAsyncMemo.tsx b/web_app/src/hooks/useAsyncMemo.tsx
new file mode 100644
index 0000000..d860bb5
--- /dev/null
+++ b/web_app/src/hooks/useAsyncMemo.tsx
@@ -0,0 +1,33 @@
+import { DependencyList, useEffect, useState } from 'react'
+
+export function useAsyncMemo(
+ factory: () => Promise | undefined | null,
+ deps: DependencyList
+): T | undefined
+export function useAsyncMemo(
+ factory: () => Promise | undefined | null,
+ deps: DependencyList,
+ initial: T
+): T
+export function useAsyncMemo(
+ factory: () => Promise | undefined | null,
+ deps: DependencyList,
+ initial?: T
+) {
+ const [val, setVal] = useState(initial)
+
+ useEffect(() => {
+ let cancel = false
+ const promise = factory()
+ if (promise === undefined || promise === null) return
+ promise.then(v => {
+ if (!cancel) {
+ setVal(v)
+ }
+ })
+ return () => {
+ cancel = true
+ }
+ }, deps)
+ return val
+}
diff --git a/web_app/src/hooks/useHotkey.tsx b/web_app/src/hooks/useHotkey.tsx
new file mode 100644
index 0000000..9882ef8
--- /dev/null
+++ b/web_app/src/hooks/useHotkey.tsx
@@ -0,0 +1,22 @@
+import { Options, useHotkeys } from "react-hotkeys-hook"
+import { useRecoilValue } from "recoil"
+import { appState } from "@/lib/store"
+
+const useHotKey = (
+ keys: string,
+ callback: any,
+ options?: Options,
+ deps?: any[]
+) => {
+ const app = useRecoilValue(appState)
+
+ const ref = useHotkeys(
+ keys,
+ callback,
+ { ...options, enabled: !app.disableShortCuts },
+ deps
+ )
+ return ref
+}
+
+export default useHotKey
diff --git a/web_app/src/hooks/useImage.tsx b/web_app/src/hooks/useImage.tsx
new file mode 100644
index 0000000..08d0ce6
--- /dev/null
+++ b/web_app/src/hooks/useImage.tsx
@@ -0,0 +1,24 @@
+import { useEffect, useState } from "react"
+
+function useImage(file?: File): [HTMLImageElement, boolean] {
+ const [image] = useState(new Image())
+ const [isLoaded, setIsLoaded] = useState(false)
+
+ useEffect(() => {
+ if (file === undefined) {
+ return
+ }
+ image.onload = () => {
+ setIsLoaded(true)
+ }
+ setIsLoaded(false)
+ image.src = URL.createObjectURL(file)
+ return () => {
+ image.onload = null
+ }
+ }, [file, image])
+
+ return [image, isLoaded]
+}
+
+export { useImage }
diff --git a/web_app/src/hooks/useInputImage.tsx b/web_app/src/hooks/useInputImage.tsx
new file mode 100644
index 0000000..fcf653f
--- /dev/null
+++ b/web_app/src/hooks/useInputImage.tsx
@@ -0,0 +1,34 @@
+import { API_ENDPOINT } from "@/lib/api"
+import { useCallback, useEffect, useState } from "react"
+
+export default function useInputImage() {
+ const [inputImage, setInputImage] = useState()
+
+ const fetchInputImage = useCallback(() => {
+ const headers = new Headers()
+ headers.append("pragma", "no-cache")
+ headers.append("cache-control", "no-cache")
+
+ fetch(`${API_ENDPOINT}/inputimage`, { headers }).then(async (res) => {
+ const filename = res.headers
+ .get("content-disposition")
+ ?.split("filename=")[1]
+ .split(";")[0]
+
+ const data = await res.blob()
+ if (data && data.type.startsWith("image")) {
+ const userInput = new File(
+ [data],
+ filename !== undefined ? filename : "inputImage"
+ )
+ setInputImage(userInput)
+ }
+ })
+ }, [setInputImage])
+
+ useEffect(() => {
+ fetchInputImage()
+ }, [fetchInputImage])
+
+ return inputImage
+}
diff --git a/web_app/src/hooks/useResolution.tsx b/web_app/src/hooks/useResolution.tsx
new file mode 100644
index 0000000..39de67e
--- /dev/null
+++ b/web_app/src/hooks/useResolution.tsx
@@ -0,0 +1,31 @@
+import { useCallback, useEffect, useState } from 'react'
+
+const useResolution = () => {
+ const [width, setWidth] = useState(window.innerWidth)
+
+ const windowSizeHandler = useCallback(() => {
+ setWidth(window.innerWidth)
+ }, [])
+
+ useEffect(() => {
+ window.addEventListener('resize', windowSizeHandler)
+
+ return () => {
+ window.removeEventListener('resize', windowSizeHandler)
+ }
+ })
+
+ if (width < 768) {
+ return 'mobile'
+ }
+
+ if (width >= 768 && width < 1224) {
+ return 'tablet'
+ }
+
+ if (width >= 1224) {
+ return 'desktop'
+ }
+}
+
+export default useResolution
diff --git a/web_app/src/lib/api.ts b/web_app/src/lib/api.ts
new file mode 100644
index 0000000..91cd165
--- /dev/null
+++ b/web_app/src/lib/api.ts
@@ -0,0 +1,270 @@
+import { PluginName } from "@/lib/types"
+import { ControlNetMethodMap, Rect, Settings } from "@/lib/store"
+import { dataURItoBlob, loadImage, srcToFile } from "@/lib/utils"
+
+export const API_ENDPOINT = import.meta.env.VITE_BACKEND
+ ? import.meta.env.VITE_BACKEND
+ : ""
+
+export default async function inpaint(
+ imageFile: File,
+ settings: Settings,
+ croperRect: Rect,
+ prompt?: string,
+ negativePrompt?: string,
+ seed?: number,
+ maskBase64?: string,
+ customMask?: File,
+ paintByExampleImage?: File
+) {
+ // 1080, 2000, Original
+ const fd = new FormData()
+ fd.append("image", imageFile)
+ if (maskBase64 !== undefined) {
+ fd.append("mask", dataURItoBlob(maskBase64))
+ } else if (customMask !== undefined) {
+ fd.append("mask", customMask)
+ }
+
+ const hdSettings = settings.hdSettings[settings.model]
+ fd.append("ldmSteps", settings.ldmSteps.toString())
+ fd.append("ldmSampler", settings.ldmSampler.toString())
+ fd.append("zitsWireframe", settings.zitsWireframe.toString())
+ fd.append("hdStrategy", hdSettings.hdStrategy)
+ fd.append("hdStrategyCropMargin", hdSettings.hdStrategyCropMargin.toString())
+ fd.append(
+ "hdStrategyCropTrigerSize",
+ hdSettings.hdStrategyCropTrigerSize.toString()
+ )
+ fd.append(
+ "hdStrategyResizeLimit",
+ hdSettings.hdStrategyResizeLimit.toString()
+ )
+
+ fd.append("prompt", prompt === undefined ? "" : prompt)
+ fd.append(
+ "negativePrompt",
+ negativePrompt === undefined ? "" : negativePrompt
+ )
+ fd.append("croperX", croperRect.x.toString())
+ fd.append("croperY", croperRect.y.toString())
+ fd.append("croperHeight", croperRect.height.toString())
+ fd.append("croperWidth", croperRect.width.toString())
+ fd.append("useCroper", settings.showCroper ? "true" : "false")
+
+ fd.append("sdMaskBlur", settings.sdMaskBlur.toString())
+ fd.append("sdStrength", settings.sdStrength.toString())
+ fd.append("sdSteps", settings.sdSteps.toString())
+ fd.append("sdGuidanceScale", settings.sdGuidanceScale.toString())
+ fd.append("sdSampler", settings.sdSampler.toString())
+ fd.append("sdSeed", seed ? seed.toString() : "-1")
+ fd.append("sdMatchHistograms", settings.sdMatchHistograms ? "true" : "false")
+ fd.append("sdScale", (settings.sdScale / 100).toString())
+
+ fd.append("cv2Radius", settings.cv2Radius.toString())
+ fd.append("cv2Flag", settings.cv2Flag.toString())
+
+ fd.append("paintByExampleSteps", settings.paintByExampleSteps.toString())
+ fd.append(
+ "paintByExampleGuidanceScale",
+ settings.paintByExampleGuidanceScale.toString()
+ )
+ fd.append("paintByExampleSeed", seed ? seed.toString() : "-1")
+ fd.append(
+ "paintByExampleMaskBlur",
+ settings.paintByExampleMaskBlur.toString()
+ )
+ fd.append(
+ "paintByExampleMatchHistograms",
+ settings.paintByExampleMatchHistograms ? "true" : "false"
+ )
+ // TODO: resize image's shortest_edge to 224 before pass to backend, save network time?
+ // https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPImageProcessor
+ if (paintByExampleImage) {
+ fd.append("paintByExampleImage", paintByExampleImage)
+ }
+
+ // InstructPix2Pix
+ fd.append("p2pSteps", settings.p2pSteps.toString())
+ fd.append("p2pImageGuidanceScale", settings.p2pImageGuidanceScale.toString())
+ fd.append("p2pGuidanceScale", settings.p2pGuidanceScale.toString())
+
+ // ControlNet
+ fd.append(
+ "controlnet_conditioning_scale",
+ settings.controlnetConditioningScale.toString()
+ )
+ fd.append(
+ "controlnet_method",
+ ControlNetMethodMap[settings.controlnetMethod.toString()]
+ )
+
+ try {
+ const res = await fetch(`${API_ENDPOINT}/inpaint`, {
+ method: "POST",
+ body: fd,
+ })
+ if (res.ok) {
+ const blob = await res.blob()
+ const newSeed = res.headers.get("x-seed")
+ return { blob: URL.createObjectURL(blob), seed: newSeed }
+ }
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+ } catch (error) {
+ throw new Error(`Something went wrong: ${error}`)
+ }
+}
+
+export function getServerConfig() {
+ return fetch(`${API_ENDPOINT}/server_config`, {
+ method: "GET",
+ })
+}
+
+export function switchModel(name: string) {
+ const fd = new FormData()
+ fd.append("name", name)
+ return fetch(`${API_ENDPOINT}/model`, {
+ method: "POST",
+ body: fd,
+ })
+}
+
+export function currentModel() {
+ return fetch(`${API_ENDPOINT}/model`, {
+ method: "GET",
+ })
+}
+
+export function isDesktop() {
+ return fetch(`${API_ENDPOINT}/is_desktop`, {
+ method: "GET",
+ })
+}
+
+export function modelDownloaded(name: string) {
+ return fetch(`${API_ENDPOINT}/model_downloaded/${name}`, {
+ method: "GET",
+ })
+}
+
+export async function runPlugin(
+ name: string,
+ imageFile: File,
+ upscale?: number,
+ maskFile?: File | null,
+ clicks?: number[][]
+) {
+ const fd = new FormData()
+ fd.append("name", name)
+ fd.append("image", imageFile)
+ if (upscale) {
+ fd.append("upscale", upscale.toString())
+ }
+ if (clicks) {
+ fd.append("clicks", JSON.stringify(clicks))
+ }
+ if (maskFile) {
+ fd.append("mask", maskFile)
+ }
+
+ try {
+ const res = await fetch(`${API_ENDPOINT}/run_plugin`, {
+ method: "POST",
+ body: fd,
+ })
+ if (res.ok) {
+ const blob = await res.blob()
+ return { blob: URL.createObjectURL(blob) }
+ }
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+ } catch (error) {
+ throw new Error(`Something went wrong: ${error}`)
+ }
+}
+
+export async function getMediaFile(tab: string, filename: string) {
+ const res = await fetch(
+ `${API_ENDPOINT}/media/${tab}/${encodeURIComponent(filename)}`,
+ {
+ method: "GET",
+ }
+ )
+ if (res.ok) {
+ const blob = await res.blob()
+ const file = new File([blob], filename)
+ return file
+ }
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+}
+
+export async function getMedias(tab: string) {
+ const res = await fetch(`${API_ENDPOINT}/medias/${tab}`, {
+ method: "GET",
+ })
+ if (res.ok) {
+ const filenames = await res.json()
+ return filenames
+ }
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+}
+
+export async function downloadToOutput(
+ image: HTMLImageElement,
+ filename: string,
+ mimeType: string
+) {
+ const file = await srcToFile(image.src, filename, mimeType)
+ const fd = new FormData()
+ fd.append("image", file)
+ fd.append("filename", filename)
+
+ try {
+ const res = await fetch(`${API_ENDPOINT}/save_image`, {
+ method: "POST",
+ body: fd,
+ })
+ if (!res.ok) {
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+ }
+ } catch (error) {
+ throw new Error(`Something went wrong: ${error}`)
+ }
+}
+
+export async function makeGif(
+ originFile: File,
+ cleanImage: HTMLImageElement,
+ filename: string,
+ mimeType: string
+) {
+ const cleanFile = await srcToFile(cleanImage.src, filename, mimeType)
+ const fd = new FormData()
+ fd.append("name", PluginName.MakeGIF)
+ fd.append("image", originFile)
+ fd.append("clean_img", cleanFile)
+ fd.append("filename", filename)
+
+ try {
+ const res = await fetch(`${API_ENDPOINT}/run_plugin`, {
+ method: "POST",
+ body: fd,
+ })
+ if (!res.ok) {
+ const errMsg = await res.text()
+ throw new Error(errMsg)
+ }
+
+ const blob = await res.blob()
+ const newImage = new Image()
+ await loadImage(newImage, URL.createObjectURL(blob))
+ return newImage
+ } catch (error) {
+ throw new Error(`Something went wrong: ${error}`)
+ }
+}
diff --git a/web_app/src/lib/event.ts b/web_app/src/lib/event.ts
new file mode 100644
index 0000000..b1200f6
--- /dev/null
+++ b/web_app/src/lib/event.ts
@@ -0,0 +1,22 @@
+import mitt from "mitt"
+
+export const EVENT_PROMPT = "prompt"
+
+export const EVENT_CUSTOM_MASK = "custom_mask"
+export interface CustomMaskEventData {
+ mask: File
+}
+
+export const EVENT_PAINT_BY_EXAMPLE = "paint_by_example"
+export interface PaintByExampleEventData {
+ image: File
+}
+
+export const RERUN_LAST_MASK = "rerun_last_mask"
+
+export const DREAM_BUTTON_MOUSE_ENTER = "dream_button_mouse_enter"
+export const DREAM_BUTTON_MOUSE_LEAVE = "dream_btoon_mouse_leave"
+
+const emitter = mitt()
+
+export default emitter
diff --git a/web_app/src/lib/store.ts b/web_app/src/lib/store.ts
new file mode 100644
index 0000000..50d7550
--- /dev/null
+++ b/web_app/src/lib/store.ts
@@ -0,0 +1,902 @@
+import { atom, selector } from "recoil"
+import _ from "lodash"
+
+export enum HDStrategy {
+ ORIGINAL = "Original",
+ RESIZE = "Resize",
+ CROP = "Crop",
+}
+
+export enum LDMSampler {
+ ddim = "ddim",
+ plms = "plms",
+}
+
+function strEnum(o: Array): { [K in T]: K } {
+ return o.reduce((res, key) => {
+ res[key] = key
+ return res
+ }, Object.create(null))
+}
+
+export enum AIModel {
+ LAMA = "lama",
+ LDM = "ldm",
+ ZITS = "zits",
+ MAT = "mat",
+ FCF = "fcf",
+ SD15 = "sd1.5",
+ ANYTHING4 = "anything4",
+ REALISTIC_VISION_1_4 = "realisticVision1.4",
+ SD2 = "sd2",
+ CV2 = "cv2",
+ Mange = "manga",
+ PAINT_BY_EXAMPLE = "paint_by_example",
+ PIX2PIX = "instruct_pix2pix",
+ KANDINSKY22 = "kandinsky2.2",
+}
+
+export enum ControlNetMethod {
+ canny = "canny",
+ inpaint = "inpaint",
+ openpose = "openpose",
+ depth = "depth",
+}
+
+export const ControlNetMethodMap: any = {
+ canny: "control_v11p_sd15_canny",
+ inpaint: "control_v11p_sd15_inpaint",
+ openpose: "control_v11p_sd15_openpose",
+ depth: "control_v11f1p_sd15_depth",
+}
+
+export const ControlNetMethodMap2: any = {
+ control_v11p_sd15_canny: "canny",
+ control_v11p_sd15_inpaint: "inpaint",
+ control_v11p_sd15_openpose: "openpose",
+ control_v11f1p_sd15_depth: "depth",
+}
+
+export const maskState = atom({
+ key: "maskState",
+ default: undefined,
+})
+
+export const paintByExampleImageState = atom({
+ key: "paintByExampleImageState",
+ default: undefined,
+})
+
+export interface Rect {
+ x: number
+ y: number
+ width: number
+ height: number
+}
+
+interface AppState {
+ file: File | undefined
+ imageHeight: number
+ imageWidth: number
+ disableShortCuts: boolean
+ isInpainting: boolean
+ isDisableModelSwitch: boolean
+ isEnableAutoSaving: boolean
+ isInteractiveSeg: boolean
+ isInteractiveSegRunning: boolean
+ interactiveSegClicks: number[][]
+ enableFileManager: boolean
+ gifImage: HTMLImageElement | undefined
+ brushSize: number
+ isControlNet: boolean
+ controlNetMethod: string
+ plugins: string[]
+ isPluginRunning: boolean
+}
+
+export const appState = atom({
+ key: "appState",
+ default: {
+ file: undefined,
+ imageHeight: 0,
+ imageWidth: 0,
+ disableShortCuts: false,
+ isInpainting: false,
+ isDisableModelSwitch: false,
+ isEnableAutoSaving: false,
+ isInteractiveSeg: false,
+ isInteractiveSegRunning: false,
+ interactiveSegClicks: [],
+ enableFileManager: false,
+ gifImage: undefined,
+ brushSize: 40,
+ isControlNet: false,
+ controlNetMethod: ControlNetMethod.canny,
+ plugins: [],
+ isPluginRunning: false,
+ },
+})
+
+export const propmtState = atom({
+ key: "promptState",
+ default: "",
+})
+
+export const negativePropmtState = atom({
+ key: "negativePromptState",
+ default: "",
+})
+
+export const isInpaintingState = selector({
+ key: "isInpainting",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isInpainting
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isInpainting: newValue })
+ },
+})
+
+export const isPluginRunningState = selector({
+ key: "isPluginRunningState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isPluginRunning
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isPluginRunning: newValue })
+ },
+})
+
+export const serverConfigState = selector({
+ key: "serverConfigState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return {
+ isControlNet: app.isControlNet,
+ controlNetMethod: app.controlNetMethod,
+ isDisableModelSwitchState: app.isDisableModelSwitch,
+ isEnableAutoSaving: app.isEnableAutoSaving,
+ enableFileManager: app.enableFileManager,
+ plugins: app.plugins,
+ }
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ const methodShortName = ControlNetMethodMap2[newValue.controlNetMethod]
+ set(appState, { ...app, ...newValue, controlnetMethod: methodShortName })
+
+ const setting = get(settingState)
+ set(settingState, {
+ ...setting,
+ controlnetMethod: methodShortName,
+ })
+ },
+})
+
+export const brushSizeState = selector({
+ key: "brushSizeState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.brushSize
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, brushSize: newValue })
+ },
+})
+
+export const imageHeightState = selector({
+ key: "imageHeightState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.imageHeight
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, imageHeight: newValue })
+ },
+})
+
+export const imageWidthState = selector({
+ key: "imageWidthState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.imageWidth
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, imageWidth: newValue })
+ },
+})
+
+export const enableFileManagerState = selector({
+ key: "enableFileManagerState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.enableFileManager
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, enableFileManager: newValue })
+ },
+})
+
+export const gifImageState = selector({
+ key: "gifImageState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.gifImage
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, gifImage: newValue })
+ },
+})
+
+export const fileState = selector({
+ key: "fileState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.file
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, {
+ ...app,
+ file: newValue,
+ interactiveSegClicks: [],
+ isInteractiveSeg: false,
+ isInteractiveSegRunning: false,
+ })
+
+ const setting = get(settingState)
+ set(settingState, {
+ ...setting,
+ sdScale: 100,
+ })
+ },
+})
+
+export const isInteractiveSegState = selector({
+ key: "isInteractiveSegState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isInteractiveSeg
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isInteractiveSeg: newValue })
+ },
+})
+
+export const isInteractiveSegRunningState = selector({
+ key: "isInteractiveSegRunningState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isInteractiveSegRunning
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isInteractiveSegRunning: newValue })
+ },
+})
+
+export const isProcessingState = selector({
+ key: "isProcessingState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return (
+ app.isInteractiveSegRunning || app.isPluginRunning || app.isInpainting
+ )
+ },
+})
+
+export const interactiveSegClicksState = selector({
+ key: "interactiveSegClicksState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.interactiveSegClicks
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, interactiveSegClicks: newValue })
+ },
+})
+
+export const isDisableModelSwitchState = selector({
+ key: "isDisableModelSwitchState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isDisableModelSwitch
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isDisableModelSwitch: newValue })
+ },
+})
+
+export const isControlNetState = selector({
+ key: "isControlNetState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isControlNet
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isControlNet: newValue })
+ },
+})
+
+export const isEnableAutoSavingState = selector({
+ key: "isEnableAutoSavingState",
+ get: ({ get }) => {
+ const app = get(appState)
+ return app.isEnableAutoSaving
+ },
+ set: ({ get, set }, newValue: any) => {
+ const app = get(appState)
+ set(appState, { ...app, isEnableAutoSaving: newValue })
+ },
+})
+
+export const croperState = atom({
+ key: "croperState",
+ default: {
+ x: 0,
+ y: 0,
+ width: 512,
+ height: 512,
+ },
+})
+
+export const SIDE_PANEL_TAB = strEnum(["inpainting", "outpainting"])
+export type SIDE_PANEL_TAB_TYPE = keyof typeof SIDE_PANEL_TAB
+
+export interface SidePanelState {
+ tab: SIDE_PANEL_TAB_TYPE
+}
+
+export const sidePanelTabState = atom({
+ key: "sidePanelTabState",
+ default: {
+ tab: SIDE_PANEL_TAB.inpainting,
+ },
+})
+
+export const croperX = selector({
+ key: "croperX",
+ get: ({ get }) => get(croperState).x,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(croperState)
+ set(croperState, { ...rect, x: newValue })
+ },
+})
+
+export const croperY = selector({
+ key: "croperY",
+ get: ({ get }) => get(croperState).y,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(croperState)
+ set(croperState, { ...rect, y: newValue })
+ },
+})
+
+export const croperHeight = selector({
+ key: "croperHeight",
+ get: ({ get }) => get(croperState).height,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(croperState)
+ set(croperState, { ...rect, height: newValue })
+ },
+})
+
+export const croperWidth = selector({
+ key: "croperWidth",
+ get: ({ get }) => get(croperState).width,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(croperState)
+ set(croperState, { ...rect, width: newValue })
+ },
+})
+
+export const extenderState = atom({
+ key: "extenderState",
+ default: {
+ x: 0,
+ y: 0,
+ width: 512,
+ height: 512,
+ },
+})
+
+export const extenderX = selector({
+ key: "extenderX",
+ get: ({ get }) => get(extenderState).x,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(extenderState)
+ set(extenderState, { ...rect, x: newValue })
+ },
+})
+
+export const extenderY = selector({
+ key: "extenderY",
+ get: ({ get }) => get(extenderState).y,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(extenderState)
+ set(extenderState, { ...rect, y: newValue })
+ },
+})
+
+export const extenderHeight = selector({
+ key: "extenderHeight",
+ get: ({ get }) => get(extenderState).height,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(extenderState)
+ set(extenderState, { ...rect, height: newValue })
+ },
+})
+
+export const extenderWidth = selector({
+ key: "extenderWidth",
+ get: ({ get }) => get(extenderState).width,
+ set: ({ get, set }, newValue: any) => {
+ const rect = get(extenderState)
+ set(extenderState, { ...rect, width: newValue })
+ },
+})
+
+interface ToastAtomState {
+ open: boolean
+ desc: string
+ state: ToastState
+ duration: number
+}
+
+export const toastState = atom({
+ key: "toastState",
+ default: {
+ open: false,
+ desc: "",
+ state: "default",
+ duration: 3000,
+ },
+})
+
+export const shortcutsState = atom({
+ key: "shortcutsState",
+ default: false,
+})
+
+export interface HDSettings {
+ hdStrategy: HDStrategy
+ hdStrategyResizeLimit: number
+ hdStrategyCropTrigerSize: number
+ hdStrategyCropMargin: number
+ enabled: boolean
+}
+
+type ModelsHDSettings = { [key in AIModel]: HDSettings }
+
+export enum CV2Flag {
+ INPAINT_NS = "INPAINT_NS",
+ INPAINT_TELEA = "INPAINT_TELEA",
+}
+
+export interface Settings {
+ show: boolean
+ showCroper: boolean
+ downloadMask: boolean
+ graduallyInpainting: boolean
+ runInpaintingManually: boolean
+ model: AIModel
+ hdSettings: ModelsHDSettings
+
+ // For LDM
+ ldmSteps: number
+ ldmSampler: LDMSampler
+
+ // For ZITS
+ zitsWireframe: boolean
+
+ // For SD
+ sdMaskBlur: number
+ sdMode: SDMode
+ sdStrength: number
+ sdSteps: number
+ sdGuidanceScale: number
+ sdSampler: SDSampler
+ sdSeed: number
+ sdSeedFixed: boolean // true: use sdSeed, false: random generate seed on backend
+ sdNumSamples: number
+ sdMatchHistograms: boolean
+ sdScale: number
+
+ // For OpenCV2
+ cv2Radius: number
+ cv2Flag: CV2Flag
+
+ // Paint by Example
+ paintByExampleSteps: number
+ paintByExampleGuidanceScale: number
+ paintByExampleSeed: number
+ paintByExampleSeedFixed: boolean
+ paintByExampleMaskBlur: number
+ paintByExampleMatchHistograms: boolean
+
+ // InstructPix2Pix
+ p2pSteps: number
+ p2pImageGuidanceScale: number
+ p2pGuidanceScale: number
+
+ // ControlNet
+ controlnetConditioningScale: number
+ controlnetMethod: string
+}
+
+const defaultHDSettings: ModelsHDSettings = {
+ [AIModel.LAMA]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 2048,
+ hdStrategyCropTrigerSize: 800,
+ hdStrategyCropMargin: 196,
+ enabled: true,
+ },
+ [AIModel.LDM]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 1080,
+ hdStrategyCropTrigerSize: 1080,
+ hdStrategyCropMargin: 128,
+ enabled: true,
+ },
+ [AIModel.ZITS]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 1024,
+ hdStrategyCropTrigerSize: 1024,
+ hdStrategyCropMargin: 128,
+ enabled: true,
+ },
+ [AIModel.MAT]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 1024,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: true,
+ },
+ [AIModel.FCF]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 512,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.SD15]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.ANYTHING4]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.REALISTIC_VISION_1_4]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.SD2]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.PAINT_BY_EXAMPLE]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.PIX2PIX]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+ [AIModel.Mange]: {
+ hdStrategy: HDStrategy.CROP,
+ hdStrategyResizeLimit: 1280,
+ hdStrategyCropTrigerSize: 1024,
+ hdStrategyCropMargin: 196,
+ enabled: true,
+ },
+ [AIModel.CV2]: {
+ hdStrategy: HDStrategy.RESIZE,
+ hdStrategyResizeLimit: 1080,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: true,
+ },
+ [AIModel.KANDINSKY22]: {
+ hdStrategy: HDStrategy.ORIGINAL,
+ hdStrategyResizeLimit: 768,
+ hdStrategyCropTrigerSize: 512,
+ hdStrategyCropMargin: 128,
+ enabled: false,
+ },
+}
+
+export enum SDSampler {
+ ddim = "ddim",
+ pndm = "pndm",
+ klms = "k_lms",
+ kEuler = "k_euler",
+ kEulerA = "k_euler_a",
+ dpmPlusPlus = "dpm++",
+ uni_pc = "uni_pc",
+}
+
+export enum SDMode {
+ text2img = "text2img",
+ img2img = "img2img",
+ inpainting = "inpainting",
+}
+
+export const settingStateDefault: Settings = {
+ show: false,
+ showCroper: false,
+ downloadMask: false,
+ graduallyInpainting: true,
+ runInpaintingManually: false,
+ model: AIModel.LAMA,
+ hdSettings: defaultHDSettings,
+
+ ldmSteps: 25,
+ ldmSampler: LDMSampler.plms,
+
+ zitsWireframe: true,
+
+ // SD
+ sdMaskBlur: 5,
+ sdMode: SDMode.inpainting,
+ sdStrength: 0.75,
+ sdSteps: 50,
+ sdGuidanceScale: 7.5,
+ sdSampler: SDSampler.uni_pc,
+ sdSeed: 42,
+ sdSeedFixed: false,
+ sdNumSamples: 1,
+ sdMatchHistograms: false,
+ sdScale: 100,
+
+ // CV2
+ cv2Radius: 5,
+ cv2Flag: CV2Flag.INPAINT_NS,
+
+ // Paint by Example
+ paintByExampleSteps: 50,
+ paintByExampleGuidanceScale: 7.5,
+ paintByExampleSeed: 42,
+ paintByExampleMaskBlur: 5,
+ paintByExampleSeedFixed: false,
+ paintByExampleMatchHistograms: false,
+
+ // InstructPix2Pix
+ p2pSteps: 50,
+ p2pImageGuidanceScale: 1.5,
+ p2pGuidanceScale: 7.5,
+
+ // ControlNet
+ controlnetConditioningScale: 0.4,
+ controlnetMethod: ControlNetMethod.canny,
+}
+
+const localStorageEffect =
+ (key: string) =>
+ ({ setSelf, onSet }: any) => {
+ const savedValue = localStorage.getItem(key)
+ if (savedValue != null) {
+ const storageSettings = JSON.parse(savedValue)
+ storageSettings.show = false
+
+ const restored = _.merge(
+ _.cloneDeep(settingStateDefault),
+ storageSettings
+ )
+ setSelf(restored)
+ }
+
+ onSet((newValue: Settings, val: string, isReset: boolean) =>
+ isReset
+ ? localStorage.removeItem(key)
+ : localStorage.setItem(key, JSON.stringify(newValue))
+ )
+ }
+
+const ROOT_STATE_KEY = "settingsState4"
+// Each atom can reference an array of these atom effect functions which are called in priority order when the atom is initialized
+// https://recoiljs.org/docs/guides/atom-effects/#local-storage-persistence
+export const settingState = atom({
+ key: ROOT_STATE_KEY,
+ default: settingStateDefault,
+ effects: [localStorageEffect(ROOT_STATE_KEY)],
+})
+
+export const seedState = selector({
+ key: "seed",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ switch (settings.model) {
+ case AIModel.PAINT_BY_EXAMPLE:
+ return settings.paintByExampleSeedFixed
+ ? settings.paintByExampleSeed
+ : -1
+ default:
+ return settings.sdSeedFixed ? settings.sdSeed : -1
+ }
+ },
+ set: ({ get, set }, newValue: any) => {
+ const settings = get(settingState)
+ switch (settings.model) {
+ case AIModel.PAINT_BY_EXAMPLE:
+ if (!settings.paintByExampleSeedFixed) {
+ set(settingState, { ...settings, paintByExampleSeed: newValue })
+ }
+ break
+ default:
+ if (!settings.sdSeedFixed) {
+ set(settingState, { ...settings, sdSeed: newValue })
+ }
+ }
+ },
+})
+
+export const hdSettingsState = selector({
+ key: "hdSettings",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ return settings.hdSettings[settings.model]
+ },
+ set: ({ get, set }, newValue: any) => {
+ const settings = get(settingState)
+ const hdSettings = settings.hdSettings[settings.model]
+ const newHDSettings = { ...hdSettings, ...newValue }
+
+ set(settingState, {
+ ...settings,
+ hdSettings: { ...settings.hdSettings, [settings.model]: newHDSettings },
+ })
+ },
+})
+
+export const isSDState = selector({
+ key: "isSD",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ return (
+ settings.model === AIModel.SD15 ||
+ settings.model === AIModel.SD2 ||
+ settings.model === AIModel.ANYTHING4 ||
+ settings.model === AIModel.REALISTIC_VISION_1_4 ||
+ settings.model === AIModel.KANDINSKY22
+ )
+ },
+})
+
+export const isPaintByExampleState = selector({
+ key: "isPaintByExampleState",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ return settings.model === AIModel.PAINT_BY_EXAMPLE
+ },
+})
+
+export const isPix2PixState = selector({
+ key: "isPix2PixState",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ return settings.model === AIModel.PIX2PIX
+ },
+})
+
+export const runManuallyState = selector({
+ key: "runManuallyState",
+ get: ({ get }) => {
+ const settings = get(settingState)
+ const isSD = get(isSDState)
+ const isPaintByExample = get(isPaintByExampleState)
+ const isPix2Pix = get(isPix2PixState)
+ return (
+ settings.runInpaintingManually || isSD || isPaintByExample || isPix2Pix
+ )
+ },
+})
+
+export const isDiffusionModelsState = selector({
+ key: "isDiffusionModelsState",
+ get: ({ get }) => {
+ const isSD = get(isSDState)
+ const isPaintByExample = get(isPaintByExampleState)
+ const isPix2Pix = get(isPix2PixState)
+ return isSD || isPaintByExample || isPix2Pix
+ },
+})
+
+export enum SortBy {
+ NAME = "name",
+ CTIME = "ctime",
+ MTIME = "mtime",
+}
+
+export enum SortOrder {
+ DESCENDING = "desc",
+ ASCENDING = "asc",
+}
+
+interface FileManagerState {
+ sortBy: SortBy
+ sortOrder: SortOrder
+ layout: "rows" | "masonry"
+ searchText: string
+}
+
+const FILE_MANAGER_STATE_KEY = "fileManagerState"
+
+export const fileManagerState = atom({
+ key: FILE_MANAGER_STATE_KEY,
+ default: {
+ sortBy: SortBy.CTIME,
+ sortOrder: SortOrder.DESCENDING,
+ layout: "masonry",
+ searchText: "",
+ },
+ effects: [localStorageEffect(FILE_MANAGER_STATE_KEY)],
+})
+
+export const fileManagerSortBy = selector({
+ key: "fileManagerSortBy",
+ get: ({ get }) => get(fileManagerState).sortBy,
+ set: ({ get, set }, newValue: any) => {
+ const val = get(fileManagerState)
+ set(fileManagerState, { ...val, sortBy: newValue })
+ },
+})
+
+export const fileManagerSortOrder = selector({
+ key: "fileManagerSortOrder",
+ get: ({ get }) => get(fileManagerState).sortOrder,
+ set: ({ get, set }, newValue: any) => {
+ const val = get(fileManagerState)
+ set(fileManagerState, { ...val, sortOrder: newValue })
+ },
+})
+
+export const fileManagerLayout = selector({
+ key: "fileManagerLayout",
+ get: ({ get }) => get(fileManagerState).layout,
+ set: ({ get, set }, newValue: any) => {
+ const val = get(fileManagerState)
+ set(fileManagerState, { ...val, layout: newValue })
+ },
+})
+
+export const fileManagerSearchText = selector({
+ key: "fileManagerSearchText",
+ get: ({ get }) => get(fileManagerState).searchText,
+ set: ({ get, set }, newValue: any) => {
+ const val = get(fileManagerState)
+ set(fileManagerState, { ...val, searchText: newValue })
+ },
+})
diff --git a/web_app/src/lib/types.ts b/web_app/src/lib/types.ts
new file mode 100644
index 0000000..b076e16
--- /dev/null
+++ b/web_app/src/lib/types.ts
@@ -0,0 +1,9 @@
+export enum PluginName {
+ RemoveBG = "RemoveBG",
+ AnimeSeg = "AnimeSeg",
+ RealESRGAN = "RealESRGAN",
+ GFPGAN = "GFPGAN",
+ RestoreFormer = "RestoreFormer",
+ InteractiveSeg = "InteractiveSeg",
+ MakeGIF = "MakeGIF",
+}
diff --git a/web_app/src/lib/utils.ts b/web_app/src/lib/utils.ts
new file mode 100644
index 0000000..73461fc
--- /dev/null
+++ b/web_app/src/lib/utils.ts
@@ -0,0 +1,133 @@
+import { type ClassValue, clsx } from "clsx"
+import { SyntheticEvent } from "react"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
+
+export function keepGUIAlive() {
+ async function getRequest(url = "") {
+ const response = await fetch(url, {
+ method: "GET",
+ cache: "no-cache",
+ })
+ return response.json()
+ }
+
+ const keepAliveServer = () => {
+ const url = document.location
+ const route = "/flaskwebgui-keep-server-alive"
+ getRequest(url + route).then((data) => {
+ return data
+ })
+ }
+
+ const intervalRequest = 3 * 1000
+ keepAliveServer()
+ setInterval(keepAliveServer, intervalRequest)
+}
+
+export function dataURItoBlob(dataURI: string) {
+ const mime = dataURI.split(",")[0].split(":")[1].split(";")[0]
+ const binary = atob(dataURI.split(",")[1])
+ const array = []
+ for (let i = 0; i < binary.length; i += 1) {
+ array.push(binary.charCodeAt(i))
+ }
+ return new Blob([new Uint8Array(array)], { type: mime })
+}
+
+export function loadImage(image: HTMLImageElement, src: string) {
+ return new Promise((resolve, reject) => {
+ const initSRC = image.src
+ const img = image
+ img.onload = resolve
+ img.onerror = (err) => {
+ img.src = initSRC
+ reject(err)
+ }
+ img.src = src
+ })
+}
+
+export function srcToFile(src: string, fileName: string, mimeType: string) {
+ return fetch(src)
+ .then(function (res) {
+ return res.arrayBuffer()
+ })
+ .then(function (buf) {
+ return new File([buf], fileName, { type: mimeType })
+ })
+}
+
+export async function askWritePermission() {
+ try {
+ // The clipboard-write permission is granted automatically to pages
+ // when they are the active tab. So it's not required, but it's more safe.
+ const { state } = await navigator.permissions.query({
+ name: "clipboard-write" as PermissionName,
+ })
+ return state === "granted"
+ } catch (error) {
+ // Browser compatibility / Security error (ONLY HTTPS) ...
+ return false
+ }
+}
+
+function canvasToBlob(canvas: HTMLCanvasElement, mime: string): Promise {
+ return new Promise((resolve, reject) =>
+ canvas.toBlob(async (d) => {
+ if (d) {
+ resolve(d)
+ } else {
+ reject(new Error("Expected toBlob() to be defined"))
+ }
+ }, mime)
+ )
+}
+
+const setToClipboard = async (blob: any) => {
+ const data = [new ClipboardItem({ [blob.type]: blob })]
+ await navigator.clipboard.write(data)
+}
+
+export function isRightClick(ev: SyntheticEvent) {
+ const mouseEvent = ev.nativeEvent as MouseEvent
+ return mouseEvent.button === 2
+}
+
+export function isMidClick(ev: SyntheticEvent) {
+ const mouseEvent = ev.nativeEvent as MouseEvent
+ return mouseEvent.button === 1
+}
+
+export async function copyCanvasImage(canvas: HTMLCanvasElement) {
+ const blob = await canvasToBlob(canvas, "image/png")
+ try {
+ await setToClipboard(blob)
+ } catch {
+ console.log("Copy image failed!")
+ }
+}
+
+export function downloadImage(uri: string, name: string) {
+ const link = document.createElement("a")
+ link.href = uri
+ link.download = name
+
+ // this is necessary as link.click() does not work on the latest firefox
+ link.dispatchEvent(
+ new MouseEvent("click", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ })
+ )
+
+ setTimeout(() => {
+ // For Firefox it is necessary to delay revoking the ObjectURL
+ // window.URL.revokeObjectURL(base64)
+ link.remove()
+ }, 100)
+}
diff --git a/web_app/src/main.tsx b/web_app/src/main.tsx
new file mode 100644
index 0000000..3ad54c5
--- /dev/null
+++ b/web_app/src/main.tsx
@@ -0,0 +1,16 @@
+import React from "react"
+import ReactDOM from "react-dom/client"
+import { RecoilRoot } from "recoil"
+import App from "./App.tsx"
+import "./globals.css"
+import { ThemeProvider } from "./components/theme-provider.tsx"
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+
+
+
+
+
+)
diff --git a/web_app/src/vite-env.d.ts b/web_app/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/web_app/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/web_app/tailwind.config.js b/web_app/tailwind.config.js
new file mode 100644
index 0000000..0377ea1
--- /dev/null
+++ b/web_app/tailwind.config.js
@@ -0,0 +1,76 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ darkMode: ["class"],
+ content: [
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: 0 },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: 0 },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate")],
+}
\ No newline at end of file
diff --git a/web_app/tsconfig.json b/web_app/tsconfig.json
new file mode 100644
index 0000000..d024fe0
--- /dev/null
+++ b/web_app/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+
+ "baseUrl": ".",
+ "paths": {
+ "@/*": [
+ "./src/*"
+ ]
+ }
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/web_app/tsconfig.node.json b/web_app/tsconfig.node.json
new file mode 100644
index 0000000..42872c5
--- /dev/null
+++ b/web_app/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/web_app/vite.config.ts b/web_app/vite.config.ts
new file mode 100644
index 0000000..5790e82
--- /dev/null
+++ b/web_app/vite.config.ts
@@ -0,0 +1,12 @@
+import path from "path"
+import react from "@vitejs/plugin-react"
+import { defineConfig } from "vite"
+
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+})