diff --git a/.erb/configs/webpack.config.renderer.dev.ts b/.erb/configs/webpack.config.renderer.dev.ts index 7fa6640b..6a6329c1 100644 --- a/.erb/configs/webpack.config.renderer.dev.ts +++ b/.erb/configs/webpack.config.renderer.dev.ts @@ -78,12 +78,13 @@ const configuration: webpack.Configuration = { }, }, 'sass-loader', + 'postcss-loader', ], include: /\.module\.s?(c|a)ss$/, }, { test: /\.s?css$/, - use: ['style-loader', 'css-loader', 'sass-loader'], + use: ['style-loader', 'css-loader', 'sass-loader', 'postcss-loader'], exclude: /\.module\.s?(c|a)ss$/, }, // Fonts diff --git a/.eslintrc.js b/.eslintrc.js index 885d29a0..cdbc5fa2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,13 @@ module.exports = { 'no-underscore-dangle': 'off', 'no-plusplus': 'off', 'no-console': 'off', + 'prettier/prettier': [ + 'error', + { + endOfLine: 'auto', // stops prettier complaining about windows line-endings + }, + ], + 'react/jsx-props-no-spreading': 'off', }, parserOptions: { ecmaVersion: 2020, diff --git a/package-lock.json b/package-lock.json index 134529b2..1775a0a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,13 +14,37 @@ "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@ffmpeg-installer/ffmpeg": "^1.1.0", + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-brands-svg-icons": "^6.6.0", + "@fortawesome/free-regular-svg-icons": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^5.8.4", "@mui/lab": "^5.0.0-alpha.80", "@mui/material": "^5.6.4", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-hover-card": "^1.1.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-toggle": "^1.1.0", + "@radix-ui/react-toggle-group": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", "atomic-queue": "^5.0.4", "axios": "^1.6.8", "byte-size": "^8.1.0", "check-disk-space": "^3.4.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", "electron-debug": "^3.2.0", "electron-log": "^4.4.8", "electron-osx-prompt": "^1.4.1", @@ -30,6 +54,7 @@ "fs": "^0.0.1-security", "history": "^5.3.0", "lodash": "^4.17.21", + "lucide-react": "^0.428.0", "node-abi": "^3.47.0", "obs-studio-node": "https://warcraftrecorderstorage.blob.core.windows.net/warcraftrecorder/osn-0.23.71-release-win64.tar.gz", "path": "^0.12.7", @@ -41,6 +66,8 @@ "react-player": "^2.14.1", "react-router-dom": "^6.3.0", "screenfull": "^6.0.2", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7", "tsc": "^2.0.4", "tss-react": "^4.1.1", "wait-queue": "^1.1.4" @@ -62,6 +89,7 @@ "@types/webpack-env": "^1.16.3", "@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/parser": "^5.18.0", + "autoprefixer": "^10.4.20", "browserslist-config-erb": "^0.0.3", "chalk": "^4.1.2", "concurrently": "^7.1.0", @@ -97,6 +125,8 @@ "mini-css-extract-plugin": "^2.6.0", "node-loader": "^2.0.0", "opencollective-postinstall": "^2.0.3", + "postcss": "^8.4.41", + "postcss-loader": "^8.1.1", "prettier": "^2.6.2", "react-refresh": "^0.12.0", "react-refresh-typescript": "^2.0.4", @@ -105,6 +135,7 @@ "sass": "^1.49.11", "sass-loader": "^12.6.0", "style-loader": "^3.3.1", + "tailwindcss": "^3.4.10", "terser-webpack-plugin": "^5.3.1", "ts-jest": "^27.1.4", "ts-loader": "^9.2.8", @@ -119,6 +150,17 @@ "webpack-merge": "^5.8.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.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", @@ -1569,7 +1611,7 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 12" } @@ -1578,7 +1620,7 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-consumer": "0.8.0" }, @@ -2223,6 +2265,104 @@ "win32" ] }, + "node_modules/@floating-ui/core": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "dependencies": { + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz", + "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz", + "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -2262,6 +2402,90 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2656,7 +2880,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2678,7 +2901,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2824,6 +3046,14 @@ } } }, + "node_modules/@mui/base/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/icons-material": { "version": "5.8.4", "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.8.4.tgz", @@ -2946,6 +3176,14 @@ } } }, + "node_modules/@mui/lab/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/material": { "version": "5.6.4", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.6.4.tgz", @@ -2990,6 +3228,14 @@ } } }, + "node_modules/@mui/material/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/private-theming": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.8.0.tgz", @@ -3085,6 +3331,14 @@ } } }, + "node_modules/@mui/system/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/types": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.1.3.tgz", @@ -3124,7 +3378,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -3137,7 +3390,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -3146,7 +3398,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -3356,6 +3607,15 @@ "@octokit/openapi-types": "^22.2.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.5.tgz", @@ -3462,6 +3722,916 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", + "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.1.tgz", + "integrity": "sha512-IwzAOP97hQpDADYVKrEEHUH/b2LA+9MgB0LgdmnbFO2u/3M5hmEofjjr2M6CyzUblaAqJdFm6B7oFtU72DPXrA==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.1.tgz", + "integrity": "sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", + "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.0.tgz", + "integrity": "sha512-aSzvnYpP725CROcxAOEBVZZSIQVQdHgBr2QQFKySsaD14u8dNT0batuXI+AAGDdAHfXH8rbnHmjYFqVJ21KkRg==", + "dependencies": { + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz", + "integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", + "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", + "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.0.tgz", + "integrity": "sha512-dAHCDA4/ySXROEPaRtaMV5WHL8+JB/DbtyTbJjYkY0RXmKMO2Ln8DFZhywG5/mVQ4WqHDBc8smc14yPXPqZHYA==", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.0.tgz", + "integrity": "sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.0.tgz", + "integrity": "sha512-bZgOKB/LtZIij75FSuPzyEti/XBhJH52ExgtdVqjCIh+Nx/FW+LhnbXtbCzIi34ccyMsyOja8T0thCzoHFXNKA==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.1.tgz", + "integrity": "sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", + "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.0.tgz", + "integrity": "sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-toggle": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.2.tgz", + "integrity": "sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -4971,25 +6141,25 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true + "devOptional": true }, "node_modules/@types/aria-query": { "version": "4.2.2", @@ -5345,7 +6515,7 @@ "version": "17.0.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", "integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -6038,7 +7208,7 @@ "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -6247,7 +7417,6 @@ "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" } @@ -6256,7 +7425,6 @@ "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" }, @@ -6271,15 +7439,12 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6403,7 +7568,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/argparse": { "version": "2.0.1", @@ -6418,6 +7583,17 @@ "license": "MIT", "peer": true }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", @@ -6679,6 +7855,43 @@ "node": ">=10.12.0" } }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "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.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/axe-core": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", @@ -6809,8 +8022,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -6859,7 +8071,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, "engines": { "node": ">=8" } @@ -7012,7 +8223,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -7041,9 +8251,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "funding": [ { "type": "opencollective", @@ -7052,14 +8262,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -7344,6 +8557,14 @@ "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-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -7357,9 +8578,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001338", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001338.tgz", - "integrity": "sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "funding": [ { "type": "opencollective", @@ -7368,6 +8589,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -7523,7 +8748,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, "funding": [ { "type": "individual", @@ -7550,7 +8774,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -7594,6 +8817,25 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "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/class-variance-authority/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/clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -7755,13 +8997,373 @@ } }, "node_modules/clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } }, + "node_modules/cmdk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz", + "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==", + "dependencies": { + "@radix-ui/react-dialog": "1.0.5", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/cmdk/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/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -7782,7 +9384,6 @@ "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" }, @@ -7793,8 +9394,7 @@ "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 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-support": { "version": "1.1.3", @@ -8281,7 +9881,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -8305,7 +9905,6 @@ "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", @@ -8564,7 +10163,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "bin": { "cssesc": "bin/cssesc" }, @@ -8932,6 +10530,11 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "devOptional": 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/detect-port": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", @@ -8964,11 +10567,16 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "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/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -9033,6 +10641,11 @@ "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/dmg-builder": { "version": "23.6.0", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-23.6.0.tgz", @@ -9308,8 +10921,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ee-first": { "version": "1.1.1", @@ -9937,9 +11549,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==" + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.9.tgz", + "integrity": "sha512-HfkT8ndXR0SEkU8gBQQM3rz035bpE/hxkZ1YIt4KJPEFES68HfIU6LzKukH0H794Lm83WJtkSAMfEToxCs15VA==" }, "node_modules/electron-updater": { "version": "5.3.0", @@ -10040,8 +11652,7 @@ "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/emojilib": { "version": "2.4.0", @@ -10425,9 +12036,9 @@ "optional": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -11778,7 +13389,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -11795,7 +13405,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -11845,7 +13454,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -11976,7 +13584,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -12131,6 +13738,32 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -12153,6 +13786,19 @@ "node": ">= 0.6" } }, + "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/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -12238,7 +13884,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -12249,9 +13894,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "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/function-timeout": { "version": "1.0.2", @@ -12339,6 +13987,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -12418,7 +14074,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -12639,6 +14294,17 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hat": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", @@ -13256,6 +14922,14 @@ "readable-stream": "^2.0.0" } }, + "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/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -13292,7 +14966,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -13341,11 +15014,14 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13385,7 +15061,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13394,7 +15069,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -13412,7 +15086,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -13451,7 +15124,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -13768,6 +15440,20 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -14410,6 +16096,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-sdsl": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", @@ -14814,10 +16508,9 @@ } }, "node_modules/lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "engines": { "node": ">=10" } @@ -15286,6 +16979,14 @@ "node": ">=10" } }, + "node_modules/lucide-react": { + "version": "0.428.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.428.0.tgz", + "integrity": "sha512-rGrzslfEcgqwh+TLBC5qJ8wvVIXhLvAIXVFKNHndYyb1utSxxn9rXOC+1CNJLi6yNOooyPqIs6+3YCp6uSiEvg==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", @@ -15369,7 +17070,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/make-fetch-happen": { "version": "9.1.0", @@ -15695,7 +17396,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -15713,7 +17413,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -16014,9 +17713,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -16024,10 +17721,15 @@ } }, "node_modules/nanoid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", - "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", - "dev": true, + "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" }, @@ -16188,9 +17890,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/nopt": { "version": "5.0.0", @@ -16249,6 +17951,14 @@ "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" @@ -19083,6 +20793,14 @@ "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/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -19456,6 +21174,11 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -19581,7 +21304,6 @@ "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" } @@ -19591,6 +21313,34 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -19611,15 +21361,14 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -19654,7 +21403,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, "engines": { "node": ">= 6" } @@ -19930,10 +21678,9 @@ } }, "node_modules/postcss": { - "version": "8.4.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", - "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", - "dev": true, + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "funding": [ { "type": "opencollective", @@ -19942,12 +21689,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -20047,6 +21798,168 @@ "postcss": "^8.2.15" } }, + "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.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/postcss-merge-longhand": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz", @@ -20204,6 +22117,30 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-normalize-charset": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", @@ -20398,10 +22335,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -20444,8 +22380,7 @@ "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==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -20731,7 +22666,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -20955,6 +22889,51 @@ "typescript": "^4" } }, + "node_modules/react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.4", + "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.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "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-router": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", @@ -20992,6 +22971,28 @@ "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "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-test-renderer": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.0.0.tgz", @@ -21027,6 +23028,22 @@ "react-dom": ">=16.6.0" } }, + "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/read-cache/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/read-config-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.2.0.tgz", @@ -21148,7 +23165,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -21280,11 +23296,11 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "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.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -21372,7 +23388,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -21428,7 +23443,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -22295,7 +24309,6 @@ "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" }, @@ -22307,7 +24320,6 @@ "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" } @@ -22597,10 +24609,9 @@ } }, "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==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -23088,7 +25099,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -23098,11 +25108,29 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string.prototype.matchall": { "version": "4.0.7", @@ -23153,7 +25181,18 @@ "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-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -23298,6 +25337,84 @@ "semver": "bin/semver" } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "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": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/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/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", @@ -23399,6 +25516,64 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tailwind-merge": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", + "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", + "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", + "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.21.0", + "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/tailwindcss/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/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -23648,9 +25823,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "any-promise": "^1.0.0" } @@ -23659,9 +25832,7 @@ "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==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -23753,7 +25924,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -23837,6 +26007,11 @@ "utf8-byte-length": "^1.0.1" } }, + "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/ts-jest": { "version": "27.1.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", @@ -23916,7 +26091,7 @@ "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", @@ -23959,7 +26134,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.4.0" } @@ -24123,7 +26298,7 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24295,6 +26470,35 @@ "yaku": "^0.16.6" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "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.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -24341,6 +26545,47 @@ } } }, + "node_modules/use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "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/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -24393,7 +26638,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -25014,7 +27259,6 @@ "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" }, @@ -25089,6 +27333,23 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -25225,7 +27486,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -25258,6 +27519,11 @@ } }, "dependencies": { + "@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==" + }, "@ampproject/remapping": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", @@ -26441,13 +28707,13 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true + "devOptional": true }, "@cspotcode/source-map-support": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, + "devOptional": true, "requires": { "@cspotcode/source-map-consumer": "0.8.0" } @@ -26887,6 +29153,81 @@ "integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==", "optional": true }, + "@floating-ui/core": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "requires": { + "@floating-ui/utils": "^0.2.7" + } + }, + "@floating-ui/dom": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "requires": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.7" + } + }, + "@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "requires": { + "@floating-ui/dom": "^1.0.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + }, + "@fortawesome/fontawesome-common-types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@fortawesome/free-brands-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz", + "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@fortawesome/free-regular-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz", + "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "requires": { + "prop-types": "^15.8.1" + } + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -26916,6 +29257,59 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -27235,7 +29629,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, "requires": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -27250,8 +29643,7 @@ "@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==", - "dev": true + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, "@jridgewell/source-map": { "version": "0.3.2", @@ -27353,6 +29745,13 @@ "clsx": "^1.1.1", "prop-types": "^15.7.2", "react-is": "^17.0.2" + }, + "dependencies": { + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + } } }, "@mui/icons-material": { @@ -27395,6 +29794,11 @@ "react-transition-group": "^4.4.2", "rifm": "^0.12.1" } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" } } }, @@ -27415,6 +29819,13 @@ "prop-types": "^15.7.2", "react-is": "^17.0.2", "react-transition-group": "^4.4.2" + }, + "dependencies": { + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + } } }, "@mui/private-theming": { @@ -27450,6 +29861,13 @@ "clsx": "^1.1.1", "csstype": "^3.0.11", "prop-types": "^15.7.2" + }, + "dependencies": { + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + } } }, "@mui/types": { @@ -27474,7 +29892,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -27483,14 +29900,12 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -27643,6 +30058,12 @@ "@octokit/openapi-types": "^22.2.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.5.tgz", @@ -27700,6 +30121,456 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" }, + "@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" + }, + "@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + } + }, + "@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "requires": {} + }, + "@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "requires": {} + }, + "@radix-ui/react-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", + "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + } + }, + "@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "requires": {} + }, + "@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + } + }, + "@radix-ui/react-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "requires": {} + }, + "@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-hover-card": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.1.tgz", + "integrity": "sha512-IwzAOP97hQpDADYVKrEEHUH/b2LA+9MgB0LgdmnbFO2u/3M5hmEofjjr2M6CyzUblaAqJdFm6B7oFtU72DPXrA==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + } + }, + "@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "requires": { + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-popover": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.1.tgz", + "integrity": "sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + } + }, + "@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "requires": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + } + }, + "@radix-ui/react-portal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", + "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "requires": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "requires": { + "@radix-ui/react-slot": "1.1.0" + } + }, + "@radix-ui/react-progress": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.0.tgz", + "integrity": "sha512-aSzvnYpP725CROcxAOEBVZZSIQVQdHgBr2QQFKySsaD14u8dNT0batuXI+AAGDdAHfXH8rbnHmjYFqVJ21KkRg==", + "requires": { + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + } + }, + "@radix-ui/react-scroll-area": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz", + "integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==", + "requires": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-select": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", + "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "requires": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + } + }, + "@radix-ui/react-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", + "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/react-slider": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.0.tgz", + "integrity": "sha512-dAHCDA4/ySXROEPaRtaMV5WHL8+JB/DbtyTbJjYkY0RXmKMO2Ln8DFZhywG5/mVQ4WqHDBc8smc14yPXPqZHYA==", + "requires": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + } + }, + "@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "requires": { + "@radix-ui/react-compose-refs": "1.1.0" + } + }, + "@radix-ui/react-switch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.0.tgz", + "integrity": "sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + } + }, + "@radix-ui/react-tabs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.0.tgz", + "integrity": "sha512-bZgOKB/LtZIij75FSuPzyEti/XBhJH52ExgtdVqjCIh+Nx/FW+LhnbXtbCzIi34ccyMsyOja8T0thCzoHFXNKA==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + } + }, + "@radix-ui/react-toast": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.1.tgz", + "integrity": "sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + } + }, + "@radix-ui/react-toggle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", + "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + } + }, + "@radix-ui/react-toggle-group": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.0.tgz", + "integrity": "sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-toggle": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + } + }, + "@radix-ui/react-tooltip": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.2.tgz", + "integrity": "sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==", + "requires": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + } + }, + "@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "requires": {} + }, + "@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "requires": { + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "requires": { + "@radix-ui/react-use-callback-ref": "1.1.0" + } + }, + "@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "requires": {} + }, + "@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "requires": {} + }, + "@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "requires": { + "@radix-ui/rect": "1.1.0" + } + }, + "@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "requires": { + "@radix-ui/react-use-layout-effect": "1.1.0" + } + }, + "@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "requires": { + "@radix-ui/react-primitive": "2.0.0" + } + }, + "@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + }, "@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -28799,25 +31670,25 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true + "devOptional": true }, "@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true + "devOptional": true }, "@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true + "devOptional": true }, "@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true + "devOptional": true }, "@types/aria-query": { "version": "4.2.2", @@ -29172,7 +32043,7 @@ "version": "17.0.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", "integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==", - "dev": true, + "devOptional": true, "requires": { "@types/react": "*" } @@ -29714,7 +32585,7 @@ "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true + "devOptional": true }, "acorn-globals": { "version": "6.0.0", @@ -29861,14 +32732,12 @@ "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 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "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, "requires": { "color-convert": "^2.0.1" } @@ -29876,15 +32745,12 @@ "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "peer": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -29992,7 +32858,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "argparse": { "version": "2.0.1", @@ -30006,6 +32872,14 @@ "dev": true, "peer": true }, + "aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "requires": { + "tslib": "^2.0.0" + } + }, "aria-query": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", @@ -30216,6 +33090,20 @@ "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==" }, + "autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "requires": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + } + }, "axe-core": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", @@ -30322,8 +33210,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -30353,8 +33240,7 @@ "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { "version": "4.1.0", @@ -30495,7 +33381,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -30518,15 +33403,14 @@ "dev": true }, "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" } }, "browserslist-config-erb": { @@ -30746,6 +33630,11 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "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==" + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -30759,9 +33648,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001338", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001338.tgz", - "integrity": "sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==" + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==" }, "chalk": { "version": "4.1.2", @@ -30907,7 +33796,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -30923,7 +33811,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -30960,6 +33847,21 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "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==", + "requires": { + "clsx": "2.0.0" + }, + "dependencies": { + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + } + } + }, "clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -31080,9 +33982,190 @@ } }, "clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + }, + "cmdk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz", + "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==", + "requires": { + "@radix-ui/react-dialog": "1.0.5", + "@radix-ui/react-primitive": "1.0.3" + }, + "dependencies": { + "@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@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==", + "requires": { + "@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" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + } + }, + "@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==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "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==", + "requires": { + "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" + } + } + } }, "co": { "version": "4.6.0", @@ -31100,7 +34183,6 @@ "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, "requires": { "color-name": "~1.1.4" } @@ -31108,8 +34190,7 @@ "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 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-support": { "version": "1.1.3", @@ -31481,7 +34562,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "cross-env": { "version": "7.0.3", @@ -31496,7 +34577,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -31671,8 +34751,7 @@ "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, "cssnano": { "version": "5.1.7", @@ -31949,6 +35028,11 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "devOptional": true }, + "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==" + }, "detect-port": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", @@ -31976,11 +35060,16 @@ } } }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true + "devOptional": true }, "diff-sequences": { "version": "27.5.1", @@ -32029,6 +35118,11 @@ "path-type": "^4.0.0" } }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, "dmg-builder": { "version": "23.6.0", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-23.6.0.tgz", @@ -32252,8 +35346,7 @@ "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "ee-first": { "version": "1.1.1", @@ -32749,9 +35842,9 @@ } }, "electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==" + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.9.tgz", + "integrity": "sha512-HfkT8ndXR0SEkU8gBQQM3rz035bpE/hxkZ1YIt4KJPEFES68HfIU6LzKukH0H794Lm83WJtkSAMfEToxCs15VA==" }, "electron-updater": { "version": "5.3.0", @@ -32828,8 +35921,7 @@ "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "emojilib": { "version": "2.4.0", @@ -33101,9 +36193,9 @@ "optional": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" }, "escape-html": { "version": "1.0.3", @@ -34065,7 +37157,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -34078,7 +37169,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -34114,7 +37204,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -34216,7 +37305,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -34326,6 +37414,22 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + } + } + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -34342,6 +37446,12 @@ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true }, + "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 + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -34420,13 +37530,12 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "function-timeout": { "version": "1.0.2", @@ -34495,6 +37604,11 @@ "has-symbols": "^1.0.1" } }, + "get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" + }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -34552,7 +37666,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "requires": { "is-glob": "^4.0.3" } @@ -34711,6 +37824,14 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, "hat": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", @@ -35156,6 +38277,14 @@ } } }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -35186,7 +38315,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "requires": { "binary-extensions": "^2.0.0" } @@ -35217,11 +38345,11 @@ } }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "requires": { - "has": "^1.0.3" + "hasown": "^2.0.2" } }, "is-date-object": { @@ -35242,14 +38370,12 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-generator-fn": { "version": "2.1.0", @@ -35261,7 +38387,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -35287,8 +38412,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.7", @@ -35512,6 +38636,15 @@ "istanbul-lib-report": "^3.0.0" } }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -36010,6 +39143,11 @@ } } }, + "jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==" + }, "js-sdsl": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", @@ -36357,10 +39495,9 @@ } }, "lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" }, "lines-and-columns": { "version": "1.2.4", @@ -36704,6 +39841,12 @@ "yallist": "^4.0.0" } }, + "lucide-react": { + "version": "0.428.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.428.0.tgz", + "integrity": "sha512-rGrzslfEcgqwh+TLBC5qJ8wvVIXhLvAIXVFKNHndYyb1utSxxn9rXOC+1CNJLi6yNOooyPqIs6+3YCp6uSiEvg==", + "requires": {} + }, "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", @@ -36769,7 +39912,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "make-fetch-happen": { "version": "9.1.0", @@ -37035,8 +40178,7 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "methods": { "version": "1.1.2", @@ -37048,7 +40190,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -37268,8 +40409,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "peer": true, "requires": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -37277,10 +40416,9 @@ } }, "nanoid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", - "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", - "dev": true + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, "natural-compare": { "version": "1.4.0", @@ -37400,9 +40538,9 @@ } }, "node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "nopt": { "version": "5.0.0", @@ -37447,7 +40585,12 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "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 }, "normalize-url": { @@ -39405,6 +42548,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -39657,6 +42805,11 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -39755,14 +42908,34 @@ "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 + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "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==" }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" + } + } + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -39780,15 +42953,14 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pidtree": { "version": "0.5.0", @@ -39806,8 +42978,7 @@ "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" }, "pkg-conf": { "version": "2.1.0", @@ -40015,14 +43186,13 @@ } }, "postcss": { - "version": "8.4.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", - "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", - "dev": true, + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "requires": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" } }, "postcss-calc": { @@ -40084,6 +43254,78 @@ "dev": true, "requires": {} }, + "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==", + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "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==", + "requires": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "dependencies": { + "lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==" + }, + "yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==" + } + } + }, + "postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "requires": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "dependencies": { + "cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "requires": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + } + }, + "typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "optional": true, + "peer": true + } + } + }, "postcss-merge-longhand": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz", @@ -40182,6 +43424,14 @@ "icss-utils": "^5.0.0" } }, + "postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "requires": { + "postcss-selector-parser": "^6.1.1" + } + }, "postcss-normalize-charset": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", @@ -40301,10 +43551,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -40332,8 +43581,7 @@ "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==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "prelude-ls": { "version": "1.2.1", @@ -40561,8 +43809,7 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "queue-promise": { "version": "2.2.1", @@ -40727,6 +43974,27 @@ "dev": true, "requires": {} }, + "react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "requires": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + } + }, + "react-remove-scroll-bar": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "requires": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + } + }, "react-router": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", @@ -40754,6 +44022,16 @@ "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" } }, + "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==", + "requires": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + } + }, "react-test-renderer": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.0.0.tgz", @@ -40784,6 +44062,21 @@ "prop-types": "^15.6.2" } }, + "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==", + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + } + } + }, "read-config-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.2.0.tgz", @@ -40871,7 +44164,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -40969,11 +44261,11 @@ "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -41038,8 +44330,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rfdc": { "version": "1.3.0", @@ -41080,7 +44371,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -41674,7 +44964,6 @@ "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, "requires": { "shebang-regex": "^3.0.0" } @@ -41682,8 +44971,7 @@ "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 + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "side-channel": { "version": "1.0.4", @@ -41910,10 +45198,9 @@ "dev": true }, "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==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" }, "source-map-resolve": { "version": "0.6.0", @@ -42309,7 +45596,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -42319,8 +45605,24 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + } + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" } } }, @@ -42364,7 +45666,14 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -42475,6 +45784,61 @@ } } }, + "sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" + } + } + }, "sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", @@ -42547,6 +45911,53 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "tailwind-merge": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", + "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==" + }, + "tailwindcss": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", + "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", + "requires": { + "@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.21.0", + "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" + }, + "dependencies": { + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + } + } + }, + "tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "requires": {} + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -42722,8 +46133,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "peer": true, "requires": { "any-promise": "^1.0.0" } @@ -42732,8 +46141,6 @@ "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==", - "dev": true, - "peer": true, "requires": { "thenify": ">= 3.1.0 < 4" } @@ -42808,7 +46215,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -42867,6 +46273,11 @@ "utf8-byte-length": "^1.0.1" } }, + "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==" + }, "ts-jest": { "version": "27.1.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", @@ -42911,7 +46322,7 @@ "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", - "dev": true, + "devOptional": true, "requires": { "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", @@ -42932,7 +46343,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true + "devOptional": true } } }, @@ -43059,7 +46470,7 @@ "version": "4.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true + "devOptional": true }, "uglify-js": { "version": "3.19.0", @@ -43181,6 +46592,15 @@ "yaku": "^0.16.6" } }, + "update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -43207,6 +46627,23 @@ "schema-utils": "^3.0.0" } }, + "use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "requires": { + "tslib": "^2.0.0" + } + }, + "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==", + "requires": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + } + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -43255,7 +46692,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", - "dev": true + "devOptional": true }, "v8-to-istanbul": { "version": "8.1.1", @@ -43724,7 +47161,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -43780,6 +47216,16 @@ "strip-ansi": "^6.0.0" } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -43884,7 +47330,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true + "devOptional": true }, "yocto-queue": { "version": "0.1.0", diff --git a/package.json b/package.json index 9233f693..85b1a3da 100644 --- a/package.json +++ b/package.json @@ -173,6 +173,7 @@ "@types/webpack-env": "^1.16.3", "@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/parser": "^5.18.0", + "autoprefixer": "^10.4.20", "browserslist-config-erb": "^0.0.3", "chalk": "^4.1.2", "concurrently": "^7.1.0", @@ -208,6 +209,8 @@ "mini-css-extract-plugin": "^2.6.0", "node-loader": "^2.0.0", "opencollective-postinstall": "^2.0.3", + "postcss": "^8.4.41", + "postcss-loader": "^8.1.1", "prettier": "^2.6.2", "react-refresh": "^0.12.0", "react-refresh-typescript": "^2.0.4", @@ -216,6 +219,7 @@ "sass": "^1.49.11", "sass-loader": "^12.6.0", "style-loader": "^3.3.1", + "tailwindcss": "^3.4.10", "terser-webpack-plugin": "^5.3.1", "ts-jest": "^27.1.4", "ts-loader": "^9.2.8", @@ -236,13 +240,37 @@ "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@ffmpeg-installer/ffmpeg": "^1.1.0", + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-brands-svg-icons": "^6.6.0", + "@fortawesome/free-regular-svg-icons": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^5.8.4", "@mui/lab": "^5.0.0-alpha.80", "@mui/material": "^5.6.4", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-hover-card": "^1.1.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-toggle": "^1.1.0", + "@radix-ui/react-toggle-group": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.2", "atomic-queue": "^5.0.4", "axios": "^1.6.8", "byte-size": "^8.1.0", "check-disk-space": "^3.4.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", "electron-debug": "^3.2.0", "electron-log": "^4.4.8", "electron-osx-prompt": "^1.4.1", @@ -252,6 +280,7 @@ "fs": "^0.0.1-security", "history": "^5.3.0", "lodash": "^4.17.21", + "lucide-react": "^0.428.0", "node-abi": "^3.47.0", "obs-studio-node": "https://warcraftrecorderstorage.blob.core.windows.net/warcraftrecorder/osn-0.23.71-release-win64.tar.gz", "path": "^0.12.7", @@ -263,6 +292,8 @@ "react-player": "^2.14.1", "react-router-dom": "^6.3.0", "screenfull": "^6.0.2", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7", "tsc": "^2.0.4", "tss-react": "^4.1.1", "wait-queue": "^1.1.4" diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..9e6c2541 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +/* eslint global-require: off */ + +module.exports = { + plugins: [require('tailwindcss'), require('autoprefixer')], +}; diff --git a/src/main/Manager.ts b/src/main/Manager.ts index ad144fcc..36ff9e33 100644 --- a/src/main/Manager.ts +++ b/src/main/Manager.ts @@ -140,8 +140,10 @@ export default class Manager { valid: false, current: this.obsVideoCfg, get: (cfg: ConfigService) => getObsVideoConfig(cfg), - validate: async (config: ObsVideoConfig) => Manager.validateVideoConfig(config), - configure: async (config: ObsVideoConfig) => this.configureObsVideo(config), + validate: async (config: ObsVideoConfig) => + Manager.validateVideoConfig(config), + configure: async (config: ObsVideoConfig) => + this.configureObsVideo(config), }, { name: 'obsAudio', @@ -149,7 +151,8 @@ export default class Manager { current: this.obsAudioCfg, get: (cfg: ConfigService) => getObsAudioConfig(cfg), validate: async () => {}, - configure: async (config: ObsAudioConfig) => this.configureObsAudio(config), + configure: async (config: ObsAudioConfig) => + this.configureObsAudio(config), }, { name: 'flavour', @@ -164,8 +167,10 @@ export default class Manager { valid: false, current: this.overlayCfg, get: (cfg: ConfigService) => getOverlayConfig(cfg), - validate: async (config: ObsOverlayConfig) => Manager.validateOverlayConfig(config), - configure: async (config: ObsOverlayConfig) => this.configureObsOverlay(config), + validate: async (config: ObsOverlayConfig) => + Manager.validateOverlayConfig(config), + configure: async (config: ObsOverlayConfig) => + this.configureObsOverlay(config), }, /* eslint-enable prettier/prettier */ ]; @@ -384,7 +389,7 @@ export default class Manager { this.eraLogHandler?.activity; if (inOverrun) { - this.refreshRecStatus(RecStatus.Overruning); + this.refreshRecStatus(RecStatus.Overrunning); } else if (inActivity) { this.refreshRecStatus(RecStatus.Recording); } else if (this.recorder.obsState === ERecordingState.Recording) { diff --git a/src/main/constants.ts b/src/main/constants.ts index 66bcd009..0600902f 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -28,13 +28,13 @@ const obsResolutions = { '2560x1600': { width: 2560, height: 1600 }, '3440x1440': { width: 3440, height: 1440 }, '3440x1200': { width: 3840, height: 1200 }, - '3520x990' : { width: 3520, height: 990 }, + '3520x990': { width: 3520, height: 990 }, '3840x1080': { width: 3840, height: 1080 }, '3840x1440': { width: 3840, height: 1440 }, '3840x1600': { width: 3840, height: 1600 }, '3840x2160': { width: 3840, height: 2160 }, '5120x1440': { width: 5120, height: 1440 }, - '5120x2160': { width: 5120, height: 2160}, + '5120x2160': { width: 5120, height: 2160 }, /* eslint-enable prettier/prettier */ }; @@ -1030,18 +1030,15 @@ const videoButtonSx = { const scrollBarSx = { scrollbarWidth: 'thin', '&::-webkit-scrollbar': { - width: '0.5em', + width: '0.125em', }, '&::-webkit-scrollbar-track': { - background: '#f1f1f1', - borderRadius: '2px', - border: '1px solid black', + background: 'transparent', boxSizing: 'border-box', }, '&::-webkit-scrollbar-thumb': { - backgroundColor: '#888', - borderRadius: '2px', - border: '1px solid black', + backgroundColor: 'hsl(var(--popover))', + borderRadius: '6px', boxSizing: 'border-box', }, '&::-webkit-scrollbar-thumb:hover': { diff --git a/src/main/main.ts b/src/main/main.ts index 70a1c474..2676dda6 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -162,7 +162,7 @@ const createWindow = async () => { // This shows the correct version on a release build, not during development. mainWindow.webContents.send( - 'updateTitleBar', + 'updateVersionDisplay', `Warcraft Recorder v${appVersion}` ); diff --git a/src/main/types.ts b/src/main/types.ts index f166b66f..0c2bba67 100644 --- a/src/main/types.ts +++ b/src/main/types.ts @@ -20,7 +20,7 @@ enum RecStatus { InvalidConfig, ReadyToRecord, FatalError, - Overruning, + Overrunning, Reconfiguring, } @@ -470,7 +470,7 @@ type CheckAuthResponse = { type WindowCaptureChoice = { name: string; - value: string | number; + value: string; }; export { diff --git a/src/renderer/App.css b/src/renderer/App.css index 9756ae10..5f36b106 100644 --- a/src/renderer/App.css +++ b/src/renderer/App.css @@ -2,13 +2,90 @@ * @NOTE: Prepend a `~` to css file paths that are in your node_modules * See https://github.com/webpack-contrib/sass-loader#imports */ +@import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap'); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 9%; + --background-higher: 0 0% 11%; + --background-dark-gradient-from: 0 0% 7%; + --background-dark-gradient-to: 0 0% 8%; + + --foreground: 0, 0%, 45%; + --foreground-lighter: 0, 0%, 66%; + + --muted: 223 47% 11%; + --muted-foreground: 215.4 16.3% 56.9%; + + --accent: 216 34% 17%; + --accent-foreground: 210 40% 98%; + + --popover: 0 0% 30%; + --popover-foreground: 0 0% 86%; + --popover-border: 0 0% 25%; + --popover-inset: 0 0% 35%; + + --border: 216 34% 17%; + --input: 216 34% 17%; + + --card: 0 0% 23%; + --card-foreground: 0 0% 69%; + + --primary: 14 71% 43%; + --primary-foreground: 0 0% 100%; + + --secondary: 0 0% 28%; + --secondary-foreground: 0 0% 69%; + + --destructive: 0 63% 31%; + --destructive-foreground: 210 40% 98%; + + --ring: 216 34% 17%; + + --radius: 0.5rem; + + --font-sans: 'Inter'; + + --success: 149, 69%, 51%; + --success-border: 149, 66%, 39%; + + --error: 0, 70%, 35%; + --error-border: 0, 68%, 26%; + --error-foreground: 0, 70%, 66%; + + --warning: 45, 93%, 47%; + --warning-border: 45, 90%, 35%; + + --blue-accent: 200, 98%, 39%; + --blue-accent-border: 200, 95%, 27%; + + --video-item-background: 0 0% 18%; + --video-item-background-hover: 0 0% 24%; + --video-item-border: 0 0% 21.16%; + --video-item-foreground: 0 0% 77.17%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + font-feature-settings: 'rlig' 1, 'calt' 1; + } +} html { margin: 0px; height: 100%; width: 100%; overflow: clip; - background-color: #1a233a; + background-color: var(--background); } body { @@ -37,24 +114,6 @@ div#root { #title-bar-btns { -webkit-app-region: no-drag; - position: fixed; - top: 1px; - right: 0px; -} - -#title-bar-btns button { - height: 32px; - width: 32px; - background-color: transparent; - border: none; - color: white; - font-size: 16px; - outline: none; -} - -#title-bar-btns button:hover { - background-color: #1a1a1a; - outline: none; } #navigator { @@ -66,12 +125,6 @@ div#root { text-align: center; } -#logo { - position: fixed; - top: 5px; - left: 5px; -} - .status-buttons { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); @@ -1033,4 +1086,4 @@ input[type='button'].btn-block, input[type='reset'].btn-block, input[type='submit'].btn-block { width: 100%; -} \ No newline at end of file +} diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index a23d8dc6..5567af25 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -12,13 +12,17 @@ import { RendererVideo, } from 'main/types'; import Box from '@mui/material/Box'; +import { ArrowBigDownDash } from 'lucide-react'; import Layout from './Layout'; import RendererTitleBar from './RendererTitleBar'; -import BottomStatusBar from './BottomStatusBar'; import './App.css'; import { useSettings } from './useSettings'; import { getCategoryFromConfig } from './rendererutils'; import StateManager from './StateManager'; +import { TooltipProvider } from './components/Tooltip/Tooltip'; +import Toaster from './components/Toast/Toaster'; +import { useToast } from './components/Toast/useToast'; +import { ToastAction } from './components/Toast/Toast'; const ipc = window.electron.ipcRenderer; @@ -27,6 +31,8 @@ const WarcraftRecorder = () => { const [error, setError] = useState(''); const [micStatus, setMicStatus] = useState(MicStatus.NONE); const [crashes, setCrashes] = useState([]); + const upgradeNotified = useRef(false); + const { toast } = useToast(); // The video state contains most of the frontend state, it's complex so // frontend triggered modifications go through the StateManager class, which @@ -46,6 +52,28 @@ const WarcraftRecorder = () => { link: undefined, }); + useEffect(() => { + if (upgradeNotified.current) return; + + if (upgradeStatus.available) { + toast({ + title: 'Update available!', + description: + 'There is an update available for Warcraft Recorder. Please click the button below to download it.', + action: ( + ipc.sendMessage('openURL', [upgradeStatus.link])} + > + Download + + ), + duration: 60000, // stay up for a minute I guess + }); + upgradeNotified.current = true; + } + }, [upgradeStatus, upgradeNotified, toast]); + const [savingStatus, setSavingStatus] = useState( SaveStatus.NotSaving ); @@ -135,24 +163,24 @@ const WarcraftRecorder = () => { width: '100%', }} > - - - + + + + + ); }; diff --git a/src/renderer/ArenaCompDisplay.tsx b/src/renderer/ArenaCompDisplay.tsx index f878d2d9..4b6f9e9d 100644 --- a/src/renderer/ArenaCompDisplay.tsx +++ b/src/renderer/ArenaCompDisplay.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import CloseIcon from '@mui/icons-material/Close'; import { specializationById } from 'main/constants'; @@ -15,7 +15,6 @@ const ArenaCompDisplay: React.FC = (props: IProps) => { const { video } = props; const { combatants, category } = video; const isSoloShuffle = category === VideoCategory.SoloShuffle; - const fontSize = '0.75rem'; const iconSize = '18px'; if (combatants === undefined) { @@ -79,19 +78,12 @@ const ArenaCompDisplay: React.FC = (props: IProps) => { justifyContent: 'end', }} > - {combatant._name} - + = (props: IProps) => { objectFit: 'cover', }} /> - {combatant._name} - + ); }; diff --git a/src/renderer/ArenaInfo.tsx b/src/renderer/ArenaInfo.tsx index 255196e1..1953c9f2 100644 --- a/src/renderer/ArenaInfo.tsx +++ b/src/renderer/ArenaInfo.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import { RendererVideo } from 'main/types'; import { getVideoResultText } from './rendererutils'; @@ -14,55 +14,25 @@ const ArenaInfo: React.FC = (props: IProps) => { const renderResultText = () => { return ( - + {resultText} - + ); }; const renderMapName = () => { return ( - + {zoneName} - + ); }; const renderCategoryName = () => { return ( - + {category} - + ); }; diff --git a/src/renderer/AudioSourceControls.tsx b/src/renderer/AudioSourceControls.tsx index ed50f36b..f4dcd0e0 100644 --- a/src/renderer/AudioSourceControls.tsx +++ b/src/renderer/AudioSourceControls.tsx @@ -1,30 +1,10 @@ -import { - Box, - Checkbox, - Chip, - FormControl, - FormControlLabel, - IconButton, - InputLabel, - ListItemText, - MenuItem, - Select, - SelectChangeEvent, - Slider, - Stack, - Switch, - TextField, - Tooltip, -} from '@mui/material'; import { DeviceType, IOBSDevice } from 'main/types'; import React from 'react'; -import { VolumeDown, VolumeUp } from '@mui/icons-material'; import { configSchema } from 'main/configSchema'; -import InfoIcon from '@mui/icons-material/Info'; +import { Info, Volume1, Volume2 } from 'lucide-react'; import { useSettings, setConfigValues } from './useSettings'; import { blurAll, - getAudioDeviceDescription, getKeyByValue, getKeyModifiersString, getNextKeyOrMouseEvent, @@ -32,66 +12,12 @@ import { standardizeAudioDeviceNames, } from './rendererutils'; import { PTTKeyPressEvent, UiohookKeyMap } from '../types/KeyTypesUIOHook'; - -const selectStyle = { - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, - '.MuiSvgIcon-root ': { - fill: 'white !important', - }, -}; - -const sliderSx = { - '& .MuiSlider-thumb': { - color: 'white', - }, - '& .MuiSlider-track': { - color: '#bb4220', - }, - '& .MuiSlider-rail': { - color: '#bb4220', - }, - '& .MuiSlider-active': { - color: '#bb4220', - }, -}; - -const formControlStyle = { m: 1, width: '100%' }; - -const switchStyle = { - mx: 2, - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import Label from './components/Label/Label'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { MultiSelect } from './components/MultiSelect/MultiSelect'; +import Slider from './components/Slider/Slider'; +import Switch from './components/Switch/Switch'; +import { Input } from './components/Input/Input'; const ipc = window.electron.ipcRenderer; let debounceTimer: NodeJS.Timer | undefined; @@ -195,255 +121,199 @@ const AudioSourceControls: React.FC = () => { audioDevices ); - const handleMultiSelect = ( - type: DeviceType, - event: SelectChangeEvent - ) => { - const { - target: { value }, - } = event; - - const standardizedValue = standardizeAudioDeviceNames( - value, + const onDeviceChange = (type: DeviceType, values: string[]) => { + const standardizedValues = standardizeAudioDeviceNames( + values, audioDevices ).join(); - if (type === DeviceType.INPUT) { setConfig((prevState) => { return { ...prevState, - audioInputDevices: standardizedValue, + audioInputDevices: standardizedValues, }; }); } else { setConfig((prevState) => { return { ...prevState, - audioOutputDevices: standardizedValue, + audioOutputDevices: standardizedValues, }; }); } }; - const getSelectedChip = (id: string) => { - const description = getAudioDeviceDescription(id, audioDevices); - return ( - - ); - }; - - const renderSelected = (selected: string[]) => { - return ( - - {selected !== undefined && selected.map(getSelectedChip)} - - ); - }; - - const getOutputMenuItem = (device: IOBSDevice) => { - const tooManySelected = output.length >= 5; - const isSelected = output.indexOf(device.id) > -1; - - return ( - - - - - ); - }; - - const getInputMenuItem = (device: IOBSDevice) => { - const tooManySelected = input.length >= 5; - const isSelected = input.indexOf(device.id) > -1; - - return ( - - - - - ); - }; - const getSpeakerSelect = () => { return ( - - Speakers - - +
+ + ({ + value: audioDevice.id, + label: audioDevice.description, + }))} + onValueChange={(values) => onDeviceChange(DeviceType.OUTPUT, values)} + defaultValue={output} + placeholder="Select an output device" + maxCount={1} + /> +
); }; - const setSpeakerVolume = (_event: Event, newValue: number | number[]) => { - if (typeof newValue !== 'number') { + const setSpeakerVolume = (newValue: number[]) => { + if (typeof newValue[0] !== 'number') { return; } setConfig((prevState) => { return { ...prevState, - speakerVolume: newValue / 100, + speakerVolume: newValue[0] / 100, }; }); }; const getSpeakerVolume = () => { return ( - - - - - - - +
+ + + +
); }; const getMicSelect = () => { return ( - - Mics - - +
+ + ({ + value: audioDevice.id, + label: audioDevice.description, + }))} + onValueChange={(values) => onDeviceChange(DeviceType.INPUT, values)} + defaultValue={input} + placeholder="Select an input device" + maxCount={1} + /> +
); }; - const setMicVolume = (_event: Event, newValue: number | number[]) => { - if (typeof newValue !== 'number') { + const setMicVolume = (newValue: number[]) => { + if (typeof newValue[0] !== 'number') { return; } setConfig((prevState) => { return { ...prevState, - micVolume: newValue / 100, + micVolume: newValue[0] / 100, }; }); }; const getMicVolume = () => { return ( - - - - - - - +
+ + + +
); }; - const setForceMono = (event: React.ChangeEvent) => { + const setForceMono = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - obsForceMono: event.target.checked, + obsForceMono: checked, }; }); }; - const setPushToTalk = (event: React.ChangeEvent) => { + const setPushToTalk = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - pushToTalk: event.target.checked, + pushToTalk: checked, }; }); }; - const setAudioSuppression = (event: React.ChangeEvent) => { + const setAudioSuppression = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - obsAudioSuppression: event.target.checked, + obsAudioSuppression: checked, }; }); }; const getMonoSwitch = () => { return ( - + +
- } - label="Mono Input" - labelPlacement="top" - sx={{ - color: 'white', - }} - /> +
+ ); }; const getPushToTalkSwitch = () => { return ( - - } - label="Push To Talk" - labelPlacement="top" - sx={{ - color: 'white', - }} - /> +
+ +
+ +
+
); }; @@ -481,99 +351,68 @@ const AudioSourceControls: React.FC = () => { const getPushToTalkSelect = () => { return ( - setPttHotKeyFieldFocused(true)} - onBlur={() => setPttHotKeyFieldFocused(false)} - /> +
+ + setPttHotKeyFieldFocused(true)} + onBlur={() => setPttHotKeyFieldFocused(false)} + readOnly + /> +
); }; const getAudioSuppressionSwitch = () => { return ( - + +
- } - label="Audio Suppression" - labelPlacement="top" - sx={{ - color: 'white', - }} - /> - ); - }; - - const getInfoIcon = () => { - const helptext = [ - /* eslint-disable prettier/prettier */ - ['Speakers', configSchema.audioOutputDevices.description].join('\n'), - ['Mics', configSchema.audioInputDevices.description].join('\n'), - ['Audio Suppression', configSchema.obsAudioSuppression.description].join('\n'), - ['Mono Input', configSchema.obsForceMono.description].join('\n'), - ['Push To Talk', configSchema.pushToTalk.description].join('\n'), - // eslint-enable prettier/prettier */ - ].join('\n\n'); - - return ( - {helptext}
}> - - - - + + ); }; return ( - - - {getSpeakerSelect()} - {getSpeakerVolume()} - - - {getMicSelect()} - {getMicVolume()} - - {getAudioSuppressionSwitch()} - {getMonoSwitch()} - {getPushToTalkSwitch()} - {config.pushToTalk && getPushToTalkSelect()} - {getInfoIcon()} - +
+
+
+ {getSpeakerSelect()} + {getSpeakerVolume()} +
+
+ {getMicSelect()} + {getMicVolume()} +
+ {getAudioSuppressionSwitch()} + {getMonoSwitch()} +
+
+ {getPushToTalkSwitch()} + {config.pushToTalk && getPushToTalkSelect()} +
+
); }; diff --git a/src/renderer/BattlegroundInfo.tsx b/src/renderer/BattlegroundInfo.tsx index e60d7c58..8cf80719 100644 --- a/src/renderer/BattlegroundInfo.tsx +++ b/src/renderer/BattlegroundInfo.tsx @@ -1,6 +1,5 @@ import React from 'react'; import Box from '@mui/material/Box'; -import { Typography } from '@mui/material'; import { RendererVideo } from 'main/types'; interface IProps { @@ -22,18 +21,9 @@ const BattlegroundInfo: React.FC = (props: IProps) => { justifyContent: 'center', }} > - + {zoneName} - + ); }; diff --git a/src/renderer/BottomStatusBar.tsx b/src/renderer/BottomStatusBar.tsx index 41cb339a..48188f7b 100644 --- a/src/renderer/BottomStatusBar.tsx +++ b/src/renderer/BottomStatusBar.tsx @@ -1,10 +1,4 @@ -import { - Crashes, - MicStatus, - RecStatus, - SaveStatus, - UpgradeStatus, -} from 'main/types'; +import { Crashes, MicStatus, RecStatus, SaveStatus } from 'main/types'; import Box from '@mui/material/Box'; import { Fade, LinearProgress, Typography } from '@mui/material'; import { useEffect, useState } from 'react'; @@ -13,28 +7,19 @@ import LogButton from './LogButton'; import RecorderStatus from './RecorderStatus'; import SavingStatus from './SavingStatus'; import TestButton from './TestButton'; -import VersionUpdateWidget from './VersionUpdateWidget'; import MicrophoneStatus from './MicrophoneStatus'; import CrashStatus from './CrashStatus'; interface IProps { recorderStatus: RecStatus; error: string; - upgradeStatus: UpgradeStatus; savingStatus: SaveStatus; micStatus: MicStatus; crashes: Crashes; } const BottomStatusBar: React.FC = (props: IProps) => { - const { - recorderStatus, - error, - upgradeStatus, - savingStatus, - micStatus, - crashes, - } = props; + const { recorderStatus, error, savingStatus, micStatus, crashes } = props; const [showUploadProgressBar, setShowUploadProgressBar] = useState(false); const [showDownloadProgressBar, setShowDownloadProgressBar] = useState(false); @@ -148,20 +133,7 @@ const BottomStatusBar: React.FC = (props: IProps) => { }; return ( - +
= (props: IProps) => { }} > - @@ -204,7 +175,7 @@ const BottomStatusBar: React.FC = (props: IProps) => { - +
); }; diff --git a/src/renderer/CategoryPage.tsx b/src/renderer/CategoryPage.tsx index 2a8e5ddd..418b0792 100644 --- a/src/renderer/CategoryPage.tsx +++ b/src/renderer/CategoryPage.tsx @@ -1,15 +1,9 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import { AppState, RendererVideo } from 'main/types'; -import { - Button, - List, - ListItem, - ListItemButton, - Typography, -} from '@mui/material'; +import { List } from '@mui/material'; import { scrollBarSx } from 'main/constants'; -import { MutableRefObject, useState } from 'react'; +import { MutableRefObject } from 'react'; import { VideoPlayer } from './VideoPlayer'; import { VideoCategory } from '../types/VideoCategory'; import SearchBar from './SearchBar'; @@ -23,6 +17,9 @@ import { import VideoFilter from './VideoFilter'; import VideoButton from './VideoButton'; import StateManager from './StateManager'; +import Separator from './components/Separator/Separator'; +import { Button } from './components/Button/Button'; +import { cn } from './components/utils'; interface IProps { category: VideoCategory; @@ -120,27 +117,23 @@ const CategoryPage = (props: IProps) => { : 'transparent'; return ( - - handleChangeVideo(videoState.indexOf(video))} + role="button" + > + handleChangeVideo(videoState.indexOf(video))} - > - - - + persistentProgress={persistentProgress} + /> + ); }; @@ -167,17 +160,8 @@ const CategoryPage = (props: IProps) => { > @@ -188,28 +172,18 @@ const CategoryPage = (props: IProps) => { const getVideoSelection = () => { return ( <> - +
{!isClips && ( - - - + )} - +
- - +
+
{ alignContent: 'center', ...scrollBarSx, '&::-webkit-scrollbar': { - width: '1em', + width: '0.33em', }, }} > @@ -241,94 +215,40 @@ const CategoryPage = (props: IProps) => { const renderFirstTimeUserPrompt = () => { return ( - - - You have no videos saved for this category. If it is your first time - here, setup instructions can be found at the link below. If you have - problems, please use the Discord #help channel to get support. - - - +
+

+ You have no videos saved for this category +

+ +

+ If it is your first time here, setup instructions can be found at the + link below. If you have problems, please use the Discord #help channel + to get support. +

+ +
); }; const renderFirstTimeClipPrompt = () => { return ( - - - You have no clips saved. Videos you clip will display here. - - +
+

You have no clips saved

+ +

+ Videos you clip will be displayed here. +

+
); }; return ( - +
{haveVideos && getVideoPlayer()} {haveVideos && getVideoSelection()} {!haveVideos && !isClips && renderFirstTimeUserPrompt()} {!haveVideos && isClips && renderFirstTimeClipPrompt()} - +
); }; diff --git a/src/renderer/ChatOverlayControls.tsx b/src/renderer/ChatOverlayControls.tsx index 5e16b95b..55254388 100644 --- a/src/renderer/ChatOverlayControls.tsx +++ b/src/renderer/ChatOverlayControls.tsx @@ -1,58 +1,13 @@ -import { - Box, - FormControlLabel, - IconButton, - Switch, - TextField, - Tooltip, -} from '@mui/material'; -import React, { ChangeEvent } from 'react'; +import React from 'react'; import { configSchema } from 'main/configSchema'; -import InfoIcon from '@mui/icons-material/Info'; -import LockIcon from '@mui/icons-material/Lock'; +import { Info, Lock } from 'lucide-react'; import { useSettings, setConfigValues, getConfigValue } from './useSettings'; -import ChatOverlaySlider from './ChatOverlaySlider'; import { fileSelect } from './rendererutils'; - -const textFieldStyle = { - width: '300px', - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, -}; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import Label from './components/Label/Label'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import Switch from './components/Switch/Switch'; +import { Input } from './components/Input/Input'; +import Slider from './components/Slider/Slider'; const ipc = window.electron.ipcRenderer; @@ -92,279 +47,212 @@ const ChatOverlayControls: React.FC = () => { config.chatOverlayYPosition, ]); - const setOverlayEnabled = (event: ChangeEvent) => { + const setOverlayEnabled = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - chatOverlayEnabled: event.target.checked, + chatOverlayEnabled: checked, }; }); }; - const setOwnImage = (event: ChangeEvent) => { + const setOwnImage = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - chatOverlayOwnImage: event.target.checked, + chatOverlayOwnImage: checked, }; }); }; - const setWidth = (width: number) => { + const setWidth = (width: number[]) => { setConfig((prevState) => { return { ...prevState, - chatOverlayWidth: width, + chatOverlayWidth: width[0], }; }); }; - const setHeight = (height: number) => { + const setHeight = (height: number[]) => { setConfig((prevState) => { return { ...prevState, - chatOverlayHeight: height, + chatOverlayHeight: height[0], }; }); }; - const setXPosition = (xPos: number) => { + const setXPosition = (xPos: number[]) => { setConfig((prevState) => { return { ...prevState, - chatOverlayXPosition: xPos, + chatOverlayXPosition: xPos[0], }; }); }; - const setYPosition = (yPos: number) => { + const setYPosition = (yPos: number[]) => { setConfig((prevState) => { return { ...prevState, - chatOverlayYPosition: yPos, + chatOverlayYPosition: yPos[0], }; }); }; const getChatOverlayEnabledSwitch = () => { return ( - + +
- } - label={ - - Chat Overlay - - } - labelPlacement="top" - sx={{ color: 'white' }} - /> - ); - }; - - const getProOnlyIcon = () => { - return ( - - - - - +
+ ); }; const getChatOverlayOwnImageSwitch = () => { return ( - + +
- } - label={ - - Own Image - {getProOnlyIcon()} - - } - labelPlacement="top" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> +
+ ); }; const getChatOverlaySizeSliders = () => { - const disabled = !config.chatOverlayEnabled || config.chatOverlayOwnImage; + if (config.chatOverlayOwnImage) return null; + const disabled = !config.chatOverlayEnabled; return ( - - +
+ +
+ - } - label="Width" - labelPlacement="start" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> - +
+
+
+ +
+ - } - label="Height" - labelPlacement="start" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> - +
+
+ ); }; const getChatOverlayPositionSliders = () => { return ( - - +
+ +
+ - } - label="Horizonal" - labelPlacement="start" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> - +
+
+ +
+ - } - label="Vertical" - labelPlacement="start" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> - +
+
+
); }; - const setScale = (scale: number) => { + const setScale = (scale: number[]) => { setConfig((prevState) => { return { ...prevState, - chatOverlayScale: scale, + chatOverlayScale: scale[0], }; }); }; const getScaleSlider = () => { return ( - - - } - label="Scale" - labelPlacement="start" - sx={{ - color: 'white', - '& .MuiFormControlLabel-label.Mui-disabled': { - color: 'white', - }, - }} - /> - - ); - }; - - const getInfoIcon = () => { - const helptext = [ - /* eslint-disable prettier/prettier */ - ['Chat Overlay', configSchema.chatOverlayEnabled.description].join('\n'), - ['Own Image', configSchema.chatOverlayOwnImage.description].join('\n'), - ['Image Path', configSchema.chatOverlayOwnImagePath.description].join('\n'), - ['Width & Height', 'How the default image should be cropped. Not available for custom overlays.'].join('\n'), - ['Horizontal & Vertical', 'The coordinates on the scene where the overlay should be placed.'].join('\n'), - ['Scale', configSchema.chatOverlayScale.description].join('\n'), - /* eslint-enable prettier/prettier */ - ].join('\n\n'); - - return ( - {helptext}}> - - - - +
+ +
+ +
+
); }; @@ -385,60 +273,43 @@ const ChatOverlayControls: React.FC = () => { const getOwnImagePathField = () => { return ( - +
+ + +
); }; return ( - - +
+
{getChatOverlayEnabledSwitch()} {getChatOverlayOwnImageSwitch()} {config.cloudStorage && config.chatOverlayOwnImage && getOwnImagePathField()} - {getInfoIcon()} - - - - {getChatOverlaySizeSliders()} - {getChatOverlayPositionSliders()} - {getScaleSlider()} - - +
+ {config.chatOverlayEnabled && ( +
+ {getChatOverlaySizeSliders()} + {getChatOverlayPositionSliders()} + {getScaleSlider()} +
+ )} +
); }; diff --git a/src/renderer/CloudSettings.tsx b/src/renderer/CloudSettings.tsx index 0af51dd1..9d5dea9f 100644 --- a/src/renderer/CloudSettings.tsx +++ b/src/renderer/CloudSettings.tsx @@ -1,45 +1,28 @@ import * as React from 'react'; -import Box from '@mui/material/Box'; -import { - FormControl, - FormControlLabel, - InputLabel, - LinearProgress, - MenuItem, - Select, - SelectChangeEvent, - Switch, - TextField, - Tooltip, - Typography, -} from '@mui/material'; -import { ConfigurationSchema } from 'main/configSchema'; +import { configSchema, ConfigurationSchema } from 'main/configSchema'; import { CloudStatus, RecStatus } from 'main/types'; import { useState } from 'react'; -import CloudIcon from '@mui/icons-material/Cloud'; +import { Cloud, Info } from 'lucide-react'; import { setConfigValues, useSettings } from './useSettings'; +import Switch from './components/Switch/Switch'; +import Label from './components/Label/Label'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { Input } from './components/Input/Input'; +import Progress from './components/Progress/Progress'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from './components/Select/Select'; +import Separator from './components/Separator/Separator'; +import TextBanner from './components/TextBanner/TextBanner'; const ipc = window.electron.ipcRenderer; const raidDifficultyOptions = ['LFR', 'Normal', 'Heroic', 'Mythic']; -const formControlLabelStyle = { color: 'white', m: 2 }; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; - let debounceTimer: NodeJS.Timer | undefined; interface IProps { @@ -124,7 +107,7 @@ const CloudSettings = (props: IProps) => { const isComponentDisabled = () => { const isRecording = recorderStatus === RecStatus.Recording; - const isOverrunning = recorderStatus === RecStatus.Overruning; + const isOverrunning = recorderStatus === RecStatus.Overrunning; return isRecording || isOverrunning; }; @@ -134,96 +117,53 @@ const CloudSettings = (props: IProps) => { } return ( - - Some settings in this category are currently hidden as they can not be + + Some settings in this category are currently hidden as they cannot be modified while a recording is active. - + ); }; const getSwitch = ( preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => ( ); const getSwitchForm = ( preference: keyof ConfigurationSchema, - label: string, - width: string | undefined = undefined + label: string ) => { - const changeFn = (event: React.ChangeEvent) => { + const changeFn = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - [preference]: event.target.checked, + [preference]: checked, }; }); }; return ( - +
+ +
+ {getSwitch(preference, changeFn)} +
+
); }; - const formControlStyle = { width: '100%' }; - - const style = { - m: 1, - width: '100%', - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, - '.MuiSvgIcon-root ': { - fill: 'white !important', - }, - }; - - const setMinRaidThreshold = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setMinRaidThreshold = (value: string) => { setConfig((prevState) => { return { ...prevState, @@ -238,25 +178,36 @@ const CloudSettings = (props: IProps) => { } return ( - - +
+ - +
); }; @@ -279,24 +230,34 @@ const CloudSettings = (props: IProps) => { } return ( - +
+ + +
); }; - const setCloudStorage = (event: React.ChangeEvent) => { + const setCloudStorage = (checked: boolean) => { setConfig((prevState) => { - const cloudStorage = event.target.checked; + const cloudStorage = checked; const newState = { ...prevState, @@ -313,11 +274,11 @@ const CloudSettings = (props: IProps) => { }); }; - const setCloudUpload = (event: React.ChangeEvent) => { + const setCloudUpload = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - cloudUpload: event.target.checked, + cloudUpload: checked, }; }); }; @@ -328,15 +289,17 @@ const CloudSettings = (props: IProps) => { } return ( - - - +
+ +
+ {getSwitch('cloudStorage', setCloudStorage)} +
+
); }; @@ -346,25 +309,25 @@ const CloudSettings = (props: IProps) => { } return ( - - - +
+ +
+ {getSwitch('cloudUpload', setCloudUpload)} +
+
); }; - const setCloudUploadRateLimit = ( - event: React.ChangeEvent - ) => { + const setCloudUploadRateLimit = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - cloudUploadRateLimit: event.target.checked, + cloudUploadRateLimit: checked, }; }); }; @@ -375,15 +338,20 @@ const CloudSettings = (props: IProps) => { } return ( - - - +
+ +
+ {getSwitch('cloudUploadRateLimit', setCloudUploadRateLimit)} +
+
); }; @@ -404,21 +372,29 @@ const CloudSettings = (props: IProps) => { } return ( - - + + - + {config.cloudAccountName === '' && ( + + Cannot be empty + + )} + ); }; @@ -439,23 +415,30 @@ const CloudSettings = (props: IProps) => { } return ( - - + + - + {config.cloudAccountPassword === '' && ( + + Cannot be empty + + )} + ); }; @@ -474,21 +457,26 @@ const CloudSettings = (props: IProps) => { } return ( - - + + - + {config.cloudGuildName === '' && ( + + Cannot be empty + + )} + ); }; @@ -498,101 +486,40 @@ const CloudSettings = (props: IProps) => { const perc = Math.round((100 * usage) / max); return ( - - - +
+ + - - + + {Math.round(usage)}GB of {Math.round(max)}GB - - + +
); }; const getCloudUploadCategorySettings = () => { return ( <> - - {getSwitchForm('cloudUploadRaids', 'Upload Raids', '125px')} +
+ {getSwitchForm('cloudUploadRaids', 'Upload Raids')} {getMinRaidDifficultySelect()} - - - - {getSwitchForm('cloudUploadDungeons', 'Upload Mythic+', '125px')} +
+ +
+ {getSwitchForm('cloudUploadDungeons', 'Upload Mythic+')} {getMinKeystoneLevelField()} - - - - {getSwitchForm('cloudUpload2v2', 'Upload 2v2', '125px')} - {getSwitchForm('cloudUpload3v3', 'Upload 3v3', '125px')} - {getSwitchForm('cloudUpload5v5', 'Upload 5v5', '125px')} - {getSwitchForm('cloudUploadSkirmish', 'Upload Skirmish', '125px')} - {getSwitchForm( - 'cloudUploadSoloShuffle', - 'Upload Solo Shuffle', - '150px' - )} - {getSwitchForm( - 'cloudUploadBattlegrounds', - 'Upload Battlegrounds', - '160px' - )} - +
+ +
+ {getSwitchForm('cloudUpload2v2', 'Upload 2v2')} + {getSwitchForm('cloudUpload3v3', 'Upload 3v3')} + {getSwitchForm('cloudUpload5v5', 'Upload 5v5')} + {getSwitchForm('cloudUploadSkirmish', 'Upload Skirmish')} + {getSwitchForm('cloudUploadSoloShuffle', 'Upload Solo Shuffle')} + {getSwitchForm('cloudUploadBattlegrounds', 'Upload Battlegrounds')} +
); }; @@ -615,45 +542,61 @@ const CloudSettings = (props: IProps) => { return <>; } - const helperText = - config.cloudUploadRateLimitMbps < 1 ? 'Must be 1 or greater' : ''; - return ( - +
+ + + {config.cloudUploadRateLimitMbps < 1 && ( + + Must be 1 or greater + + )} +
); }; return ( - +
{getDisabledText()} - - {getCloudSwitch()} - {getCloudUploadSwitch()} - {getCloudUploadRateLimitSwitch()} - {getRateLimitField()} - +
{getCloudSwitch()}
- +
{getCloudAccountNameField()} {getCloudAccountPasswordField()} {getCloudGuildField()} - - - {config.cloudStorage && getCloudUsageBar()} - {config.cloudUpload && getCloudUploadCategorySettings()} - +
+ + {config.cloudStorage && ( + <> + {getCloudUsageBar()} + + + )} + +
+
{getCloudUploadSwitch()}
+
+ {getCloudUploadRateLimitSwitch()} + {getRateLimitField()} +
+ {config.cloudUpload && getCloudUploadCategorySettings()} +
+
); }; diff --git a/src/renderer/DeleteDialog.tsx b/src/renderer/DeleteDialog.tsx new file mode 100644 index 00000000..4656acef --- /dev/null +++ b/src/renderer/DeleteDialog.tsx @@ -0,0 +1,58 @@ +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from './components/Dialog/Dialog'; +import { Button } from './components/Button/Button'; +import ControlIcon from '../../assets/icon/ctrl-icon.png'; +import { Tooltip } from './components/Tooltip/Tooltip'; + +type DeleteDialogProps = { + children: React.ReactNode; + onDelete: (event: React.MouseEvent) => void; + tooltipContent: string; +}; + +const DeleteDialog = ({ + children, + onDelete, + tooltipContent, +}: DeleteDialogProps) => { + return ( + + + {children} + + + + Are you sure? + +
+ Hold{' '} + ctrlIcon{' '} + to skip this prompt. +
+ + + + + + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/renderer/DiscordButton.tsx b/src/renderer/DiscordButton.tsx index 4d57fb98..e0df7eef 100644 --- a/src/renderer/DiscordButton.tsx +++ b/src/renderer/DiscordButton.tsx @@ -1,5 +1,7 @@ -import { Button, Tooltip } from '@mui/material'; -import icon from '../../assets/icon/discord-icon.png'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faDiscord } from '@fortawesome/free-brands-svg-icons'; +import { Button } from './components/Button/Button'; +import { Tooltip } from './components/Tooltip/Tooltip'; const ipc = window.electron.ipcRenderer; @@ -9,14 +11,15 @@ export default function DiscordButton() { }; return ( - + ); diff --git a/src/renderer/DungeonCompDisplay.tsx b/src/renderer/DungeonCompDisplay.tsx index 1f3aa969..4d3d3ecc 100644 --- a/src/renderer/DungeonCompDisplay.tsx +++ b/src/renderer/DungeonCompDisplay.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import { specializationById } from 'main/constants'; import { RawCombatant, RendererVideo } from 'main/types'; @@ -65,7 +65,7 @@ const DungeonCompDisplay: React.FC = (props: IProps) => { sx={{ display: 'flex', flexDirection: 'row', - alignItems: 'flex-end', + alignItems: 'center', justifyContent: 'start', }} > @@ -82,19 +82,12 @@ const DungeonCompDisplay: React.FC = (props: IProps) => { objectFit: 'cover', }} /> - {combatant._name} - +
); }; diff --git a/src/renderer/DungeonInfo.tsx b/src/renderer/DungeonInfo.tsx index 3182a00b..04f3eba1 100644 --- a/src/renderer/DungeonInfo.tsx +++ b/src/renderer/DungeonInfo.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import { RendererVideo } from 'main/types'; import { dungeonAffixesById } from 'main/constants'; @@ -41,56 +41,26 @@ const DungeonInfo: React.FC = (props: IProps) => { objectFit: 'cover', }} /> - + {dungeonAffixesById[affixID]} - +
); }; const renderDungeonName = () => { return ( - + {dungeonName} - + ); }; const renderDungeonLevel = () => { return ( - + +{video.keystoneLevel || video.level} - + ); }; @@ -105,19 +75,9 @@ const DungeonInfo: React.FC = (props: IProps) => { justifyContent: 'center', }} > - + {resultText} - + = (props: IProps) => { justifyContent: 'center', }} > - + {deathCount} - + = (props: IProps) => { const isComponentDisabled = () => { const isRecording = recorderStatus === RecStatus.Recording; - const isOverrunning = recorderStatus === RecStatus.Overruning; + const isOverrunning = recorderStatus === RecStatus.Overrunning; return isRecording || isOverrunning; }; @@ -104,49 +59,37 @@ const FlavourSettings: React.FC = (props: IProps) => { } return ( - - These settings can not be modified while a recording is active. - + + These settings cannot be modified while a recording is active. + ); }; const getSwitch = ( preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => ( ); - const setRecordRetail = (event: React.ChangeEvent) => { + const setRecordRetail = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordRetail: event.target.checked, + recordRetail: checked, }; }); }; - const setRecordClassic = (event: React.ChangeEvent) => { + const setRecordClassic = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordClassic: event.target.checked, + recordClassic: checked, }; }); }; @@ -170,50 +113,50 @@ const FlavourSettings: React.FC = (props: IProps) => { }); }; - const retailLogPathHelperText = () => { - if (config.retailLogPath !== '') { - return ''; - } - - return 'Invalid retail log path'; - }; - const getRetailSettings = () => { if (isComponentDisabled()) { return <>; } return ( - - - - +
+
+ +
+ {getSwitch('recordRetail', setRecordRetail)} +
+
{config.recordRetail && ( - +
+ + + {config.retailLogPath === '' && ( + + Invalid retail log path + + )} +
)} - +
); }; @@ -236,66 +179,61 @@ const FlavourSettings: React.FC = (props: IProps) => { }); }; - const classicLogPathHelperText = () => { - if (config.classicLogPath !== '') { - return ''; - } - - return 'Invalid classic log path'; - }; - const getClassicSettings = () => { if (isComponentDisabled()) { return <>; } return ( - - - - +
+
+ +
+ {getSwitch('recordClassic', setRecordClassic)} +
+
{config.recordClassic && ( - +
+ + + {config.classicLogPath === '' && ( + + Invalid classic log path + + )} +
)} - +
); }; - const eraLogPathHelperText = () => { - if (config.eraLogPath !== '') { - return ''; - } - - return 'Invalid era log path'; - }; - - const setRecordEra = (event: React.ChangeEvent) => { + const setRecordEra = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordEra: event.target.checked, + recordEra: checked, }; }); }; @@ -325,51 +263,51 @@ const FlavourSettings: React.FC = (props: IProps) => { } return ( - - - - +
+
+ +
+ {getSwitch('recordEra', setRecordEra)} +
+
{config.recordEra && ( - +
+ + + {config.eraLogPath === '' && ( + + Invalid Classic Era log path + + )} +
)} - +
); }; return ( - +
{getDisabledText()} {getRetailSettings()} {getClassicSettings()} {getEraSettings()} - +
); }; diff --git a/src/renderer/GeneralSettings.tsx b/src/renderer/GeneralSettings.tsx index 895f5fb0..ab3f94d2 100644 --- a/src/renderer/GeneralSettings.tsx +++ b/src/renderer/GeneralSettings.tsx @@ -1,56 +1,16 @@ import * as React from 'react'; -import TextField from '@mui/material/TextField'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import Box from '@mui/material/Box'; -import { LinearProgress, Switch, Tooltip, Typography } from '@mui/material'; -import { ConfigurationSchema } from 'main/configSchema'; +import { configSchema } from 'main/configSchema'; import { DiskStatus, RecStatus } from 'main/types'; import { useEffect, useRef, useState } from 'react'; -import SaveIcon from '@mui/icons-material/Save'; +import { HardDrive, Info } from 'lucide-react'; import { setConfigValues, useSettings } from './useSettings'; import { pathSelect } from './rendererutils'; - -const style = { - width: '300px', - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, -}; - -const formControlLabelStyle = { color: 'white', m: 2 }; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import { Input } from './components/Input/Input'; +import Label from './components/Label/Label'; +import Switch from './components/Switch/Switch'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import Progress from './components/Progress/Progress'; +import TextBanner from './components/TextBanner/TextBanner'; interface IProps { recorderStatus: RecStatus; @@ -103,33 +63,19 @@ const GeneralSettings: React.FC = (props: IProps) => { config.maxStorage, ]); - const setSeparateBufferPath = ( - event: React.ChangeEvent - ) => { + const setSeparateBufferPath = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, bufferStoragePath: '', - separateBufferPath: event.target.checked, + separateBufferPath: checked, }; }); }; - const getSwitch = ( - preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void - ) => ( - - ); - const isComponentDisabled = () => { const isRecording = recorderStatus === RecStatus.Recording; - const isOverrunning = recorderStatus === RecStatus.Overruning; + const isOverrunning = recorderStatus === RecStatus.Overrunning; return isRecording || isOverrunning; }; @@ -139,20 +85,9 @@ const GeneralSettings: React.FC = (props: IProps) => { } return ( - - These settings can not be modified while a recording is active. - + + These settings cannot be modified while a recording is active. + ); }; @@ -177,21 +112,25 @@ const GeneralSettings: React.FC = (props: IProps) => { } return ( - - + + - + {config.storagePath === '' && ( + Must not be empty + )} + ); }; @@ -220,15 +159,24 @@ const GeneralSettings: React.FC = (props: IProps) => { } return ( - - - +
+ +
+ +
+
); }; @@ -242,19 +190,25 @@ const GeneralSettings: React.FC = (props: IProps) => { } return ( - - + + - + ); }; @@ -273,18 +227,22 @@ const GeneralSettings: React.FC = (props: IProps) => { } return ( - - + + - + ); }; @@ -297,61 +255,29 @@ const GeneralSettings: React.FC = (props: IProps) => { max === 0 ? `${usage}GB of Unlimited` : `${usage}GB of ${max}GB`; return ( - - - +
+ + - - + + {text} - - + +
); }; return ( - +
{getDisabledText()} - - +
{getStoragePathField()} {getBufferSwitch()} - - +
{getBufferPathField()} {getMaxStorageField()} {getDiskUsageBar()} -
+
); }; diff --git a/src/renderer/Layout.tsx b/src/renderer/Layout.tsx index 60d1445a..cc05d4fc 100644 --- a/src/renderer/Layout.tsx +++ b/src/renderer/Layout.tsx @@ -1,22 +1,31 @@ import * as React from 'react'; -import Box from '@mui/material/Box'; -import { Pages, RecStatus, AppState, RendererVideo } from 'main/types'; -import { Badge, Tab, Tabs } from '@mui/material'; -import SettingsIcon from '@mui/icons-material/Settings'; -import TvIcon from '@mui/icons-material/Tv'; +import { + Pages, + RecStatus, + AppState, + RendererVideo, + MicStatus, + Crashes, + UpgradeStatus, + SaveStatus, +} from 'main/types'; import { MutableRefObject } from 'react'; -import ClipIcon from '../../assets/icon/clip-icon.png'; +import { + Clapperboard, + Cog, + Dice2, + Dice3, + Dice5, + Goal, + MonitorCog, + Sword, + Swords, +} from 'lucide-react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faDungeon, faDragon } from '@fortawesome/free-solid-svg-icons'; import { VideoCategory } from '../types/VideoCategory'; import SceneEditor from './SceneEditor'; import SettingsPage from './SettingsPage'; -import RaidIcon from '../../assets/icon/dragon.png'; -import TwoPeopleIcon from '../../assets/icon/two-people.png'; -import ThreePeopleIcon from '../../assets/icon/three-people.png'; -import FivePeopleIcon from '../../assets/icon/five-people.png'; -import SwordIcon from '../../assets/icon/swords.png'; -import DaggerIcon from '../../assets/icon/dagger.png'; -import DungeonIcon from '../../assets/icon/dungeon.png'; -import FlagIcon from '../../assets/icon/flag.png'; import { setConfigValue } from './useSettings'; import { getCategoryIndex, @@ -26,6 +35,14 @@ import { } from './rendererutils'; import CategoryPage from './CategoryPage'; import StateManager from './StateManager'; +import Menu from './components/Menu'; +import Separator from './components/Separator/Separator'; +import LogsButton from './LogButton'; +import TestButton from './TestButton'; +import DiscordButton from './DiscordButton'; +import ApplicationStatusCard from './containers/ApplicationStatusCard/ApplicationStatusCard'; +import UpgradeNotifier from './containers/UpgradeNotifier/UpgradeNotifier'; +import { ScrollArea } from './components/ScrollArea/ScrollArea'; interface IProps { recorderStatus: RecStatus; @@ -35,6 +52,11 @@ interface IProps { setAppState: React.Dispatch>; persistentProgress: MutableRefObject; playerHeight: MutableRefObject; + error: string; + micStatus: MicStatus; + crashes: Crashes; + upgradeStatus: UpgradeStatus; + savingStatus: SaveStatus; } /** @@ -49,13 +71,24 @@ const Layout = (props: IProps) => { setAppState, persistentProgress, playerHeight, + error, + micStatus, + crashes, + upgradeStatus, + savingStatus, } = props; const { page, category } = appState; + const [appVersion, setAppVersion] = React.useState(); - const handleChangeCategory = ( - _: React.SyntheticEvent, - newCategory: VideoCategory - ) => { + React.useEffect(() => { + window.electron.ipcRenderer.on('updateVersionDisplay', (t: unknown) => { + if (typeof t === 'string') { + setAppVersion(t.split('v')[1] as string); + } + }); + }, []); + + const handleChangeCategory = (newCategory: VideoCategory) => { const index = getCategoryIndex(newCategory); setConfigValue('selectedCategory', index); @@ -85,7 +118,7 @@ const Layout = (props: IProps) => { }); }; - const handleChangePage = (_: React.SyntheticEvent, newPage: Pages) => { + const handleChangePage = (newPage: Pages) => { setAppState((prevState) => { return { ...prevState, @@ -94,26 +127,18 @@ const Layout = (props: IProps) => { }); }; - const renderCategoryTab = (tabCategory: VideoCategory, tabIcon: string) => { + const renderCategoryTab = ( + tabCategory: VideoCategory, + tabIcon: string | React.ReactNode + ) => { const categoryFilter = getVideoCategoryFilter(tabCategory); const categoryState = videoState.filter(categoryFilter); const numVideos = categoryState.length; return ( - + + + {typeof tabIcon === 'string' ? ( {tabCategory} { height="25" style={{ transform: 'translate(-15px, 0px)' }} /> - - } - sx={{ color: 'white', minHeight: '60px', height: '60px' }} - label={tabCategory} - /> + ) : ( + tabIcon + )} + + {tabCategory} + + ); }; const renderSettingsTab = () => { return ( - } - sx={{ color: 'white', minHeight: '60px', height: '60px' }} - label="Settings" - /> + + + + + General + ); }; const renderSceneTab = () => { return ( - } - sx={{ color: 'white', minHeight: '60px', height: '60px' }} - label="Scene" - /> + + + + + Scene + ); }; - const getTabs = () => { + const SideMenu = () => { return ( - - + + - - {renderCategoryTab(VideoCategory.TwoVTwo, TwoPeopleIcon)} - {renderCategoryTab(VideoCategory.ThreeVThree, ThreePeopleIcon)} - {renderCategoryTab(VideoCategory.FiveVFive, FivePeopleIcon)} - {renderCategoryTab(VideoCategory.Skirmish, DaggerIcon)} - {renderCategoryTab(VideoCategory.SoloShuffle, SwordIcon)} - {renderCategoryTab(VideoCategory.MythicPlus, DungeonIcon)} - {renderCategoryTab(VideoCategory.Raids, RaidIcon)} - {renderCategoryTab(VideoCategory.Battlegrounds, FlagIcon)} - {renderCategoryTab(VideoCategory.Clips, ClipIcon)} - - - - - Recordings + {renderCategoryTab(VideoCategory.TwoVTwo, )} + {renderCategoryTab(VideoCategory.ThreeVThree, )} + {renderCategoryTab(VideoCategory.FiveVFive, )} + {renderCategoryTab(VideoCategory.Skirmish, )} + {renderCategoryTab(VideoCategory.SoloShuffle, )} + {renderCategoryTab( + VideoCategory.MythicPlus, + + )} + {renderCategoryTab( + VideoCategory.Raids, + + )} + {renderCategoryTab(VideoCategory.Battlegrounds, )} + {renderCategoryTab(VideoCategory.Clips, )} + + + + Settings {renderSettingsTab()} {renderSceneTab()} - - - + + +
+ +
+ + + + +
+ {!!appVersion && ( +
+ Version {appVersion} +
+ )} +
+ ); }; @@ -255,20 +264,12 @@ const Layout = (props: IProps) => { }; return ( - - {getTabs()} +
+ {page === Pages.Settings && renderSettingsPage()} {page === Pages.SceneEditor && renderSceneEditor()} {page === Pages.None && renderCategoryPage()} - +
); }; diff --git a/src/renderer/LogButton.tsx b/src/renderer/LogButton.tsx index 96fc7d98..59178745 100644 --- a/src/renderer/LogButton.tsx +++ b/src/renderer/LogButton.tsx @@ -1,24 +1,24 @@ -import { Button, Tooltip } from '@mui/material'; -import DescriptionIcon from '@mui/icons-material/Description'; +import { FileText } from 'lucide-react'; +import { Button } from './components/Button/Button'; +import { Tooltip } from './components/Tooltip/Tooltip'; const ipc = window.electron.ipcRenderer; -export default function SettingsButton() { +export default function LogsButton() { const openLogPath = () => { ipc.sendMessage('logPath', ['open']); }; return ( - + ); diff --git a/src/renderer/PVESettings.tsx b/src/renderer/PVESettings.tsx index a13bd606..5f3b6ca6 100644 --- a/src/renderer/PVESettings.tsx +++ b/src/renderer/PVESettings.tsx @@ -1,63 +1,18 @@ -import FormControlLabel from '@mui/material/FormControlLabel'; -import { - Box, - FormControl, - InputLabel, - MenuItem, - Select, - SelectChangeEvent, - Switch, - TextField, -} from '@mui/material'; -import { ConfigurationSchema } from 'main/configSchema'; +import { configSchema, ConfigurationSchema } from 'main/configSchema'; import React from 'react'; +import { Info } from 'lucide-react'; import { setConfigValues, useSettings } from './useSettings'; - -const formControlStyle = { width: '100%' }; - -const style = { - m: 1, - width: '100%', - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, - '.MuiSvgIcon-root ': { - fill: 'white !important', - }, -}; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import Switch from './components/Switch/Switch'; +import Label from './components/Label/Label'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { Input } from './components/Input/Input'; +import { + Select, + SelectTrigger, + SelectContent, + SelectItem, + SelectValue, +} from './components/Select/Select'; const raidDifficultyOptions = ['LFR', 'Normal', 'Heroic', 'Mythic']; @@ -93,33 +48,37 @@ const PVESettings: React.FC = () => { const getSwitch = ( preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => ( ); - const setRecordRaids = (event: React.ChangeEvent) => { + const setRecordRaids = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordRaids: event.target.checked, + recordRaids: checked, }; }); }; const getRecordRaidSwitch = () => { return ( - +
+ +
+ {getSwitch('recordRaids', setRecordRaids)} +
+
); }; @@ -140,25 +99,28 @@ const PVESettings: React.FC = () => { } return ( - +
+ + +
); }; - const setMinRaidDifficulty = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setMinRaidDifficulty = (value: string) => { setConfig((prevState) => { return { ...prevState, @@ -173,25 +135,33 @@ const PVESettings: React.FC = () => { } return ( - - +
+ - +
); }; @@ -217,17 +187,21 @@ const PVESettings: React.FC = () => { } return ( - +
+ + +
); }; @@ -253,37 +227,46 @@ const PVESettings: React.FC = () => { } return ( - +
+ + +
); }; - const setRecordDungeons = (event: React.ChangeEvent) => { + const setRecordDungeons = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordDungeons: event.target.checked, + recordDungeons: checked, }; }); }; const getRecordDungeonSwitch = () => { return ( - +
+ +
+ {getSwitch('recordDungeons', setRecordDungeons)} +
+
); }; @@ -302,50 +285,43 @@ const PVESettings: React.FC = () => { } return ( - +
+ + +
); }; return ( - - +
+
{getRecordRaidSwitch()} {getMinEncounterDurationField()} {getRaidOverrunField()} {getMinRaidDifficultySelect()} - +
- +
{getRecordDungeonSwitch()} {getMinKeystoneLevelField()} {getDungeonOverrunField()} - - +
+
); }; diff --git a/src/renderer/PVPSettings.tsx b/src/renderer/PVPSettings.tsx index 943aaea8..9f345738 100644 --- a/src/renderer/PVPSettings.tsx +++ b/src/renderer/PVPSettings.tsx @@ -1,23 +1,8 @@ -import FormControlLabel from '@mui/material/FormControlLabel'; -import { Box, Switch } from '@mui/material'; import { ConfigurationSchema } from 'main/configSchema'; import React from 'react'; import { setConfigValues, useSettings } from './useSettings'; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import Switch from './components/Switch/Switch'; +import Label from './components/Label/Label'; const PVPSettings: React.FC = () => { const [config, setConfig] = useSettings(); @@ -49,93 +34,88 @@ const PVPSettings: React.FC = () => { const getSwitch = ( preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => ( ); const getSwitchForm = ( preference: keyof ConfigurationSchema, label: string, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => { return ( - +
+ +
+ {getSwitch(preference, changeFn)} +
+
); }; - const setRecord2v2 = (event: React.ChangeEvent) => { + const setRecord2v2 = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordTwoVTwo: event.target.checked, + recordTwoVTwo: checked, }; }); }; - const setRecord3v3 = (event: React.ChangeEvent) => { + const setRecord3v3 = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordThreeVThree: event.target.checked, + recordThreeVThree: checked, }; }); }; - const setRecord5v5 = (event: React.ChangeEvent) => { + const setRecord5v5 = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordFiveVFive: event.target.checked, + recordFiveVFive: checked, }; }); }; - const setRecordSkirmish = (event: React.ChangeEvent) => { + const setRecordSkirmish = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordSkirmish: event.target.checked, + recordSkirmish: checked, }; }); }; - const setRecordSolo = (event: React.ChangeEvent) => { + const setRecordSolo = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordSoloShuffle: event.target.checked, + recordSoloShuffle: checked, }; }); }; - const setRecordBgs = (event: React.ChangeEvent) => { + const setRecordBgs = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - recordBattlegrounds: event.target.checked, + recordBattlegrounds: checked, }; }); }; return ( - +
{getSwitchForm('recordTwoVTwo', 'Record 2v2', setRecord2v2)} {getSwitchForm('recordThreeVThree', 'Record 3v3', setRecord3v3)} {getSwitchForm('recordFiveVFive', 'Record 5v5', setRecord5v5)} @@ -146,7 +126,7 @@ const PVPSettings: React.FC = () => { 'Record Battlegrounds', setRecordBgs )} - +
); }; diff --git a/src/renderer/PovSelection.tsx b/src/renderer/PovSelection.tsx index 6d49a0a5..ebd1797f 100644 --- a/src/renderer/PovSelection.tsx +++ b/src/renderer/PovSelection.tsx @@ -1,13 +1,6 @@ -import { - Box, - IconButton, - List, - ListItem, - ListItemButton, - Tooltip, - Typography, -} from '@mui/material'; -import { scrollBarSx } from 'main/constants'; +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +import { Box } from '@mui/material'; import { AppState, RendererVideo } from 'main/types'; import CloudIcon from '@mui/icons-material/Cloud'; import SaveIcon from '@mui/icons-material/Save'; @@ -20,28 +13,12 @@ import { stopPropagation, } from './rendererutils'; import * as Images from './images'; - -const listItemButtonSx = { - display: 'flex', - width: '100%', - height: '25px', - alignItems: 'center', - justifyContent: 'center', - p: 0, - '&.Mui-selected, &.Mui-selected:hover': { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - borderRadius: '2px', - }, -}; - -const iconButtonSx = { - height: '25px', - width: '25px', - borderRadius: '2px', - '& .MuiTouchRipple-root .MuiTouchRipple-child': { - borderRadius: '2px', - }, -}; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { + ToggleGroup, + ToggleGroupItem, +} from './components/ToggleGroup/ToggleGroup'; +import { ScrollArea } from './components/ScrollArea/ScrollArea'; interface IProps { povs: RendererVideo[]; @@ -81,7 +58,6 @@ export default function PovSelection(props: IProps) { const cloudSelected = localPovIndex === cloudIndex; const diskSelected = localPovIndex === diskIndex; - const povSelected = cloudSelected || diskSelected; const cloudButtonColor = cloudSelected ? '#bb4420' : 'white'; const diskButtonColor = diskSelected ? '#bb4420' : 'white'; @@ -100,10 +76,12 @@ export default function PovSelection(props: IProps) { * Update state variables following a change of selected point of view. */ const handleChangePov = ( - event: React.MouseEvent, + event: React.MouseEvent | undefined, povIndex: number ) => { - stopPropagation(event); + if (event) { + stopPropagation(event); + } setLocalPovIndex(povIndex); const video = povs[povIndex]; @@ -125,26 +103,20 @@ export default function PovSelection(props: IProps) { */ const getCloudIcon = () => { let opacity = 1; - let title = 'Saved in the cloud'; - - let onClick = ( - event: React.MouseEvent - ) => { - handleChangePov(event, cloudIndex); - }; + let title = 'Use cloud version'; if (!haveCloudVideo) { opacity = 0.2; title = 'No cloud recording is saved'; - onClick = stopPropagation; } return ( - - + handleChangePov(e, cloudIndex)} + className="!pointer-events-auto" > - + ); }; @@ -164,26 +136,19 @@ export default function PovSelection(props: IProps) { */ const getDiskIcon = () => { let opacity = 1; - let title = 'Saved on local disk'; - - let onClick = ( - event: React.MouseEvent - ) => { - handleChangePov(event, diskIndex); - }; + let title = 'Use local disk version'; if (!haveDiskVideo) { opacity = 0.2; title = 'No disk recording is saved'; - onClick = stopPropagation; } return ( - - + handleChangePov(e, diskIndex)} > - + ); }; return ( - - +
{ if (haveCloudVideo) { handleChangePov(event, cloudIndex); @@ -216,40 +175,21 @@ export default function PovSelection(props: IProps) { } }} > - - + {getCloudIcon()} {getDiskIcon()} - - + class-icon - + {name} - + - - - +
+ + ); }; @@ -300,32 +232,32 @@ export default function PovSelection(props: IProps) { }, {}); }; + const povsArray = Object.values(groupByName(povs)); + return ( - - - {Object.values(groupByName(povs)).map((g) => getGroupListItem(g))} - - +
+ {/* + If we don't have more than three, we don't want to render a scrollable area. + + This is because it's a faff to vertically center <3 elements within that area, so let's just forego it. + */} + {povsArray.length > 5 ? ( + <> + +
+ {povsArray.map((g) => getGroupListItem(g))} +
+
+
+ + ) : ( +
+ {povsArray.map((g) => getGroupListItem(g))} +
+ )} +
); } diff --git a/src/renderer/RaidCompAndResult.tsx b/src/renderer/RaidCompAndResult.tsx index f2f3fd7a..fdf9518f 100644 --- a/src/renderer/RaidCompAndResult.tsx +++ b/src/renderer/RaidCompAndResult.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import { RawCombatant, RendererVideo } from 'main/types'; import { specializationById } from 'main/constants'; @@ -123,19 +123,9 @@ const RaidCompAndResult: React.FC = (props: IProps) => { objectFit: 'cover', }} /> - + {roleCount[role as keyof RoleCount]} - + ); }; @@ -168,19 +158,9 @@ const RaidCompAndResult: React.FC = (props: IProps) => { justifyContent: 'center', }} > - + {`${resultText} (Pull ${getPullNumber()})`} - + ); }; @@ -196,19 +176,9 @@ const RaidCompAndResult: React.FC = (props: IProps) => { justifyContent: 'center', }} > - + {deathCount} - + = (props: IProps) => { const renderDifficultyText = () => { return ( - + {difficultyText} - + ); }; const renderEncounterText = () => { return ( - + {encounterName} - + ); }; @@ -56,19 +35,9 @@ const RaidEncounterInfo: React.FC = (props: IProps) => { } return ( - + {zoneName} - + ); }; diff --git a/src/renderer/RecorderStatus.tsx b/src/renderer/RecorderStatus.tsx index 89511428..20c22bf7 100644 --- a/src/renderer/RecorderStatus.tsx +++ b/src/renderer/RecorderStatus.tsx @@ -15,6 +15,7 @@ import { import { RecStatus } from 'main/types'; import React from 'react'; import { getSettings } from './useSettings'; +import StatusLight from './components/StatusLight/StatusLight'; interface IProps { recorderStatus: RecStatus; @@ -160,7 +161,7 @@ export default function RecorderStatus(props: IProps) { ); } - if (recorderStatus === RecStatus.Overruning) { + if (recorderStatus === RecStatus.Overrunning) { return ( <> @@ -198,7 +199,7 @@ export default function RecorderStatus(props: IProps) { return ; } - if (recorderStatus === RecStatus.Overruning) { + if (recorderStatus === RecStatus.Overrunning) { return ; } @@ -231,7 +232,7 @@ export default function RecorderStatus(props: IProps) { if ( recorderStatus === RecStatus.InvalidConfig || - recorderStatus === RecStatus.Overruning + recorderStatus === RecStatus.Overrunning ) { return 'yellow'; } diff --git a/src/renderer/RendererTitleBar.tsx b/src/renderer/RendererTitleBar.tsx index e78f05cc..2dcdbcfd 100644 --- a/src/renderer/RendererTitleBar.tsx +++ b/src/renderer/RendererTitleBar.tsx @@ -1,6 +1,5 @@ -import { Box } from '@mui/material'; -import React from 'react'; -import icon from '../../assets/icon/small-icon.png'; +import { ComponentProps } from 'react'; +import { cn } from './components/utils'; const ipc = window.electron.ipcRenderer; @@ -17,41 +16,45 @@ export default function RendererTitleBar() { ipc.sendMessage('mainWindow', ['quit']); }; - const [title, setTitle] = React.useState('Warcraft Recorder Pro'); - - React.useEffect(() => { - window.electron.ipcRenderer.on('updateTitleBar', (t) => { - setTitle(t as string); - }); - }, []); + const TitleBarButton = ({ + children, + className, + ...props + }: ComponentProps<'button'>) => { + return ( + + ); + }; return ( - - -
{title}
-
- - - +
-
+
); } diff --git a/src/renderer/SceneEditor.tsx b/src/renderer/SceneEditor.tsx index b518a35e..bdb53c3b 100644 --- a/src/renderer/SceneEditor.tsx +++ b/src/renderer/SceneEditor.tsx @@ -1,18 +1,27 @@ import { Box } from '@mui/material'; import React from 'react'; import { RecStatus } from 'main/types'; -import { scrollBarSx } from 'main/constants'; import RecorderPreview from './RecorderPreview'; import ChatOverlayControls from './ChatOverlayControls'; import VideoSourceControls from './VideoSourceControls'; import AudioSourceControls from './AudioSourceControls'; import VideoBaseControls from './VideoBaseControls'; +import { ScrollArea } from './components/ScrollArea/ScrollArea'; +import Separator from './components/Separator/Separator'; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from './components/Tabs/Tabs'; interface IProps { recorderStatus: RecStatus; } -const boxColor = '#141b2d'; +const CategoryHeading = ({ children }: { children: React.ReactNode }) => ( +

{children}

+); const SceneEditor: React.FC = (props: IProps) => { const { recorderStatus } = props; @@ -24,78 +33,46 @@ const SceneEditor: React.FC = (props: IProps) => { flexDirection: 'column', width: '100%', height: '100%', + borderBottomLeftRadius: '6px', }} + className="bg-background-higher pt-[32px]" > - - + + Source + Video + Audio + Overlay + + - - - - - - - - - - - - + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
); }; diff --git a/src/renderer/SearchBar.tsx b/src/renderer/SearchBar.tsx index 417f103d..80a29030 100644 --- a/src/renderer/SearchBar.tsx +++ b/src/renderer/SearchBar.tsx @@ -1,7 +1,8 @@ -import { TextField } from '@mui/material'; import { AppState } from 'main/types'; import { useEffect, useState } from 'react'; import VideoFilter from './VideoFilter'; +import { Input } from './components/Input/Input'; +import Label from './components/Label/Label'; interface IProps { appState: AppState; @@ -42,30 +43,19 @@ const SearchBar = (props: IProps) => { }; return ( - e.stopPropagation()} - sx={{ - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { borderColor: '#bb4220' }, - '& > fieldset': { borderColor: 'black' }, - '&:hover fieldset': { - borderColor: '#bb4220', - }, - }, - '& label.Mui-focused': { color: '#bb4220' }, - input: { color: 'white' }, - height: '40px', - }} - inputProps={{ style: { color: 'white' } }} - /> +
+ + e.stopPropagation()} + /> +
); }; diff --git a/src/renderer/SettingsPage.tsx b/src/renderer/SettingsPage.tsx index fd7a7452..f8d8e885 100644 --- a/src/renderer/SettingsPage.tsx +++ b/src/renderer/SettingsPage.tsx @@ -1,264 +1,89 @@ -import { Box, IconButton, Tooltip, Typography } from '@mui/material'; import React from 'react'; import { RecStatus } from 'main/types'; -import { configSchema } from 'main/configSchema'; -import InfoIcon from '@mui/icons-material/Info'; -import { scrollBarSx } from 'main/constants'; import GeneralSettings from './GeneralSettings'; import WindowsSettings from './WindowsSettings'; import FlavourSettings from './FlavourSettings'; import PVESettings from './PVESettings'; import PVPSettings from './PVPSettings'; import CloudSettings from './CloudSettings'; +import { + Tabs, + TabsList, + TabsContent, + TabsTrigger, +} from './components/Tabs/Tabs'; +import Separator from './components/Separator/Separator'; +import { ScrollArea } from './components/ScrollArea/ScrollArea'; interface IProps { recorderStatus: RecStatus; } -const boxColor = '#141b2d'; - -const getHeading = (heading: string) => { - return ( - - {heading} - - ); -}; - -const getGeneralSettingsInfoIcon = () => { - const helptext = [ - /* eslint-disable prettier/prettier */ - ['Disk Storage Folder', configSchema.storagePath.description].join('\n'), - ['Max Disk Storage', configSchema.maxStorage.description].join('\n'), - ['Separate Buffer Folder', configSchema.separateBufferPath.description].join('\n'), - ['Buffer Storage Folder', configSchema.bufferStoragePath.description].join('\n'), - /* eslint-enable prettier/prettier */ - ].join('\n\n'); - - return ( - {helptext}}> - - - - - ); -}; - -const getGameSettingsInfoIcon = () => { - const helptext = [ - ['Record Retail', configSchema.recordRetail.description].join('\n'), - ['Retail Log Path', configSchema.retailLogPath.description].join('\n'), - ['Record Classic', configSchema.recordClassic.description].join('\n'), - ['Classic Log Path', configSchema.classicLogPath.description].join('\n'), - ['Record Classic Era', configSchema.recordEra.description].join('\n'), - ['Era Log Path', configSchema.eraLogPath.description].join('\n'), - ].join('\n\n'); - - return ( - {helptext}}> - - - - - ); -}; - -const getPVESettingsInfoIcon = () => { - const helptext = [ - /* eslint-disable prettier/prettier */ - ['Record Raids', configSchema.recordRaids.description].join('\n'), - ['Minimum Encounter Duration', configSchema.minEncounterDuration.description].join('\n'), - ['Raid Overrun', configSchema.raidOverrun.description].join('\n'), - ['Minimum Raid Difficulty', configSchema.minRaidDifficulty.description].join('\n'), - ['Record Mythic+', configSchema.recordDungeons.description].join('\n'), - ['Minimum Keystone Level', configSchema.minKeystoneLevel.description].join('\n'), - ['Mythic+ Overrun', configSchema.dungeonOverrun.description].join('\n'), - // eslint-enable prettier/prettier */ - ].join('\n\n'); - - return ( - {helptext}}> - - - - - ); -}; - -const getCloudSettingsInfoIcon = () => { - const helptext = [ - /* eslint-disable prettier/prettier */ - ['Cloud Playback', configSchema.cloudStorage.description].join('\n'), - ['Cloud Upload', configSchema.cloudUpload.description].join('\n'), - ['Upload Rate Limit', configSchema.cloudUploadRateLimit.description].join('\n'), - ['Account Name', configSchema.cloudAccountName.description].join('\n'), - ['Account Password', configSchema.cloudAccountPassword.description].join('\n'), - ['Guild Name', configSchema.cloudGuildName.description].join('\n'), - ['Upload Toggles', "Provides control over what content types get automatically uploaded."].join('\n'), - /* eslint-enable prettier/prettier */ - ].join('\n\n'); - - return ( - {helptext}}> - - - - - ); -}; +const CategoryHeading = ({ children }: { children: React.ReactNode }) => ( +

{children}

+); const SettingsPage: React.FC = (props: IProps) => { const { recorderStatus } = props; return ( - - - {getHeading('General Settings')} - {getGeneralSettingsInfoIcon()} - - - - - - - {getHeading('Game Settings')} - {getGameSettingsInfoIcon()} - - - - - - - {getHeading('PvE Settings')} - {getPVESettingsInfoIcon()} - - - - - - {getHeading('PvP Settings')} - - - - - {getHeading('Windows Settings')} - - - - - - {getHeading('Cloud Settings')} - {getCloudSettingsInfoIcon()} - - - - - +
+ + + Application + Game + Pro + + + +
+
+ General Settings + + +
+
+ Windows Settings + + +
+
+
+ + +
+
+ Game Settings + + +
+
+ PvE Settings + + +
+
+ PvP Settings + + +
+
+
+ +
+
+ Cloud Settings + + +
+
+
+
+
+
); }; diff --git a/src/renderer/TagDialog.tsx b/src/renderer/TagDialog.tsx index 1132d489..59356a42 100644 --- a/src/renderer/TagDialog.tsx +++ b/src/renderer/TagDialog.tsx @@ -1,39 +1,31 @@ +import { RendererVideo } from 'main/types'; +import { MutableRefObject, useState } from 'react'; +import StateManager from './StateManager'; import { Dialog, - DialogTitle, + DialogClose, DialogContent, - DialogContentText, - TextField, - DialogActions, - Button, -} from '@mui/material'; -import { RendererVideo } from 'main/types'; -import { Dispatch, MutableRefObject, SetStateAction } from 'react'; -import StateManager from './StateManager'; + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from './components/Dialog/Dialog'; +import { Input } from './components/Input/Input'; +import { Button } from './components/Button/Button'; +import { Tooltip } from './components/Tooltip/Tooltip'; interface IProps { video: RendererVideo; - tagDialogOpen: boolean; - setTagDialogOpen: Dispatch>; stateManager: MutableRefObject; + children: React.ReactNode; + tooltipContent: string; } -const buttonSx = { - color: 'white', - ':hover': { - color: 'white', - borderColor: '#bb4420', - background: '#bb4420', - }, -}; - export default function TagDialog(props: IProps) { - const { video, tagDialogOpen, setTagDialogOpen, stateManager } = props; + const { video, stateManager, children, tooltipContent } = props; - const closeTagDialog = (event: React.MouseEvent) => { - event.stopPropagation(); - setTagDialogOpen(false); - }; + const [tag, setTag] = useState(video.tag); const saveTag = (newTag: string) => { stateManager.current.tag(video, newTag); @@ -49,54 +41,30 @@ export default function TagDialog(props: IProps) { const clearTag = (event: React.MouseEvent) => { event.stopPropagation(); saveTag(''); - setTagDialogOpen(false); + }; + + const onSave = (event: React.MouseEvent) => { + event.stopPropagation(); + saveTag(tag ?? ''); }; return ( - ) => { - event.preventDefault(); - event.stopPropagation(); - const formData = new FormData(event.currentTarget); - const formJson = Object.fromEntries((formData as any).entries()); - const { newTag } = formJson; - saveTag(newTag); - setTagDialogOpen(false); - }, - }} - > - Add a Description + + + {children} + - - This description is queryable in the search bar. - - + Add a Description + + This description is queryable in the search bar. + + + { @@ -104,19 +72,24 @@ export default function TagDialog(props: IProps) { // dialog is open and other similar things. e.stopPropagation(); }} + onChange={(e) => setTag(e.target.value)} /> + + + + + + + + + + + - - - - - ); } diff --git a/src/renderer/TestButton.tsx b/src/renderer/TestButton.tsx index 43189a5d..95164a53 100644 --- a/src/renderer/TestButton.tsx +++ b/src/renderer/TestButton.tsx @@ -1,8 +1,14 @@ -import { Box, Button, Popover, Tooltip, Typography } from '@mui/material'; -import ScienceIcon from '@mui/icons-material/Science'; import React from 'react'; import { VideoCategory } from 'types/VideoCategory'; import { RecStatus } from 'main/types'; +import { FlaskConical } from 'lucide-react'; +import { Button } from './components/Button/Button'; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from './components/HoverCard/HoverCard'; +import Separator from './components/Separator/Separator'; const ipc = window.electron.ipcRenderer; @@ -12,16 +18,6 @@ interface IProps { const TestButton: React.FC = (props: IProps) => { const { recorderStatus } = props; - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(anchorEl ? null : event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; const testCategories = [ VideoCategory.TwoVTwo, @@ -32,13 +28,15 @@ const TestButton: React.FC = (props: IProps) => { VideoCategory.MythicPlus, ]; - const runTest = (event: any, category: VideoCategory) => { + const runTest = ( + event: React.MouseEvent, + category: VideoCategory + ) => { // 'Click' will perform a normal test // 'Ctrl-Alt-Click' will initiate a test but won't finish it // and requires a force stop of the recording. const endTest = !(event.ctrlKey && event.altKey); ipc.sendMessage('test', [category, endTest]); - handleClose(); }; const getPopover = () => { @@ -46,101 +44,45 @@ const TestButton: React.FC = (props: IProps) => { if (ready) { return ( - - - - Select a category to test: - - {testCategories.map((category: VideoCategory) => { - return ( - - ); - })} - - +
+

Select a category to test

+ + {testCategories.map((category: VideoCategory) => { + return ( + + ); + })} +
); } return ( - - - - Unable to run a test right now. To run a test, World of Warcraft - must be running, your settings must be valid, and you must not - currently be in an activity. - - - +
+

+ Unable to run a test right now. To run a test, World of Warcraft must + be running, your settings must be valid, and you must not currently be + in an activity. +

+
); }; return ( - <> - - - - {getPopover()} - + + {getPopover()} + ); }; diff --git a/src/renderer/VideoBaseControls.tsx b/src/renderer/VideoBaseControls.tsx index b64b7249..e00fb475 100644 --- a/src/renderer/VideoBaseControls.tsx +++ b/src/renderer/VideoBaseControls.tsx @@ -1,23 +1,9 @@ -import { - Box, - FormControl, - FormControlLabel, - IconButton, - InputLabel, - MenuItem, - Select, - SelectChangeEvent, - ToggleButton, - ToggleButtonGroup, - Tooltip, - Typography, -} from '@mui/material'; -import React, { FC, useEffect, useRef, useState } from 'react'; +import { FC, useEffect, useRef, useState } from 'react'; import { Encoder, RecStatus } from 'main/types'; import { obsResolutions } from 'main/constants'; import { configSchema } from 'main/configSchema'; -import InfoIcon from '@mui/icons-material/Info'; import { ESupportedEncoders, QualityPresets } from 'main/obsEnums'; +import { Info } from 'lucide-react'; import { useSettings, setConfigValues } from './useSettings'; import { encoderFilter, @@ -25,44 +11,23 @@ import { mapEncoderToString, mapStringToEncoder, } from './rendererutils'; +import Label from './components/Label/Label'; +import { + ToggleGroup, + ToggleGroupItem, +} from './components/ToggleGroup/ToggleGroup'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from './components/Select/Select'; +import TextBanner from './components/TextBanner/TextBanner'; const ipc = window.electron.ipcRenderer; -const formControlStyle = { m: 1, width: '100%' }; - -const selectStyle = { - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, - '.MuiSvgIcon-root ': { - fill: 'white !important', - }, - '& .MuiInputBase-input.Mui-disabled': { - WebkitTextFillColor: 'darkgrey', - }, - '&.Mui-disabled .MuiOutlinedInput-notchedOutline': { - borderColor: 'darkgrey', - }, -}; - const outputResolutions = Object.keys(obsResolutions); const fpsOptions = [10, 20, 30, 60]; @@ -126,58 +91,11 @@ const VideoBaseControls: FC = (props: IProps) => { const isComponentDisabled = () => { const isRecording = recorderStatus === RecStatus.Recording; - const isOverrunning = recorderStatus === RecStatus.Overruning; + const isOverrunning = recorderStatus === RecStatus.Overrunning; return isRecording || isOverrunning; }; - const getMenuItem = (value: string) => { - return ( - - {value} - - ); - }; - - const getEncoderMenuItem = (enc: Encoder) => { - return ( - - {mapEncoderToString(enc)} - - ); - }; - - const getQualityMenuItem = (quality: QualityPresets) => { - return ( - - {quality} - - ); - }; - - const getToggleButton = (value: number) => { - return ( - - {value} - - ); - }; - - const setCanvasResolution = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setCanvasResolution = (value: string) => { const selectedhighRes = isHighRes(value); if (selectedhighRes) { @@ -204,30 +122,37 @@ const VideoBaseControls: FC = (props: IProps) => { } return ( - - Canvas Resolution +
+ - +
); }; - const setFPS = (_event: React.MouseEvent, fps: number) => { + const setFPS = (fps: string) => { if (fps === null) { return; } @@ -235,7 +160,7 @@ const VideoBaseControls: FC = (props: IProps) => { setConfig((prevState) => { return { ...prevState, - obsFPS: fps, + obsFPS: parseInt(fps, 10), }; }); }; @@ -246,30 +171,34 @@ const VideoBaseControls: FC = (props: IProps) => { } return ( - - {fpsOptions.map(getToggleButton)} - - } - label="FPS" - labelPlacement="top" - sx={{ color: 'white', pb: 3 }} - /> +
+ + + {fpsOptions.map((fpsOption) => ( + + {fpsOption} + + ))} + +
); }; - const setQuality = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setQuality = (value: string) => { setConfig((prevState) => { return { ...prevState, @@ -284,20 +213,9 @@ const VideoBaseControls: FC = (props: IProps) => { } return ( - - These settings can not be modified while a recording is active. - + + These settings cannot be modified while a recording is active. + ); }; @@ -311,31 +229,37 @@ const VideoBaseControls: FC = (props: IProps) => { return true; }; - const options = Object.values(QualityPresets) - .filter(cloudFilter) - .map(getQualityMenuItem); + const options = Object.values(QualityPresets).filter(cloudFilter); return ( - - Quality +
+ - +
); }; - const setEncoder = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setEncoder = (value: string) => { setConfig((prevState) => { return { ...prevState, @@ -350,70 +274,46 @@ const VideoBaseControls: FC = (props: IProps) => { } return ( - - Video Encoder +
+ - - ); - }; - - const getInfoIcon = () => { - if (isComponentDisabled()) { - return <>; - } - - const helptext = [ - ['FPS', configSchema.obsFPS.description].join('\n'), - ['Canvas Resolution', configSchema.obsOutputResolution.description].join( - '\n' - ), - ['Quality', configSchema.obsQuality.description].join('\n'), - ['Video Encoder', configSchema.obsRecEncoder.description].join('\n'), - ].join('\n\n'); - - return ( - {helptext}
}> - - - -
+ ); }; return ( - +
{getDisabledText()} - +
{getFPSToggle()} {getCanvasResolutionSelect()} {getQualitySelect()} {getEncoderSelect()} - {getInfoIcon()} - - +
+
); }; diff --git a/src/renderer/VideoButton.tsx b/src/renderer/VideoButton.tsx index bdeedcc4..ca2b5d2f 100644 --- a/src/renderer/VideoButton.tsx +++ b/src/renderer/VideoButton.tsx @@ -1,29 +1,24 @@ -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - IconButton, - Tooltip, - Typography, -} from '@mui/material'; -import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; -import AccessTimeIcon from '@mui/icons-material/AccessTime'; -import EventIcon from '@mui/icons-material/Event'; -import BookmarksIcon from '@mui/icons-material/Bookmarks'; -import DeleteIcon from '@mui/icons-material/Delete'; -import DeleteSweepIcon from '@mui/icons-material/DeleteSweep'; -import FolderIcon from '@mui/icons-material/Folder'; -import MessageIcon from '@mui/icons-material/Message'; +import { Box } from '@mui/material'; import React, { MutableRefObject, useEffect, useState } from 'react'; import { RendererVideo, AppState } from 'main/types'; import { VideoCategory } from 'types/VideoCategory'; -import DownloadIcon from '@mui/icons-material/Download'; -import UploadIcon from '@mui/icons-material/Upload'; -import LinkIcon from '@mui/icons-material/Link'; +import { + CalendarDays, + Clock, + CloudDownload, + CloudUpload, + FolderOpen, + Hourglass, + Link2, + PackageX, + Trash, +} from 'lucide-react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faMessage, faStar } from '@fortawesome/free-solid-svg-icons'; +import { + faStar as faStarOutline, + faMessage as faMessageOutline, +} from '@fortawesome/free-regular-svg-icons'; import { getResultColor, isArenaUtil, @@ -35,7 +30,6 @@ import { getVideoDate, stopPropagation, povNameSort, - countUniquePovs, } from './rendererutils'; import ArenaCompDisplay from './ArenaCompDisplay'; import DungeonCompDisplay from './DungeonCompDisplay'; @@ -45,11 +39,14 @@ import DungeonInfo from './DungeonInfo'; import ArenaInfo from './ArenaInfo'; import RaidCompAndResult from './RaidCompAndResult'; import TagDialog from './TagDialog'; -import ControlIcon from '../../assets/icon/ctrl-icon.png'; import PovSelection from './PovSelection'; import { useSettings } from './useSettings'; -import SnackBar from './SnackBar'; import StateManager from './StateManager'; +import { cn } from './components/utils'; +import { Tooltip } from './components/Tooltip/Tooltip'; +import { Button } from './components/Button/Button'; +import DeleteDialog from './DeleteDialog'; +import { useToast } from './components/Toast/useToast'; interface IProps { selected: boolean; @@ -60,29 +57,6 @@ interface IProps { persistentProgress: MutableRefObject; } -const dialogButtonSx = { - color: 'white', - ':hover': { - color: 'white', - borderColor: '#bb4420', - background: '#bb4420', - }, -}; - -const iconButtonSx = { - backgroundColor: 'dimgray', - border: '1px solid black', - boxShadow: 3, - borderRadius: '5px', - mx: '2px', - '& .MuiTouchRipple-root .MuiTouchRipple-child': { - borderRadius: '5px', - }, - ':hover': { - background: '#bb4420', - }, -}; - const ipc = window.electron.ipcRenderer; export default function VideoButton(props: IProps) { @@ -105,12 +79,9 @@ export default function VideoButton(props: IProps) { const videoDate = getVideoDate(video); const [ctrlDown, setCtrlDown] = useState(false); - const [tagDialogOpen, setTagDialogOpen] = useState(false); - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [localPovIndex, setLocalPovIndex] = useState(0); - const [linkSnackBarSuccessOpen, setLinkSnackBarSuccessOpen] = useState(false); - const [linkSnackBarFailedOpen, setLinkSnackBarFailedOpen] = useState(false); + const { toast } = useToast(); const povs = [video, ...video.multiPov].sort(povNameSort); const multiPov = povs.length > 1; @@ -132,20 +103,12 @@ export default function VideoButton(props: IProps) { povs.filter((v) => v.videoName === videoName).filter((v) => v.cloud) .length > 0; - const bookmarkOpacity = isProtected ? 1 : 0.2; - const tagOpacity = tag ? 1 : 0.2; let tagTooltip: string = tag || 'Add a tag'; if (tagTooltip.length > 50) { tagTooltip = `${tagTooltip.slice(0, 50)}...`; } - // We do some hokey maths here to decide the height of the button, because - // I've no idea how else to stop the image resizing the entire thing unless - // its parent has an absolute size, super annoying. - const uniquePovs = countUniquePovs(povs); - const buttonHeight = Math.max(25 + uniquePovs * 25, 130); - useEffect(() => { if (povs.length > localPovIndex) { return; @@ -159,7 +122,6 @@ export default function VideoButton(props: IProps) { */ const deleteVideo = (event: React.MouseEvent) => { event.stopPropagation(); - setDeleteDialogOpen(false); const src = cloud ? videoName : videoSource; window.electron.ipcRenderer.sendMessage('deleteVideo', [src, cloud]); @@ -186,8 +148,6 @@ export default function VideoButton(props: IProps) { */ const deleteAllPovs = (event: React.MouseEvent) => { event.stopPropagation(); - setDeleteDialogOpen(false); - povs.forEach((p) => { const src = p.cloud ? p.videoName : p.videoSource; @@ -229,10 +189,6 @@ export default function VideoButton(props: IProps) { }); }); - const openTagDialog = () => { - setTagDialogOpen(true); - }; - const protectVideo = (event: React.SyntheticEvent) => { event.stopPropagation(); stateManager.current.toggleProtect(pov); @@ -257,114 +213,33 @@ export default function VideoButton(props: IProps) { ]); }; - const deleteSingleClicked = (event: React.MouseEvent) => { + const onDeleteSingle = (event: React.MouseEvent) => { event.stopPropagation(); if (ctrlDown) { deleteVideo(event); - } else { - setDeleteDialogOpen(true); } }; - const deleteAllClicked = (event: React.MouseEvent) => { + const onDeleteAll = (event: React.MouseEvent) => { event.stopPropagation(); if (ctrlDown) { deleteAllPovs(event); - } else { - setDeleteDialogOpen(true); } }; - const getTagDialog = () => { - return ( - - ); - }; - - const getDeleteDialog = () => { - const getTitle = () => { - const msg = 'Are you sure?'; - return {msg}; - }; - - const getHotKeyText = () => { - return ( - - - Hold{' '} - Control Key{' '} - to skip this prompt. - - - ); - }; - - const getCancelButton = () => { - return ( - - ); - }; - - const getDeleteButton = () => { - return ( - - ); - }; - - return ( - - {getTitle()} - {getHotKeyText()} - - {getCancelButton()} - {getDeleteButton()} - - - ); - }; - const getOpenButton = () => { return ( - - + ); }; @@ -375,14 +250,15 @@ export default function VideoButton(props: IProps) { const getUploadButton = () => { return ( - - + ); }; @@ -393,151 +269,110 @@ export default function VideoButton(props: IProps) { const getDownloadButton = () => { return ( - - + ); }; - const getShareableLinkSnackBarSuccess = () => { - return ( - - ); - }; - - const getShareableLinkSnackBarFailed = () => { - return ( - - ); - }; - const getShareableLink = async (event: React.MouseEvent) => { event.stopPropagation(); event.preventDefault(); try { await ipc.invoke('getShareableLink', [videoName]); - setLinkSnackBarSuccessOpen(true); + toast({ + title: 'Shareable link generated and placed in clipboard', + description: 'This link will be valid for up to 30 days.', + duration: 5000, + }); } catch (error) { - setLinkSnackBarFailedOpen(true); + toast({ + title: 'Failed to generate link', + description: 'Please see logs for more details', + variant: 'destructive', + duration: 5000, + }); } }; const getShareLinkButton = () => { return ( - -
- {getShareableLinkSnackBarSuccess()} - {getShareableLinkSnackBarFailed()} - - - -
+ + ); }; const getDeleteSingleButton = () => { return ( - - deleteVideo(e)} tooltipContent="Delete"> + + ); }; const getDeleteAllButton = () => { return ( - - deleteAllPovs(e)} + tooltipContent="Delete all points of view" + > + + ); }; return ( - - {getTagDialog()} - {getDeleteDialog()} - - +
- +
+ video-thumbnail +
- +
- +
- - - - - +
+ +
+ + {formattedDuration} - - + +
- - - - + +
+ + {videoTime} - - + +
- - - - + +
+ + {videoDate} - - + +
-
+
- - - + + + + + + {cloud && getShareLinkButton()} @@ -728,10 +514,10 @@ export default function VideoButton(props: IProps) { getUploadButton()} {getDeleteSingleButton()} {multiPov && getDeleteAllButton()} - +
-
-
+ + ); } diff --git a/src/renderer/VideoFilter.ts b/src/renderer/VideoFilter.ts index fef021c3..6f0746b9 100644 --- a/src/renderer/VideoFilter.ts +++ b/src/renderer/VideoFilter.ts @@ -361,21 +361,21 @@ export default class VideoFilter { */ static getSuggestions(category: VideoCategory) { if (category === VideoCategory.MythicPlus) { - return 'Search suggestions: timed temple yesterday +18 priest bookmarked fortified'; + return 'Try: timed temple yesterday +18 priest bookmarked fortified'; } if (category === VideoCategory.Raids) { - return 'Search suggestions: kill today retail mythic destruction bookmarked'; + return 'Try: kill today retail mythic destruction bookmarked'; } if (category === VideoCategory.Battlegrounds) { - return 'Search suggestions: warsong gulch bookmarked'; + return 'Try: warsong gulch bookmarked'; } if (category === VideoCategory.SoloShuffle) { - return 'Search suggestions: dalaran 6-0 bookmarked'; + return 'Try: dalaran 6-0 bookmarked'; } - return 'Search suggestions: win enigma crucible arcane bookmarked'; + return 'Try: win enigma crucible arcane bookmarked'; } } diff --git a/src/renderer/VideoMarkerToggles.tsx b/src/renderer/VideoMarkerToggles.tsx index 48d5a25f..a0ebc8d5 100644 --- a/src/renderer/VideoMarkerToggles.tsx +++ b/src/renderer/VideoMarkerToggles.tsx @@ -1,4 +1,3 @@ -import { Box, Button } from '@mui/material'; import { VideoCategory } from 'types/VideoCategory'; import { useEffect, useRef } from 'react'; import { ConfigurationSchema } from 'main/configSchema'; @@ -8,16 +7,11 @@ import { convertNumToDeathMarkers, convertDeathMarkersToNum, } from './rendererutils'; - -const buttonSx = { - mx: 0.5, - height: '40px', - ':hover': { - color: 'white', - borderColor: '#bb4420', - background: '#bb4420', - }, -}; +import { + ToggleGroup, + ToggleGroupItem, +} from './components/ToggleGroup/ToggleGroup'; +import Label from './components/Label/Label'; interface IProps { config: ConfigurationSchema; @@ -44,140 +38,102 @@ const VideoMarkerToggles = (props: IProps) => { }); }, [config.deathMarkers, config.encounterMarkers, config.roundMarkers]); - const toggleDeaths = () => { - const options = Object.values(DeathMarkers); - const current = options.indexOf(deathMarkers); - const next = current < options.length - 1 ? current + 1 : 0; - + const setDeaths = (value: DeathMarkers) => { setConfig((prevState) => { return { ...prevState, - deathMarkers: convertDeathMarkersToNum(options[next]), + deathMarkers: convertDeathMarkersToNum(value), }; }); }; - const toggleEncounters = () => { + const setEncounterMarkers = (value: string) => { + const isTrue = value === 'true'; setConfig((prevState) => { return { ...prevState, - encounterMarkers: !config.encounterMarkers, + encounterMarkers: isTrue, }; }); }; - const toggleRound = () => { + const setRoundMarkers = (value: string) => { + const isTrue = value === 'true'; setConfig((prevState) => { return { ...prevState, - roundMarkers: !config.roundMarkers, + roundMarkers: isTrue, }; }); }; const renderDeathSelection = () => { - let color; - let backgroundColor; - - if (deathMarkers === DeathMarkers.ALL) { - color = 'rgba(255, 255, 255, 1)'; - backgroundColor = 'rgba(187, 68, 32, 0.75)'; - } else if (deathMarkers === DeathMarkers.OWN) { - color = 'rgba(255, 255, 255, 0.75)'; - backgroundColor = 'rgba(187, 68, 32, 0.4)'; - } else { - color = 'rgba(255, 255, 255, 0.5)'; - backgroundColor = 'rgba(0, 0, 0, 0)'; - } - return ( - +
+ + + + {DeathMarkers.ALL} + + + {DeathMarkers.OWN} + + + {DeathMarkers.NONE} + + +
); }; const renderEncounterSelection = () => { - const text = config.encounterMarkers ? 'ON' : 'OFF'; - - let color; - let backgroundColor; - - if (config.encounterMarkers) { - color = 'rgba(255, 255, 255, 1)'; - backgroundColor = 'rgba(163, 53, 238, 0.5)'; - } else { - color = 'rgba(255, 255, 255, 0.5)'; - backgroundColor = 'rgba(0, 0, 0, 0)'; - } - return ( - +
+ + + On + Off + +
); }; const renderRoundSelection = () => { - const text = config.roundMarkers ? 'ON' : 'OFF'; - - let color; - let background; - - if (config.roundMarkers) { - color = 'rgba(255, 255, 255, 1)'; - background = - 'linear-gradient(120deg, rgba(255, 0, 0, 0.5) 30%, rgba(21, 212, 0, 0.5) 70%)'; - } else { - color = 'rgba(255, 255, 255, 0.5)'; - background = 'rgba(0, 0, 0, 0)'; - } - return ( - +
+ + + On + Off + +
); }; return ( - +
{renderDeathSelection()} {category === VideoCategory.MythicPlus && renderEncounterSelection()} {category === VideoCategory.SoloShuffle && renderRoundSelection()} - +
); }; diff --git a/src/renderer/VideoPlayer.tsx b/src/renderer/VideoPlayer.tsx index 70e93860..dd509ebc 100644 --- a/src/renderer/VideoPlayer.tsx +++ b/src/renderer/VideoPlayer.tsx @@ -12,7 +12,7 @@ import { useRef, useState, } from 'react'; -import { Box, Button, Slider, Tooltip, Typography } from '@mui/material'; +import { Box, Slider, Typography } from '@mui/material'; import { Resizable } from 're-resizable'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PauseIcon from '@mui/icons-material/Pause'; @@ -40,6 +40,8 @@ import { isSoloShuffleUtil, secToMmSs, } from './rendererutils'; +import { Button } from './components/Button/Button'; +import { Tooltip } from './components/Tooltip/Tooltip'; interface IProps { video: RendererVideo; @@ -56,6 +58,12 @@ const progressInterval = 100; const sliderSx = { '& .MuiSlider-thumb': { color: 'white', + width: '16px', + height: '16px', + '&:hover': { + color: '#bb4220', + boxShadow: 'none', + }, }, '& .MuiSlider-track': { color: '#bb4220', @@ -111,7 +119,7 @@ export const VideoPlayer = (props: IProps) => { return { value: marker.time, label: ( - + { '& .MuiSlider-valueLabel': { fontSize: '0.75rem', }, + '&:hover': { + backgroundColor: '#bb4220', + boxShadow: 'none', + }, }, "&[data-index='1']": { - width: '5px', - height: '5px', + width: '10px', + height: '10px', zIndex: 1, backgroundColor: 'white', '& .MuiSlider-valueLabel': { @@ -410,6 +422,10 @@ export const VideoPlayer = (props: IProps) => { rotate: '180deg', }, }, + '&:hover': { + backgroundColor: '#bb4220', + boxShadow: 'none', + }, }, "&[data-index='2']": { backgroundColor: 'white', @@ -419,6 +435,10 @@ export const VideoPlayer = (props: IProps) => { '& .MuiSlider-valueLabel': { fontSize: '0.75rem', }, + '&:hover': { + backgroundColor: '#bb4220', + boxShadow: 'none', + }, }, }, }} @@ -498,9 +518,11 @@ export const VideoPlayer = (props: IProps) => { */ const renderPlayPause = () => { return ( - ); }; @@ -517,18 +539,18 @@ export const VideoPlayer = (props: IProps) => { */ const getAppropriateVolumeIcon = () => { if (muted) { - return ; + return ; } if (volume === 0) { - return ; + return ; } if (volume < 0.5) { - return ; + return ; } - return ; + return ; }; /** @@ -536,7 +558,7 @@ export const VideoPlayer = (props: IProps) => { */ const renderVolumeButton = () => { return ( - ); @@ -550,17 +572,11 @@ export const VideoPlayer = (props: IProps) => { const max = duration; return ( - - +
+ {secToMmSs(current)} / {secToMmSs(max)} - - + +
); }; @@ -571,8 +587,8 @@ export const VideoPlayer = (props: IProps) => { const playbackRateText = `${playbackRate}x`; return ( - - @@ -587,14 +603,15 @@ export const VideoPlayer = (props: IProps) => { const tooltip = cloud ? 'You can only clip locally saved videos' : 'Clip'; return ( - +
@@ -618,8 +635,8 @@ export const VideoPlayer = (props: IProps) => { */ const renderClipFinishedButton = () => { return ( - - @@ -628,8 +645,8 @@ export const VideoPlayer = (props: IProps) => { const renderClipCancelButton = () => { return ( - - @@ -641,8 +658,8 @@ export const VideoPlayer = (props: IProps) => { */ const renderFullscreenButton = () => { return ( - - @@ -665,7 +682,7 @@ export const VideoPlayer = (props: IProps) => { const renderVolumeSlider = () => { return ( { */ const renderControls = () => { return ( - +
{renderPlayPause()} {renderVolumeButton()} {renderVolumeSlider()} @@ -701,7 +707,7 @@ export const VideoPlayer = (props: IProps) => { {!clipMode && renderFullscreenButton()} {clipMode && renderClipFinishedButton()} {clipMode && renderClipCancelButton()} - +
); }; diff --git a/src/renderer/VideoSourceControls.tsx b/src/renderer/VideoSourceControls.tsx index dec18e48..58f90c2f 100644 --- a/src/renderer/VideoSourceControls.tsx +++ b/src/renderer/VideoSourceControls.tsx @@ -1,75 +1,25 @@ -import { - Box, - FormControlLabel, - Switch, - ToggleButton, - ToggleButtonGroup, - Tooltip, - FormControl, - IconButton, - InputLabel, - Select, - MenuItem, - SelectChangeEvent, -} from '@mui/material'; import React, { useState } from 'react'; import { OurDisplayType, WindowCaptureChoice } from 'main/types'; import { configSchema } from 'main/configSchema'; -import InfoIcon from '@mui/icons-material/Info'; +import { Info } from 'lucide-react'; import { useSettings, setConfigValues } from './useSettings'; +import Label from './components/Label/Label'; +import { + ToggleGroup, + ToggleGroupItem, +} from './components/ToggleGroup/ToggleGroup'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from './components/Select/Select'; +import Switch from './components/Switch/Switch'; +import { Tooltip } from './components/Tooltip/Tooltip'; const ipc = window.electron.ipcRenderer; -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; - -const formControlStyle = { m: 1, width: '100%' }; - -const selectStyle = { - color: 'white', - '& .MuiOutlinedInput-notchedOutline': { - borderColor: 'white', - }, - '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#bb4220', - }, - '&.Mui-focused': { - borderColor: '#bb4220', - color: '#bb4220', - }, - '&:hover': { - '&& fieldset': { - borderColor: '#bb4220', - }, - }, - '& .MuiOutlinedInput-root': { - '&.Mui-focused fieldset': { - borderColor: '#bb4220', - }, - }, - '.MuiSvgIcon-root ': { - fill: 'white !important', - }, - '& .MuiInputBase-input.Mui-disabled': { - WebkitTextFillColor: 'darkgrey', - }, - '&.Mui-disabled .MuiOutlinedInput-notchedOutline': { - borderColor: 'darkgrey', - }, -}; - const VideoSourceControls: React.FC = () => { const [config, setConfig] = useSettings(); const [displays, setDisplays] = useState([]); @@ -113,10 +63,7 @@ const VideoSourceControls: React.FC = () => { config.obsWindowName, ]); - const setOBSCaptureMode = ( - _event: React.MouseEvent, - mode: string - ) => { + const setOBSCaptureMode = (mode: string) => { if (mode === null) { return; } @@ -129,11 +76,7 @@ const VideoSourceControls: React.FC = () => { }); }; - const setOBSWindowName = (event: SelectChangeEvent) => { - const { - target: { value }, - } = event; - + const setOBSWindowName = (value: string) => { setConfig((prevState) => { return { ...prevState, @@ -142,10 +85,7 @@ const VideoSourceControls: React.FC = () => { }); }; - const setMonitor = ( - _event: React.MouseEvent, - display: number - ) => { + const setMonitor = (display: string) => { if (display === null) { return; } @@ -153,54 +93,44 @@ const VideoSourceControls: React.FC = () => { setConfig((prevState) => { return { ...prevState, - monitorIndex: display, + monitorIndex: parseInt(display, 10), }; }); }; - const setCaptureCursor = (event: React.ChangeEvent) => { + const setCaptureCursor = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - captureCursor: event.target.checked, + captureCursor: checked, }; }); }; - const getToggleButton = ( - value: string | number, - display: string | number - ) => { - return ( - - {display} - - ); - }; - const getCaptureModeToggle = () => { return ( - - {getToggleButton('window_capture', 'window')} - {getToggleButton('game_capture', 'game')} - {getToggleButton('monitor_capture', 'monitor')} - +
+ + + Window + Game + Monitor + +
); }; @@ -210,16 +140,27 @@ const VideoSourceControls: React.FC = () => { } return ( - - {displays.map((display: OurDisplayType) => - getToggleButton(display.index, display.index + 1) - )} - +
+ + + {displays.map((display: OurDisplayType) => ( + + {display.index + 1} + + ))} + +
); }; @@ -228,14 +169,6 @@ const VideoSourceControls: React.FC = () => { return <>; } - const mapWindowToMenuItem = (item: WindowCaptureChoice) => { - return ( - - {item.name} - - ); - }; - // Always include the base game modes even if they aren't currently running. const classicOpen = windows.find( (window) => window.name === '[WowClassic.exe]: World of Warcraft' @@ -260,70 +193,61 @@ const VideoSourceControls: React.FC = () => { } return ( - - Window - + + + + + {windows.map((window) => ( + + {window.name} + + ))} + - + ); }; const getCursorToggle = () => { return ( - + +
- } - label="Capture Cursor" - labelPlacement="top" - sx={{ - color: 'white', - }} - /> - ); - }; - - const getInfoIcon = () => { - const helptext = [ - ['Capture Mode', configSchema.obsCaptureMode.description].join('\n'), - ['Monitor', configSchema.monitorIndex.description].join('\n'), - ['Capture Cursor', configSchema.captureCursor.description].join('\n'), - ].join('\n\n'); - - return ( - {helptext}
}> - - - -
+ + ); }; return ( - +
{getCaptureModeToggle()} {getMonitorToggle()} {getWindowSelect()} {getCursorToggle()} - {getInfoIcon()} - +
); }; diff --git a/src/renderer/WindowsSettings.tsx b/src/renderer/WindowsSettings.tsx index e86dd712..623c00d8 100644 --- a/src/renderer/WindowsSettings.tsx +++ b/src/renderer/WindowsSettings.tsx @@ -1,23 +1,8 @@ import * as React from 'react'; -import Box from '@mui/material/Box'; -import { FormControlLabel, Switch } from '@mui/material'; import { ConfigurationSchema } from 'main/configSchema'; import { setConfigValues, useSettings } from './useSettings'; - -const switchStyle = { - '& .MuiSwitch-switchBase': { - '&.Mui-checked': { - color: '#fff', - '+.MuiSwitch-track': { - backgroundColor: '#bb4220', - opacity: 1.0, - }, - }, - '&.Mui-disabled + .MuiSwitch-track': { - opacity: 0.5, - }, - }, -}; +import Switch from './components/Switch/Switch'; +import Label from './components/Label/Label'; const WindowsSettings = () => { const [config, setConfig] = useSettings(); @@ -45,80 +30,73 @@ const WindowsSettings = () => { const getSwitch = ( preference: keyof ConfigurationSchema, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => ( ); const getSwitchForm = ( preference: keyof ConfigurationSchema, label: string, - changeFn: (event: React.ChangeEvent) => void + changeFn: (checked: boolean) => void ) => { return ( - +
+ +
+ {getSwitch(preference, changeFn)} +
+
); }; - const setRunOnStartup = (event: React.ChangeEvent) => { + const setRunOnStartup = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - startUp: event.target.checked, + startUp: checked, }; }); }; - const setStartMinimized = (event: React.ChangeEvent) => { + const setStartMinimized = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - startMinimized: event.target.checked, + startMinimized: checked, }; }); }; - const setMinimizeOnQuit = (event: React.ChangeEvent) => { + const setMinimizeOnQuit = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - minimizeOnQuit: event.target.checked, + minimizeOnQuit: checked, }; }); }; - const setMinimizeToTray = (event: React.ChangeEvent) => { + const setMinimizeToTray = (checked: boolean) => { setConfig((prevState) => { return { ...prevState, - minimizeToTray: event.target.checked, + minimizeToTray: checked, }; }); }; return ( - +
{getSwitchForm('startUp', 'Run on Startup', setRunOnStartup)} {getSwitchForm('startMinimized', 'Start Minimized', setStartMinimized)} {getSwitchForm('minimizeOnQuit', 'Minimize on Quit', setMinimizeOnQuit)} {getSwitchForm('minimizeToTray', 'Minimize to Tray', setMinimizeToTray)} - +
); }; diff --git a/src/renderer/components/Badge/Badge.tsx b/src/renderer/components/Badge/Badge.tsx new file mode 100644 index 00000000..657365fa --- /dev/null +++ b/src/renderer/components/Badge/Badge.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; + +const badgeVariants = cva( + 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 [text-shadow:_none]', + { + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', + secondary: + 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', + destructive: + 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', + outline: 'text-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ); +} + +export { Badge, badgeVariants }; diff --git a/src/renderer/components/Button/Button.tsx b/src/renderer/components/Button/Button.tsx new file mode 100644 index 00000000..1d279161 --- /dev/null +++ b/src/renderer/components/Button/Button.tsx @@ -0,0 +1,59 @@ +/* eslint-disable react/require-default-props */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-background-higher focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-card bg-transparent hover:bg-card hover:text-card-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'text-card-foreground hover:bg-card hover:text-card-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + xs: 'h-8 rounded-md px-2 py-1 text-xs', + sm: 'h-9 rounded-md px-3 text-xs', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + 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 { Button, buttonVariants }; diff --git a/src/renderer/components/Command/Command.tsx b/src/renderer/components/Command/Command.tsx new file mode 100644 index 00000000..30cbd1b6 --- /dev/null +++ b/src/renderer/components/Command/Command.tsx @@ -0,0 +1,154 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import { type DialogProps } from '@radix-ui/react-dialog'; +import { Command as CommandPrimitive } from 'cmdk'; +import { Search } from 'lucide-react'; + +import { cn } from '../utils'; +import { Dialog, DialogContent } from '../Dialog/Dialog'; + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Command.displayName = CommandPrimitive.displayName; + +type CommandDialogProps = DialogProps; + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +CommandShortcut.displayName = 'CommandShortcut'; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/src/renderer/components/Dialog/Dialog.tsx b/src/renderer/components/Dialog/Dialog.tsx new file mode 100644 index 00000000..5d4f58c4 --- /dev/null +++ b/src/renderer/components/Dialog/Dialog.tsx @@ -0,0 +1,124 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { X } from 'lucide-react'; + +import { cn } from '../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, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/src/renderer/components/HoverCard/HoverCard.tsx b/src/renderer/components/HoverCard/HoverCard.tsx new file mode 100644 index 00000000..8feee553 --- /dev/null +++ b/src/renderer/components/HoverCard/HoverCard.tsx @@ -0,0 +1,31 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as HoverCardPrimitive from '@radix-ui/react-hover-card'; + +import { cn } from '../utils'; + +const HoverCard = HoverCardPrimitive.Root; + +const HoverCardTrigger = HoverCardPrimitive.Trigger; + +const HoverCardContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( + +)); +HoverCardContent.displayName = HoverCardPrimitive.Content.displayName; + +export { HoverCard, HoverCardTrigger, HoverCardContent }; diff --git a/src/renderer/components/Input/Input.tsx b/src/renderer/components/Input/Input.tsx new file mode 100644 index 00000000..2ea628f6 --- /dev/null +++ b/src/renderer/components/Input/Input.tsx @@ -0,0 +1,28 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; + +import { cn } from '../utils'; + +export type InputProps = React.InputHTMLAttributes; + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + } +); +Input.displayName = 'Input'; + +export { Input }; diff --git a/src/renderer/components/Label/Label.tsx b/src/renderer/components/Label/Label.tsx new file mode 100644 index 00000000..a1a35557 --- /dev/null +++ b/src/renderer/components/Label/Label.tsx @@ -0,0 +1,25 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as LabelPrimitive from '@radix-ui/react-label'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; + +const labelVariants = cva( + 'text-xs font-bold leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 text-foreground-lighter' +); + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)); +Label.displayName = LabelPrimitive.Root.displayName; + +export default Label; diff --git a/src/renderer/components/Menu/Item.tsx b/src/renderer/components/Menu/Item.tsx new file mode 100644 index 00000000..4883b658 --- /dev/null +++ b/src/renderer/components/Menu/Item.tsx @@ -0,0 +1,60 @@ +/* eslint-disable react/require-default-props */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/interactive-supports-focus */ +import { PropsWithChildren, ReactNode } from 'react'; +import { useMenuContext } from './Menu'; +import { cn } from '../utils'; +import { Badge } from '../Badge/Badge'; + +type MenuItemProps = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: any; + className?: string; +}; + +const Root = ({ + value, + className, + children, +}: PropsWithChildren) => { + const { currentValue, onValueChange } = useMenuContext(); + return ( +
onValueChange(value)} + role="button" + > + {children} +
+ ); +}; + +const Icon = ({ children }: { children: ReactNode }) => { + return
{children}
; +}; + +type MenuBadgeProps = { + value?: number; +}; + +const MenuBadge = ({ value }: MenuBadgeProps) => { + return value ? ( + + {value <= 99 ? value : '99+'} + + ) : null; +}; + +const Item = Object.assign(Root, { Icon, Badge: MenuBadge }); + +export default Item; diff --git a/src/renderer/components/Menu/Menu.tsx b/src/renderer/components/Menu/Menu.tsx new file mode 100644 index 00000000..fb80bb5e --- /dev/null +++ b/src/renderer/components/Menu/Menu.tsx @@ -0,0 +1,74 @@ +/* eslint-disable react/require-default-props */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ +// Disabled the above because the only other option here is to make this context +// with generics, which is just an unnecessary PITA. + +import React, { PropsWithChildren, ReactNode } from 'react'; +import { cn } from '../utils'; + +type MenuProps = { + initialValue?: any; + onChange: (value: any) => void; + className?: string; +}; + +interface MenuContextType { + currentValue?: any; + onValueChange: (newValue: string) => void; +} + +const MenuContext = React.createContext({ + onValueChange: () => {}, +}); + +export const useMenuContext = (): MenuContextType => { + const menuContext = React.useContext(MenuContext); + + if (!menuContext) { + throw new Error( + 'useMenuContext has to be used within a MenuContextProvider' + ); + } + + return menuContext; +}; + +export const Menu = ({ + initialValue, + children, + onChange, + className, +}: PropsWithChildren) => { + const [currentValue, setCurrentValue] = React.useState(initialValue); + + const onValueChange = (newValue: string) => { + setCurrentValue(newValue); + onChange(newValue); + }; + + // This is a bit of a janky way to handle it I guess, but it accounts for + // the fact that the two sections of content and settings are two different menus + // so when one gets selected, the other needs to be cleared + React.useEffect(() => { + if (!initialValue) setCurrentValue(undefined); + }, [initialValue]); + + return ( +
+ + {children} + +
+ ); +}; + +export const MenuLabel = ({ children }: { children: ReactNode }) => { + return ( + + {children} + + ); +}; + +export default Menu; diff --git a/src/renderer/components/Menu/index.tsx b/src/renderer/components/Menu/index.tsx new file mode 100644 index 00000000..046541e3 --- /dev/null +++ b/src/renderer/components/Menu/index.tsx @@ -0,0 +1,6 @@ +import { Menu as Root, MenuLabel } from './Menu'; +import Item from './Item'; + +const Menu = Object.assign(Root, { Label: MenuLabel, Item }); + +export default Menu; diff --git a/src/renderer/components/MultiSelect/MultiSelect.tsx b/src/renderer/components/MultiSelect/MultiSelect.tsx new file mode 100644 index 00000000..98643aeb --- /dev/null +++ b/src/renderer/components/MultiSelect/MultiSelect.tsx @@ -0,0 +1,209 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable import/prefer-default-export */ +/* eslint-disable react/require-default-props */ +import * as React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { CheckIcon, XCircle, ChevronDown } from 'lucide-react'; + +import { cn } from '../utils'; +import { Button } from '../Button/Button'; +import { Badge } from '../Badge/Badge'; +import { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandItem, + CommandList, +} from '../Command/Command'; + +const multiSelectVariants = cva( + 'm-1 transition px-3 py-2 text-[11px] overflow-hidden text-ellipsis whitespace-nowrap inline-block', + { + variants: { + variant: { + default: 'text-card-foreground bg-video hover:bg-video/80', + secondary: + 'border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80', + destructive: + 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', + inverted: 'inverted', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +); + +interface MultiSelectProps + extends React.ButtonHTMLAttributes, + VariantProps { + options: { + label: string; + value: string; + icon?: React.ComponentType<{ className?: string }>; + }[]; + onValueChange: (value: string[]) => void; + defaultValue: string[]; + placeholder?: string; + animation?: number; + maxCount?: number; + modalPopover?: boolean; + asChild?: boolean; + className?: string; +} + +export const MultiSelect = React.forwardRef< + HTMLButtonElement, + MultiSelectProps +>( + ( + { + options, + onValueChange, + variant, + defaultValue = [], + placeholder = 'Select options', + animation = 0, + maxCount = 3, + modalPopover = false, + className, + ...props + }, + ref + ) => { + const [selectedValues, setSelectedValues] = + React.useState(defaultValue); + const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); + const [isAnimating] = React.useState(false); + + React.useEffect(() => { + setSelectedValues(defaultValue); + }, [defaultValue]); + + const toggleOption = (value: string) => { + const newSelectedValues = selectedValues.includes(value) + ? selectedValues.filter((v) => v !== value) + : [...selectedValues, value]; + setSelectedValues(newSelectedValues); + onValueChange(newSelectedValues); + }; + + const handleTogglePopover = () => { + setIsPopoverOpen((prev) => !prev); + }; + + return ( + + + + + setIsPopoverOpen(false)} + > + + + None found + + {options.map((option) => { + const isSelected = selectedValues.includes(option.value); + return ( + toggleOption(option.value)} + className={cn( + 'cursor-pointer text-card-foreground py-2 pl-4 text-sm', + 'hover:bg-primary hover:text-primary-foreground' + )} + > +
+ +
+ {option.icon && ( + + )} + {option.label} +
+ ); + })} +
+
+
+
+
+ ); + } +); + +MultiSelect.displayName = 'MultiSelect'; diff --git a/src/renderer/components/Popover/Popover.tsx b/src/renderer/components/Popover/Popover.tsx new file mode 100644 index 00000000..be3ed462 --- /dev/null +++ b/src/renderer/components/Popover/Popover.tsx @@ -0,0 +1,30 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as PopoverPrimitive from '@radix-ui/react-popover'; + +import { cn } from '../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/src/renderer/components/Progress/Progress.tsx b/src/renderer/components/Progress/Progress.tsx new file mode 100644 index 00000000..0363da14 --- /dev/null +++ b/src/renderer/components/Progress/Progress.tsx @@ -0,0 +1,27 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as ProgressPrimitive from '@radix-ui/react-progress'; + +import { cn } from '../utils'; + +const Progress = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, value, ...props }, ref) => ( + + + +)); +Progress.displayName = ProgressPrimitive.Root.displayName; + +export default Progress; diff --git a/src/renderer/components/ScrollArea/ScrollArea.tsx b/src/renderer/components/ScrollArea/ScrollArea.tsx new file mode 100644 index 00000000..ad27b9cf --- /dev/null +++ b/src/renderer/components/ScrollArea/ScrollArea.tsx @@ -0,0 +1,187 @@ +/* eslint-disable no-inner-declarations */ +/* eslint-disable react/require-default-props */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; + +import { ChevronDown, ChevronUp } from 'lucide-react'; +import { cn } from '../utils'; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +type ScrollIndicatorProps = { + viewport: HTMLDivElement | undefined; + scrollabilityIndicatorClasses: string; +}; + +const ScrollabilityIndicator = ({ + direction, + scrollabilityIndicatorClasses, +}: { + direction: 'up' | 'down'; + scrollabilityIndicatorClasses: string; +}) => ( +
+
+ {direction === 'down' ? : } +
+); + +const ScrollUpIndicator = ({ + viewport, + scrollabilityIndicatorClasses, +}: ScrollIndicatorProps) => { + const [canScrollUp, setCanScrollUp] = React.useState(false); + + React.useLayoutEffect(() => { + if (viewport) { + function handleScroll() { + // This is mostly to appease TS linter .. + if (viewport) { + const canScroll = viewport.scrollTop > 0; + setCanScrollUp(canScroll); + } + } + handleScroll(); + viewport.addEventListener('scroll', handleScroll); + + return () => viewport?.removeEventListener('scroll', handleScroll); + } + + return () => {}; + }); + + return canScrollUp ? ( + + ) : null; +}; + +const ScrollDownIndicator = ({ + viewport, + scrollabilityIndicatorClasses, +}: ScrollIndicatorProps) => { + const [canScrollDown, setCanScrollDown] = React.useState(false); + + React.useLayoutEffect(() => { + if (viewport) { + function handleScroll() { + // This is mostly to appease TS linter .. + if (viewport) { + const maxScroll = viewport.scrollHeight - viewport.clientHeight; + const canScroll = Math.ceil(viewport.scrollTop) < maxScroll; + setCanScrollDown(canScroll); + } + } + handleScroll(); + viewport.addEventListener('scroll', handleScroll); + + return () => viewport?.removeEventListener('scroll', handleScroll); + } + return () => {}; + }, [viewport]); + + return canScrollDown ? ( + + ) : null; +}; + +type ScrollAreaProps = { + withScrollIndicators?: boolean; + scrollabilityIndicatorClasses?: string; +}; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + ScrollAreaProps +>( + ( + { + className, + children, + withScrollIndicators = true, + scrollabilityIndicatorClasses = '', + ...props + }, + ref + ) => { + const viewportRef = React.useRef(); + const [viewport, setViewport] = React.useState(); + + React.useLayoutEffect(() => { + if (viewportRef.current) { + setViewport(viewportRef.current); + } + }, [viewportRef]); + return ( + + + {withScrollIndicators && ( + + )} + {children} + {withScrollIndicators && ( + + )} + + + + + ); + } +); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/src/renderer/components/Select/Select.tsx b/src/renderer/components/Select/Select.tsx new file mode 100644 index 00000000..c606e5d7 --- /dev/null +++ b/src/renderer/components/Select/Select.tsx @@ -0,0 +1,163 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as SelectPrimitive from '@radix-ui/react-select'; +import { ChevronDown, ChevronUp, Dot } from 'lucide-react'; + +import { cn } from '../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/src/renderer/components/Separator/Separator.tsx b/src/renderer/components/Separator/Separator.tsx new file mode 100644 index 00000000..266adfd5 --- /dev/null +++ b/src/renderer/components/Separator/Separator.tsx @@ -0,0 +1,30 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as SeparatorPrimitive from '@radix-ui/react-separator'; + +import { cn } from '../utils'; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = 'horizontal', decorative = true, ...props }, + ref + ) => ( + + ) +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export default Separator; diff --git a/src/renderer/components/Slider/Slider.tsx b/src/renderer/components/Slider/Slider.tsx new file mode 100644 index 00000000..6f498597 --- /dev/null +++ b/src/renderer/components/Slider/Slider.tsx @@ -0,0 +1,54 @@ +/* eslint-disable react/require-default-props */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as SliderPrimitive from '@radix-ui/react-slider'; + +import { cn } from '../utils'; +import { Tooltip } from '../Tooltip/Tooltip'; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + withTooltip?: boolean; + } +>(({ className, value, withTooltip = true, ...props }, ref) => ( + + + + + {withTooltip ? ( + e.preventDefault()} + onPointerDownOutside={(e) => e.preventDefault()} + > + + + ) : ( + + )} + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export default Slider; diff --git a/src/renderer/components/StatusLight/StatusLight.tsx b/src/renderer/components/StatusLight/StatusLight.tsx new file mode 100644 index 00000000..ed9aae3a --- /dev/null +++ b/src/renderer/components/StatusLight/StatusLight.tsx @@ -0,0 +1,58 @@ +/* eslint-disable react/require-default-props */ +import React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; + +const statusLightForegroundVariants = cva('rounded-full border-[3px]', { + variants: { + variant: { + ready: + 'bg-success border-success-border shadow-[0px_0px_4px_2px_rgba(45,216,127,0.5)]', + recording: + 'bg-success border-success-border shadow-[0px_0px_4px_2px_rgba(45,216,127,0.5)] animate-pulse', + invalid: + 'bg-warning border-warning-border shadow-[0px_0px_4px_2px_rgba(234,179,8,0.5)]', + error: + 'bg-error border-error-border shadow-[0px_0px_4px_2px_rgba(153,27,27,0.66)]', + waiting: 'bg-zinc-400 border-zinc-500', + overrunning: + 'bg-blue-accent border-blue-accent-border shadow-[0px_0px_4px_2px_rgba(2,132,199,0.66)]', + }, + }, +}); + +export interface StatusLightProps + extends React.HTMLAttributes, + VariantProps { + variant: + | 'waiting' + | 'recording' + | 'invalid' + | 'error' + | 'ready' + | 'overrunning'; + wrapperClasses?: string; + foregroundClasses?: string; +} + +const StatusLight = ({ + variant, + wrapperClasses, + foregroundClasses, +}: StatusLightProps) => { + return ( +
+
+
+ ); +}; + +export default StatusLight; diff --git a/src/renderer/components/Switch/Switch.tsx b/src/renderer/components/Switch/Switch.tsx new file mode 100644 index 00000000..5a57fe8b --- /dev/null +++ b/src/renderer/components/Switch/Switch.tsx @@ -0,0 +1,31 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as SwitchPrimitives from '@radix-ui/react-switch'; + +import { cn } from '../utils'; + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +Switch.displayName = SwitchPrimitives.Root.displayName; + +export default Switch; diff --git a/src/renderer/components/Tabs/Tabs.tsx b/src/renderer/components/Tabs/Tabs.tsx new file mode 100644 index 00000000..05747f5d --- /dev/null +++ b/src/renderer/components/Tabs/Tabs.tsx @@ -0,0 +1,57 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as TabsPrimitive from '@radix-ui/react-tabs'; + +import { cn } from '../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/src/renderer/components/TextBanner/TextBanner.tsx b/src/renderer/components/TextBanner/TextBanner.tsx new file mode 100644 index 00000000..e7fcb298 --- /dev/null +++ b/src/renderer/components/TextBanner/TextBanner.tsx @@ -0,0 +1,40 @@ +/* eslint-disable react/require-default-props */ +import { ShieldAlert } from 'lucide-react'; +import { PropsWithChildren } from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { cn } from '../utils'; + +// Only default variant for now, will implement/style more as needed +type TextBannerProps = { + className?: string; +}; + +const textBannerVariants = cva( + 'bg-popover border border-popover w-full text-card-foreground text-sm px-4 py-2 rounded-md flex items-center gap-x-4', + { + variants: { + variant: { + default: '', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +); + +const TextBanner = ({ + children, + variant, + className = '', +}: PropsWithChildren & + VariantProps) => { + return ( +
+ + {children} +
+ ); +}; + +export default TextBanner; diff --git a/src/renderer/components/Toast/Toast.tsx b/src/renderer/components/Toast/Toast.tsx new file mode 100644 index 00000000..d9c6643a --- /dev/null +++ b/src/renderer/components/Toast/Toast.tsx @@ -0,0 +1,134 @@ +/* eslint-disable react/prop-types */ + +import * as React from 'react'; +import * as ToastPrimitives from '@radix-ui/react-toast'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { X } from 'lucide-react'; + +import { cn } from '../utils'; + +const ToastProvider = ToastPrimitives.Provider; + +const ToastViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; + +const toastVariants = cva( + 'mt-4 group pointer-events-auto relative flex w-full flex-col gap-y-4 items-start justify-between overflow-hidden rounded-md border p-6 pr-8 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-popover text-popover-foreground border-popover-inset border-l-8 border-r-8 border-l-primary border-r-primary', + 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/src/renderer/components/Toast/Toaster.tsx b/src/renderer/components/Toast/Toaster.tsx new file mode 100644 index 00000000..9fdb9067 --- /dev/null +++ b/src/renderer/components/Toast/Toaster.tsx @@ -0,0 +1,35 @@ +import { + Toast, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, +} from './Toast'; +import { useToast } from './useToast'; + +function Toaster() { + const { toasts } = useToast(); + + return ( + + {toasts.map(({ id, title, description, action, ...props }) => { + return ( + +
+ {title && {title}} + {description && ( + {description} + )} +
+ {action} + +
+ ); + })} + +
+ ); +} + +export default Toaster; diff --git a/src/renderer/components/Toast/useToast.ts b/src/renderer/components/Toast/useToast.ts new file mode 100644 index 00000000..edec034d --- /dev/null +++ b/src/renderer/components/Toast/useToast.ts @@ -0,0 +1,191 @@ +import * as React from 'react'; + +import type { ToastActionElement, ToastProps } from './Toast'; + +const TOAST_LIMIT = 3; +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_SAFE_INTEGER; + 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 listeners: Array<(state: State) => void> = []; + +let memoryState: State = { toasts: [] }; + +function dispatch(action: Action) { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + memoryState = reducer(memoryState, action); + listeners.forEach((listener) => { + listener(memoryState); + }); +} + +const addToRemoveQueue = (toastId: string) => { + if (toastTimeouts.has(toastId)) { + return; + } + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId); + dispatch({ + type: 'REMOVE_TOAST', + toastId, + }); + }, TOAST_REMOVE_DELAY); + + toastTimeouts.set(toastId, timeout); +}; + +export const reducer = (state: State, action: Action): State => { + // eslint-disable-next-line default-case + switch (action.type) { + case 'ADD_TOAST': + default: + 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((t) => { + addToRemoveQueue(t.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), + }; + } +}; + +type Toast = Omit; + +function toast({ ...props }: Toast) { + const id = genId(); + + const update = (toastProps: ToasterToast) => + dispatch({ + type: 'UPDATE_TOAST', + toast: { ...toastProps, 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, + 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/src/renderer/components/Toggle/Toggle.tsx b/src/renderer/components/Toggle/Toggle.tsx new file mode 100644 index 00000000..e955204d --- /dev/null +++ b/src/renderer/components/Toggle/Toggle.tsx @@ -0,0 +1,45 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as TogglePrimitive from '@radix-ui/react-toggle'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; + +const toggleVariants = cva( + 'inline-flex items-center justify-center rounded-md text-xs font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-background-higher focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground flex-grow', + { + variants: { + variant: { + default: 'bg-transparent', + outline: + 'bg-transparent hover:bg-background/20 hover:text-accent-foreground data-[state=on]:bg-primary', + }, + size: { + default: 'h-10 px-3', + sm: 'h-9 px-2.5', + lg: 'h-11 px-5', + xs: 'h-6 px-1', + }, + }, + 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/src/renderer/components/ToggleGroup/ToggleGroup.tsx b/src/renderer/components/ToggleGroup/ToggleGroup.tsx new file mode 100644 index 00000000..5cca7db4 --- /dev/null +++ b/src/renderer/components/ToggleGroup/ToggleGroup.tsx @@ -0,0 +1,77 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '../utils'; +import { toggleVariants } from '../Toggle/Toggle'; + +const ToggleGroupContext = React.createContext< + VariantProps +>({ + size: 'default', + variant: 'default', +}); + +const toggleGroupVariants = cva( + 'flex items-center justify-center rounded-md bg-card', + { + variants: { + variant: { + default: '', + outline: 'border border-popover-border', + }, + size: { + sm: 'h-9', + lg: 'h-11', + xs: 'h-6', + }, + }, + } +); + +const ToggleGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, children, ...props }, ref) => ( + + + {children} + + +)); + +ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName; + +const ToggleGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, children, variant, size, ...props }, ref) => { + const context = React.useContext(ToggleGroupContext); + + return ( + + {children} + + ); +}); + +ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName; + +export { ToggleGroup, ToggleGroupItem }; diff --git a/src/renderer/components/Tooltip/Tooltip.tsx b/src/renderer/components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..d20962b9 --- /dev/null +++ b/src/renderer/components/Tooltip/Tooltip.tsx @@ -0,0 +1,81 @@ +/* eslint-disable react/require-default-props */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; + +import { cn } from '../utils'; + +interface TooltipProps + extends Omit, + Pick< + TooltipPrimitive.TooltipProps, + 'open' | 'defaultOpen' | 'onOpenChange' | 'delayDuration' + > { + content: React.ReactNode; + onClick?: React.MouseEventHandler; + side?: 'bottom' | 'left' | 'top' | 'right'; + maxWidth?: number; +} +const Tooltip = ({ + children, + content, + open, + defaultOpen, + onOpenChange, + delayDuration, + maxWidth = 220, + className, + side, + sideOffset = 8, + onClick, + ...props +}: TooltipProps) => { + return ( + + + {children} + + + + {content} + + + + ); +}; + +type TooltipProviderProps = TooltipPrimitive.TooltipProviderProps; + +const TooltipProvider = ({ + children, + delayDuration = 100, + skipDelayDuration = 300, + ...props +}: TooltipProviderProps) => { + return ( + + {children} + + ); +}; + +export { Tooltip, TooltipProvider }; diff --git a/src/renderer/components/utils/index.ts b/src/renderer/components/utils/index.ts new file mode 100644 index 00000000..2819a830 --- /dev/null +++ b/src/renderer/components/utils/index.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/renderer/containers/ApplicationStatusCard/ApplicationStatusCard.tsx b/src/renderer/containers/ApplicationStatusCard/ApplicationStatusCard.tsx new file mode 100644 index 00000000..ce96cc0f --- /dev/null +++ b/src/renderer/containers/ApplicationStatusCard/ApplicationStatusCard.tsx @@ -0,0 +1,66 @@ +import { Crashes, MicStatus, RecStatus, SaveStatus } from 'main/types'; + +import { cn } from 'renderer/components/utils'; +import MicrophoneStatus from './MicStatus'; +import Status from './Status'; +import CrashStatus from './CrashStatus'; + +type ApplicationStatusCardProps = { + recorderStatus: RecStatus; + error: string; + micStatus: MicStatus; + crashes: Crashes; + savingStatus: SaveStatus; +}; + +const ApplicationStatusCard = ({ + recorderStatus, + error, + micStatus, + crashes, + savingStatus, +}: ApplicationStatusCardProps) => { + const hasExtraBar = !!(micStatus || crashes?.length); + return ( +
+
+
+
+ +
+
+
+ + +
+
+
+ ); +}; + +export default ApplicationStatusCard; diff --git a/src/renderer/containers/ApplicationStatusCard/CrashStatus.tsx b/src/renderer/containers/ApplicationStatusCard/CrashStatus.tsx new file mode 100644 index 00000000..64612d21 --- /dev/null +++ b/src/renderer/containers/ApplicationStatusCard/CrashStatus.tsx @@ -0,0 +1,40 @@ +import { ShieldAlert } from 'lucide-react'; +import { Crashes, CrashData } from 'main/types'; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from 'renderer/components/HoverCard/HoverCard'; + +const CrashStatus = ({ crashes }: { crashes: Crashes }) => { + if (!crashes?.length) return null; + return ( + + + + + +
+

+ An OBS crash has occured and has been recovered from. This should + not happen in normal operation. You may wish to seek help by sharing + your WR and OBS logs in discord. +

+
    + {crashes.map((crash: CrashData) => { + const dateString = crash.date.toLocaleString(); + return ( +
  • + {dateString}:{' '} + {crash.reason} +
  • + ); + })} +
+
+
+
+ ); +}; + +export default CrashStatus; diff --git a/src/renderer/containers/ApplicationStatusCard/MicStatus.tsx b/src/renderer/containers/ApplicationStatusCard/MicStatus.tsx new file mode 100644 index 00000000..e1d7e2f5 --- /dev/null +++ b/src/renderer/containers/ApplicationStatusCard/MicStatus.tsx @@ -0,0 +1,25 @@ +import { Mic, MicOff } from 'lucide-react'; +import { MicStatus } from 'main/types'; +import { Tooltip } from 'renderer/components/Tooltip/Tooltip'; + +const MicrophoneStatus = ({ micStatus }: { micStatus: MicStatus }) => { + if (micStatus === MicStatus.LISTENING) { + return ( + + + + ); + } + + if (micStatus === MicStatus.MUTED) { + return ( + + + + ); + } + + return null; +}; + +export default MicrophoneStatus; diff --git a/src/renderer/containers/ApplicationStatusCard/Status.tsx b/src/renderer/containers/ApplicationStatusCard/Status.tsx new file mode 100644 index 00000000..4c1d04fe --- /dev/null +++ b/src/renderer/containers/ApplicationStatusCard/Status.tsx @@ -0,0 +1,290 @@ +/* eslint-disable react/require-default-props */ +/* eslint-disable import/prefer-default-export */ +import { CloudDownload, CloudUpload, HardDriveDownload } from 'lucide-react'; +import { RecStatus, SaveStatus } from 'main/types'; +import React from 'react'; +import { Button } from 'renderer/components/Button/Button'; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from 'renderer/components/HoverCard/HoverCard'; +import Separator from 'renderer/components/Separator/Separator'; +import StatusLight, { + StatusLightProps, +} from 'renderer/components/StatusLight/StatusLight'; +import { cn } from 'renderer/components/utils'; +import { useSettings } from 'renderer/useSettings'; + +type StatusInfo = { + statusTitle: string; + statusIndicatorVariant: StatusLightProps['variant']; + statusDescription: React.ReactNode | undefined; +}; + +type StatusProps = { + status: RecStatus; + error: string; + savingStatus: SaveStatus; +}; + +const Status = ({ status, error, savingStatus }: StatusProps) => { + const stopRecording = () => { + window.electron.ipcRenderer.sendMessage('recorder', ['stop']); + }; + + const [config] = useSettings(); + + const getConfiguredFlavours = () => { + if (config.recordRetail && config.recordClassic) { + return 'Retail and Classic'; + } + + if (config.recordRetail) { + return 'Retail'; + } + + if (config.recordClassic) { + return 'Classic'; + } + + return 'nothing. You likely want to enable retail, classic, or both in the app settings'; + }; + + // The short recording status descriptor used on the status card + const RecStatusTitle: Record = { + [RecStatus.Recording]: 'Recording', + [RecStatus.WaitingForWoW]: 'Waiting', + [RecStatus.InvalidConfig]: 'Invalid', + [RecStatus.ReadyToRecord]: 'Ready', + [RecStatus.FatalError]: 'Error', + [RecStatus.Overrunning]: 'Overrunning', + [RecStatus.Reconfiguring]: 'Reconfiguring', + }; + + // The variant applied to the StatusLight on the card, for each status + const RecStatusVariants: Record = { + [RecStatus.Recording]: 'recording', + [RecStatus.WaitingForWoW]: 'waiting', + [RecStatus.InvalidConfig]: 'invalid', + [RecStatus.ReadyToRecord]: 'ready', + [RecStatus.FatalError]: 'error', + [RecStatus.Overrunning]: 'overrunning', + [RecStatus.Reconfiguring]: 'waiting', + }; + + // The description for each status, which shows in the popover when the status title is hovered + // This can be undefined, to skip the popover functionality altogether + const RecStatusDescription: Record = { + [RecStatus.Recording]: ( +
+

+ Warcraft Recorder is currently recording +

+ +

+ You can force the recording to end. Normally this should not be + required. This can help end a failed Mythic+ run that would otherwise + need a few minutes to wrap up. +

+
+ +
+
+ ), + [RecStatus.WaitingForWoW]: ( +
+

+ Waiting for World of Warcraft to start +

+ +

+ Warcraft Recorder is configured to record {getConfiguredFlavours()} +

+
+ ), + [RecStatus.InvalidConfig]: ( +
+

+ Warcraft Recorder is misconfigured +

+ +

+ Please resolve the error below +

+

{error}

+
+ ), + [RecStatus.ReadyToRecord]: ( +
+

+ Detected World of Warcraft is running +

+ +

+ Warcraft Recorder is waiting for a recordable event to appear in the + combat log. Watching log paths: +

+
    + {config.recordRetail && ( +
  • + Retail:{' '} + {config.retailLogPath} +
  • + )} + {config.recordClassic && ( +
  • + Classic:{' '} + {config.classicLogPath} +
  • + )} +
+ +

+ Tip: If recordings do not start, + check your logging settings in-game and confirm your log path + configuration is correct. +

+
+ ), + [RecStatus.FatalError]: ( +
+

+ Warcraft Recorder has hit a fatal error +

+ +

+ Please try to resolve the error below, then restart the application. +

+

{error}

+

+ If this problem is recurring, please ask for help in Discord. See the + pins in the #help channel for advice on getting help. +

+
+ ), + [RecStatus.Overrunning]: ( +
+

Overrunning ...

+ +

+ Warcraft Recorder has detected an activity has completed successfuly + and is recording a few seconds extra to catch the aftermath. +

+
+ ), + [RecStatus.Reconfiguring]: undefined, + }; + + const statusLightsClasses = 'w-1.5 h-full rounded-l-md rounded-r-none'; + + const { statusTitle, statusIndicatorVariant, statusDescription }: StatusInfo = + { + statusTitle: RecStatusTitle[status], + statusIndicatorVariant: RecStatusVariants[status], + statusDescription: RecStatusDescription[status], + }; + + const [uploadProgress, setUploadProgress] = React.useState( + false + ); + const [downloadProgress, setDownloadProgress] = React.useState< + number | false + >(false); + + React.useEffect(() => { + const ipc = window.electron.ipcRenderer; + + ipc.on('updateUploadProgress', (progress) => { + if (!progress || progress === 100) { + setTimeout(() => setUploadProgress(false), 1000); + } + setUploadProgress(progress as number); + }); + + ipc.on('updateDownloadProgress', (progress) => { + if (!progress || progress === 100) { + setTimeout(() => setDownloadProgress(false), 1000); + } + setDownloadProgress(progress as number); + }); + + return () => { + ipc.removeAllListeners('updateUploadProgress'); + ipc.removeAllListeners('updateDownloadProgress'); + }; + }, []); + + const isSaving = savingStatus === SaveStatus.Saving; + const isUpDowning = uploadProgress !== false || downloadProgress !== false; + + return ( + + +
+ +
+ + Status + + + + {statusTitle} + + + {(isSaving || isUpDowning) && ( +
+ {isSaving && ( + <> + + {isUpDowning && } + + )} + {isUpDowning && ( + <> + <> + {downloadProgress !== false && ( + <> + {' '} + {downloadProgress.toFixed(0)}% + + )} + + {downloadProgress !== false && uploadProgress !== false && ( + + )} + <> + {uploadProgress !== false && ( + <> + {uploadProgress.toFixed(0)}% + + )} + + + )} +
+ )} +
+
+ {!!statusDescription && ( + + {statusDescription} + + )} +
+
+ ); +}; + +export default Status; diff --git a/src/renderer/containers/UpgradeNotifier/UpgradeNotifier.tsx b/src/renderer/containers/UpgradeNotifier/UpgradeNotifier.tsx new file mode 100644 index 00000000..dfd94195 --- /dev/null +++ b/src/renderer/containers/UpgradeNotifier/UpgradeNotifier.tsx @@ -0,0 +1,43 @@ +import { ArrowBigDownDash } from 'lucide-react'; +import { UpgradeStatus } from 'main/types'; +import React from 'react'; +import { Button } from 'renderer/components/Button/Button'; +import { Tooltip } from 'renderer/components/Tooltip/Tooltip'; + +const ipc = window.electron.ipcRenderer; + +type UpgradeNotifierProps = { + upgradeStatus: UpgradeStatus; +}; + +function arePropsEqual( + oldProps: UpgradeNotifierProps, + newProps: UpgradeNotifierProps +): boolean { + return ( + oldProps.upgradeStatus.available === newProps.upgradeStatus.available && + oldProps.upgradeStatus.link === newProps.upgradeStatus.link + ); +} + +const UpgradeNotifier = React.memo( + ({ upgradeStatus }: UpgradeNotifierProps) => { + if (!upgradeStatus.available) return null; + + return ( + + + + ); + }, + arePropsEqual +); + +export default UpgradeNotifier; diff --git a/src/renderer/rendererutils.ts b/src/renderer/rendererutils.ts index f99fa32a..4582f605 100644 --- a/src/renderer/rendererutils.ts +++ b/src/renderer/rendererutils.ts @@ -354,14 +354,14 @@ const getResultColor = (video: RendererVideo) => { upgradeLevel < 1 ) { // It's a completed, but depleted mythic+. - return 'rgb(171, 170, 30, 0.3)'; + return 'hsl(var(--warning))'; } if (result) { - return 'rgb(53, 164, 50, 0.3)'; + return 'hsl(var(--success))'; } - return 'rgb(156, 21, 21, 0.3)'; + return 'hsl(var(--error))'; }; const getPlayerName = (video: RendererVideo) => { diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..cbb78878 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,125 @@ +/* eslint-disable global-require */ +/** @type {import('tailwindcss').Config} */ +const plugin = require('tailwindcss/plugin'); +const { fontFamily } = require('tailwindcss/defaultTheme'); + +module.exports = { + content: ['./src/renderer/**/*.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))', + 'background-higher': 'hsl(var(--background-higher))', + 'background-dark-gradient-from': + 'hsl(var(--background-dark-gradient-from))', + 'background-dark-gradient-to': + 'hsl(var(--background-dark-gradient-to))', + foreground: 'hsl(var(--foreground))', + 'foreground-lighter': 'hsl(var(--foreground-lighter))', + 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))', + border: 'hsl(var(--popover-border))', + inset: 'hsl(var(--popover-inset))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + success: { + DEFAULT: 'hsl(var(--success))', + border: 'hsl(var(--success-border))', + }, + error: { + DEFAULT: 'hsl(var(--error))', + border: 'hsl(var(--error-border))', + text: 'hsl(var(--error-foreground))', + }, + warning: { + DEFAULT: 'hsl(var(--warning))', + border: 'hsl(var(--warning-border))', + }, + 'blue-accent': { + DEFAULT: 'hsl(var(--blue-accent))', + border: 'hsl(var(--blue-accent-border))', + }, + video: { + DEFAULT: 'hsl(var(--video-item-background))', + hover: 'hsl(var(--video-item-background-hover))', + border: 'hsl(var(--video-item-border))', + foreground: 'hsl(var(--video-item-foreground))', + }, + }, + borderRadius: { + lg: `var(--radius)`, + md: `calc(var(--radius) - 2px)`, + sm: 'calc(var(--radius) - 4px)', + }, + fontFamily: { + sans: ['var(--font-sans)', ...fontFamily.sans], + }, + textShadow: { + instance: + '-1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000', + }, + 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'), + plugin(function ({ matchUtilities, theme }) { + matchUtilities( + { + 'text-shadow': (value) => ({ + textShadow: value, + }), + }, + { values: theme('textShadow') } + ); + }), + ], + variants: {}, +}; diff --git a/tsconfig.json b/tsconfig.json index 2b1c9873..f79b9b3f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,10 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "allowJs": true, - "outDir": "release/app/dist" + "outDir": "release/app/dist", + "paths": { + "@components/*": ["./src/renderer/components/*"] + } }, "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"] }