diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..52a8328 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4439 @@ +{ + "name": "ps2-react-client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ps2-react-client", + "version": "0.0.0", + "dependencies": { + "@epicgames-ps/lib-pixelstreamingfrontend-ue5.3": "^1.0.8", + "@tanstack/react-query": "^5.62.7", + "@uidotdev/usehooks": "^2.4.1", + "ahooks": "^3.7.10", + "baseline-browser-mapping": "^2.9.14", + "caniuse-lite": "^1.0.30001764", + "date-fns": "^2.30.0", + "framer-motion": "^11.17.0", + "i18next": "^23.8.2", + "ky": "^1.1.3", + "libphonenumber-js": "^1.11.7", + "peerjs": "^1.5.4", + "react": "^18.2.0", + "react-calendar": "^4.3.0", + "react-countdown": "^2.3.5", + "react-device-detect": "^2.2.3", + "react-dom": "^18.2.0", + "react-draggable": "^4.4.6", + "react-full-screen": "^1.1.1", + "react-hook-form": "^7.53.0", + "react-i18next": "^14.0.3", + "react-input-mask": "^2.0.4", + "react-qr-code": "^2.0.11", + "react-router-dom": "^6.11.2", + "react-swipeable": "^7.0.2", + "react-timeit": "^1.2.12", + "react-timer-hook": "^3.0.7", + "react-toastify": "^10.0.5", + "react-transition-group": "^4.4.5", + "react-usestateref": "^1.0.9", + "socket.io-client": "^4.7.4", + "ua-parser-js": "^1.0.35", + "use-clipboard-copy": "^0.2.0", + "use-is-audio-active": "^1.0.0", + "usehooks-ts": "^3.0.1", + "uuid": "^9.0.1", + "zustand": "^4.3.9" + }, + "devDependencies": { + "@types/node": "^20.11.17", + "@types/peerjs": "^1.1.0", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-input-mask": "^3.0.2", + "@types/react-transition-group": "^4.4.6", + "@types/ua-parser-js": "^0.7.36", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", + "@vitejs/plugin-react-swc": "^3.0.0", + "autoprefixer": "^10.4.14", + "eslint": "^8.38.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.3.4", + "postcss": "^8.4.23", + "tailwindcss": "^3.3.2", + "typescript": "^5.0.2", + "vite": "^4.3.2" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==", + "license": "MIT" + }, + "node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ue5.3": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.3/-/lib-pixelstreamingfrontend-ue5.3-1.0.8.tgz", + "integrity": "sha512-1dIvu/So6bUKSFi2xh1cUbcPdCAEKccJUSeWs3vmlSf3xwsi6O4dTKr44Gxxq5szg5F4lxQxVPrO5rrtWeDy4Q==", + "license": "MIT", + "dependencies": { + "sdp": "^3.1.0" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "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==", + "dev": true, + "license": "ISC", + "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/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "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/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.12.14", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.23" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.12.14", + "@swc/core-darwin-x64": "1.12.14", + "@swc/core-linux-arm-gnueabihf": "1.12.14", + "@swc/core-linux-arm64-gnu": "1.12.14", + "@swc/core-linux-arm64-musl": "1.12.14", + "@swc/core-linux-x64-gnu": "1.12.14", + "@swc/core-linux-x64-musl": "1.12.14", + "@swc/core-win32-arm64-msvc": "1.12.14", + "@swc/core-win32-ia32-msvc": "1.12.14", + "@swc/core-win32-x64-msvc": "1.12.14" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.12.14", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.23", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.99.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.99.2.tgz", + "integrity": "sha512-1HunU0bXVsR1ZJMZbcOPE6VtaBJxsW809RE9xPe4Gz7MlB0GWwQvuTPhMoEmQ/hIzFKJ/DWAuttIe7BOaWx0tA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.99.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.99.2.tgz", + "integrity": "sha512-vM91UEe45QUS9ED6OklsVL15i8qKcRqNwpWzPTVWvRPRSEgDudDgHpvyTjcdlwHcrKNa80T+xXYcchT2noPnZA==", + "dependencies": { + "@tanstack/query-core": "5.99.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.8", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/peerjs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/peerjs/-/peerjs-1.1.0.tgz", + "integrity": "sha512-dVocsfYFg5QQuUB9OAxfrSvz4br4pyX+7M61ZJSRiYtE3NdayShk1p1Y8b9TmCj724TwHskVraeF7wyPl0rYcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "peerjs": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.23", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-input-mask": { + "version": "3.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@uidotdev/usehooks": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz", + "integrity": "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.10.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.11", + "@swc/core": "^1.11.31" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7.0.0-beta.0" + } + }, + "node_modules/@wojtekmaj/date-utils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.5.1.tgz", + "integrity": "sha512-+i7+JmNiE/3c9FKxzWFi2IjRJ+KzZl1QPu6QNrsgaa2MuBgXvUy4gA1TVzf/JMdIIloB76xSKikTWuyYAIVLww==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ahooks": { + "version": "3.9.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0", + "dayjs": "^1.9.1", + "intersection-observer": "^0.12.0", + "js-cookie": "^3.0.5", + "lodash": "^4.17.21", + "react-fast-compare": "^3.2.2", + "resize-observer-polyfill": "^1.5.1", + "screenfull": "^5.0.0", + "tslib": "^2.4.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "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" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/autoprefixer/node_modules/caniuse-lite": { + "version": "1.0.30001727", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.14", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist/node_modules/caniuse-lite": { + "version": "1.0.30001727", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001764", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clipboard-copy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-3.2.0.tgz", + "integrity": "sha512-vooFaGFL6ulEP1liiaWFBmmfuPm3cY3y7T9eB83ZTnYc/oFeAKsq3NcDrOkBC8XaauEE8zHQwI7k0+JSYiVQSQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.10.0.tgz", + "integrity": "sha512-YyMIS/LsSKEGXEaVJdjonWe18p4vXLo8CMA4FrW/kcaEyqdIGKCFXao31gbJddXEdIxSXFFURWrenBJPlKTgAA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "^10.10.0", + "jss-preset-default": "^10.10.0" + } + }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.7", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "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, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.183", + "dev": true, + "license": "ISC" + }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.3.5.tgz", + "integrity": "sha512-61qNIsc7fo9Pp/mju0J83kzvLm0Bsayu7OQSLEoJxLDCBjIIyb87bkzufoOvdDxLkSlMfkF7UxomC4+eztUBSA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fscreen": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fscreen/-/fscreen-1.2.0.tgz", + "integrity": "sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg==", + "license": "MIT" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-user-locale": { + "version": "2.3.2", + "license": "MIT", + "dependencies": { + "mem": "^8.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "dev": true, + "license": "ISC", + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/i18next": { + "version": "23.16.8", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/intersection-observer": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz", + "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==", + "license": "Apache-2.0" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-compose": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.10.0.tgz", + "integrity": "sha512-F5kgtWpI2XfZ3Z8eP78tZEYFdgTIbpA/TMuX3a8vwrNolYtN1N4qJR/Ob0LAsqIwCMLojtxN7c7Oo/+Vz6THow==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-expand": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.10.0.tgz", + "integrity": "sha512-ymT62W2OyDxBxr7A6JR87vVX9vTq2ep5jZLIdUSusfBIEENLdkkc0lL/Xaq8W9s3opUq7R0sZQpzRWELrfVYzA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-extend": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.10.0.tgz", + "integrity": "sha512-sKYrcMfr4xxigmIwqTjxNcHwXJIfvhvjTNxF+Tbc1NmNdyspGW47Ey6sGH8BcQ4FFQhLXctpWCQSpDwdNmXSwg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-rule-value-observable": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.10.0.tgz", + "integrity": "sha512-ZLMaYrR3QE+vD7nl3oNXuj79VZl9Kp8/u6A1IbTPDcuOu8b56cFdWRZNZ0vNr8jHewooEeq2doy8Oxtymr2ZPA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "symbol-observable": "^1.2.0" + } + }, + "node_modules/jss-plugin-template": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.10.0.tgz", + "integrity": "sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, + "node_modules/jss-preset-default": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.10.0.tgz", + "integrity": "sha512-GL175Wt2FGhjE+f+Y3aWh+JioL06/QWFgZp53CbNNq6ZkVU0TDplD8Bxm9KnkotAYn3FlplNqoW5CjyLXcoJ7Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "jss-plugin-camel-case": "10.10.0", + "jss-plugin-compose": "10.10.0", + "jss-plugin-default-unit": "10.10.0", + "jss-plugin-expand": "10.10.0", + "jss-plugin-extend": "10.10.0", + "jss-plugin-global": "10.10.0", + "jss-plugin-nested": "10.10.0", + "jss-plugin-props-sort": "10.10.0", + "jss-plugin-rule-value-function": "10.10.0", + "jss-plugin-rule-value-observable": "10.10.0", + "jss-plugin-template": "10.10.0", + "jss-plugin-vendor-prefixer": "10.10.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/ky": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libphonenumber-js": { + "version": "1.12.41", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.41.tgz", + "integrity": "sha512-lsmMmGXBxXIK/VMLEj0kL6MtUs1kBGj1nTCzi6zgQoG1DEwqwt2DQyHxcLykceIxAnfE3hya7NuIh6PpC6S3fA==" + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "license": "ISC" + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "license": "MIT", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem": { + "version": "8.1.1", + "license": "MIT", + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==" + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/mz": { + "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", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "license": "BlueOak-1.0.0", + "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-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/peerjs": { + "version": "1.5.5", + "license": "MIT", + "dependencies": { + "@msgpack/msgpack": "^2.8.0", + "eventemitter3": "^4.0.7", + "peerjs-js-binarypack": "^2.1.0", + "webrtc-adapter": "^9.0.0" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/peer" + } + }, + "node_modules/peerjs-js-binarypack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-2.1.0.tgz", + "integrity": "sha512-YIwCC+pTzp3Bi8jPI9UFKO0t0SLo6xALnHkiNt/iUFmUUZG0fEEmEyFKvjsDKweiFitzHRyhuh6NvyJZ4nNxMg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/peer" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "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.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-calendar": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-4.8.0.tgz", + "integrity": "sha512-qFgwo+p58sgv1QYMI1oGNaop90eJVKuHTZ3ZgBfrrpUb+9cAexxsKat0sAszgsizPMVo7vOXedV7Lqa0GQGMvA==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^2.0.0", + "get-user-locale": "^2.2.1", + "prop-types": "^15.6.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-countdown": { + "version": "2.3.6", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 15", + "react-dom": ">= 15" + } + }, + "node_modules/react-device-detect": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz", + "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==", + "license": "MIT", + "dependencies": { + "ua-parser-js": "^1.0.33" + }, + "peerDependencies": { + "react": ">= 0.14.0", + "react-dom": ">= 0.14.0" + } + }, + "node_modules/react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==", + "license": "MIT" + }, + "node_modules/react-dom": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-draggable": { + "version": "4.5.0", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "license": "MIT" + }, + "node_modules/react-full-screen": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/react-full-screen/-/react-full-screen-1.1.1.tgz", + "integrity": "sha512-xoEgkoTiN0dw9cjYYGViiMCBYbkS97BYb4bHPhQVWXj1UnOs8PZ1rPzpX+2HMhuvQV1jA5AF9GaRbO3fA5aZtg==", + "license": "MIT", + "dependencies": { + "fscreen": "^1.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.73.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.73.1.tgz", + "integrity": "sha512-VAfVYOPcx3piiEVQy95vyFmBwbVUsP/AUIN+mpFG8h11yshDd444nn0VyfaGWSRnhOLVgiDu7HIuBtAIzxn9dA==", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-i18next": { + "version": "14.1.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-input-mask": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-input-mask/-/react-input-mask-2.0.4.tgz", + "integrity": "sha512-1hwzMr/aO9tXfiroiVCx5EtKohKwLk/NT8QlJXHQ4N+yJJFyUuMT+zfTpLBwX/lK3PkuMlievIffncpMZ3HGRQ==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "warning": "^4.0.2" + }, + "peerDependencies": { + "react": ">=0.14.0", + "react-dom": ">=0.14.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.10.0.tgz", + "integrity": "sha512-WLiq84UYWqNBF6579/uprcIUnM1TSywYq6AIjKTTTG5ziJl9Uy+pwuvpN3apuyVwflMbD60PraeTKT7uWH9XEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.10.0", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.10.0", + "jss-preset-default": "10.10.0", + "prop-types": "^15.6.0", + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/react-qr-code": { + "version": "2.0.18", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1", + "qr.js": "0.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-router": { + "version": "6.30.1", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.1", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-swipeable": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-7.0.2.tgz", + "integrity": "sha512-v1Qx1l+aC2fdxKa9aKJiaU/ZxmJ5o98RMoFwUqAAzVWUcxgfHFXDDruCKXhw6zIYXm6V64JiHgP9f6mlME5l8w==", + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/react-timeit": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/react-timeit/-/react-timeit-1.2.12.tgz", + "integrity": "sha512-/c+NzN32ju98+RJ30TzFvp8eiJCSMtT5jheu9kUHIbDC7grZX5l2iK6i+AUGf/WAF8R++sjBNr9VVpY4VXQVSw==", + "license": "MIT", + "dependencies": { + "react-jss": "^10.9.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-timer-hook": { + "version": "3.0.8", + "license": "ISC", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-toastify": { + "version": "10.0.6", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/react-usestateref": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/react-usestateref/-/react-usestateref-1.0.9.tgz", + "integrity": "sha512-t8KLsI7oje0HzfzGhxFXzuwbf1z9vhBM1ptHLUIHhYqZDKFuI5tzdhEVxSNzUkYxwF8XdpOErzHlKxvP7sTERw==", + "license": "ISC", + "peerDependencies": { + "react": ">16.0.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.29.5", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/screenfull": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz", + "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sdp": { + "version": "3.2.1", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.1", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "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/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==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "dev": true, + "license": "MIT", + "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/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/theming": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", + "license": "MIT", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.3" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-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==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.40", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-clipboard-copy": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/use-clipboard-copy/-/use-clipboard-copy-0.2.0.tgz", + "integrity": "sha512-f0PMMwZ2/Hh9/54L12capx4s6ASdd6edNJxg2OcqWVNM8BPvtOSmNFIN1Dg/q//fPp8MpUZceHfr7cnWOS0RxA==", + "license": "MIT", + "dependencies": { + "clipboard-copy": "^3.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/use-is-audio-active": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/use-is-audio-active/-/use-is-audio-active-1.0.0.tgz", + "integrity": "sha512-8GZaxCe7DaBi1VeDDiHY9+aO1vCb0OCQb6+Gwf3j46Nxo/sITcgPmKKt0TiJVgbDlbEVP4RWu9krpadA57V6Ag==", + "license": "MIT", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "react": "^16.9.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/usehooks-ts": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16.15.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "4.5.14", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/webrtc-adapter": { + "version": "9.0.3", + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "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/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==", + "dev": true, + "license": "MIT", + "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/wrap-ansi-cjs/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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, + "license": "MIT" + }, + "node_modules/wrap-ansi/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/yaml": { + "version": "2.8.0", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "4.5.7", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json index 2741bc3..9134fd9 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,16 @@ }, "dependencies": { "@epicgames-ps/lib-pixelstreamingfrontend-ue5.3": "^1.0.8", + "@tanstack/react-query": "^5.62.7", "@uidotdev/usehooks": "^2.4.1", "ahooks": "^3.7.10", "baseline-browser-mapping": "^2.9.14", "caniuse-lite": "^1.0.30001764", "date-fns": "^2.30.0", + "framer-motion": "^11.17.0", "i18next": "^23.8.2", "ky": "^1.1.3", + "libphonenumber-js": "^1.11.7", "peerjs": "^1.5.4", "react": "^18.2.0", "react-calendar": "^4.3.0", @@ -26,10 +29,12 @@ "react-dom": "^18.2.0", "react-draggable": "^4.4.6", "react-full-screen": "^1.1.1", + "react-hook-form": "^7.53.0", "react-i18next": "^14.0.3", "react-input-mask": "^2.0.4", "react-qr-code": "^2.0.11", "react-router-dom": "^6.11.2", + "react-swipeable": "^7.0.2", "react-timeit": "^1.2.12", "react-timer-hook": "^3.0.7", "react-toastify": "^10.0.5", diff --git a/public/fonts/TTHovesProAll/TTHovesPro-DmBd.eot b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.eot new file mode 100644 index 0000000..5cc5eea Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.eot differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-DmBd.ttf b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.ttf new file mode 100644 index 0000000..45ab33d Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.ttf differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff new file mode 100644 index 0000000..bf0549a Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff2 b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff2 new file mode 100644 index 0000000..ac58b1f Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-DmBd.woff2 differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Md.eot b/public/fonts/TTHovesProAll/TTHovesPro-Md.eot new file mode 100644 index 0000000..37c2ee7 Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Md.eot differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Md.ttf b/public/fonts/TTHovesProAll/TTHovesPro-Md.ttf new file mode 100644 index 0000000..96896b5 Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Md.ttf differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Md.woff b/public/fonts/TTHovesProAll/TTHovesPro-Md.woff new file mode 100644 index 0000000..dba766b Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Md.woff differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Md.woff2 b/public/fonts/TTHovesProAll/TTHovesPro-Md.woff2 new file mode 100644 index 0000000..df64d2f Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Md.woff2 differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Rg.eot b/public/fonts/TTHovesProAll/TTHovesPro-Rg.eot new file mode 100644 index 0000000..128b76b Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Rg.eot differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Rg.ttf b/public/fonts/TTHovesProAll/TTHovesPro-Rg.ttf new file mode 100644 index 0000000..e41a50e Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Rg.ttf differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff b/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff new file mode 100644 index 0000000..fb1b27b Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff differ diff --git a/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff2 b/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff2 new file mode 100644 index 0000000..2550fa8 Binary files /dev/null and b/public/fonts/TTHovesProAll/TTHovesPro-Rg.woff2 differ diff --git a/public/fonts/TTHovesProAll/demo.html b/public/fonts/TTHovesProAll/demo.html new file mode 100644 index 0000000..a5b323f --- /dev/null +++ b/public/fonts/TTHovesProAll/demo.html @@ -0,0 +1,250 @@ + + + + + + + + + Transfonter demo + + + + +
+
+

☝︎TT Hoves Pro DemiBold

+
.your-style {
+    font-family: 'TTHovesPro-DmBd';
+    font-weight: 600;
+    font-style: normal;
+}
+
+<link rel="preload" href="TTHovesPro-DmBd.woff2" as="font" type="font/woff2" crossorigin>
+
+

+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~ +

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+
+
+ +
+

☝︎TT Hoves Pro Medium

+
.your-style {
+    font-family: 'TTHovesPro-Md';
+    font-weight: 500;
+    font-style: normal;
+}
+
+<link rel="preload" href="TTHovesPro-Md.woff2" as="font" type="font/woff2" crossorigin>
+
+

+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~ +

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+
+
+ +
+

☝︎TT Hoves Pro Regular

+
.your-style {
+    font-family: 'TTHovesPro-Rg';
+    font-weight: normal;
+    font-style: normal;
+}
+
+<link rel="preload" href="TTHovesPro-Rg.woff2" as="font" type="font/woff2" crossorigin>
+
+

+ abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ 0123456789.:,;()*!?'@#<>$%&^+-=~ +

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+

The quick brown fox jumps over the lazy dog.

+
+
+ +
+ + diff --git a/public/fonts/TTHovesProAll/stylesheet.css b/public/fonts/TTHovesProAll/stylesheet.css new file mode 100644 index 0000000..4440c8c --- /dev/null +++ b/public/fonts/TTHovesProAll/stylesheet.css @@ -0,0 +1,38 @@ +@font-face { + font-family: 'TTHovesPro'; + src: url('TTHovesPro-DmBd.eot'); + src: + url('TTHovesPro-DmBd.eot?#iefix') format('embedded-opentype'), + url('TTHovesPro-DmBd.woff2') format('woff2'), + url('TTHovesPro-DmBd.woff') format('woff'), + url('TTHovesPro-DmBd.ttf') format('truetype'); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'TTHovesPro'; + src: url('TTHovesPro-Md.eot'); + src: + url('TTHovesPro-Md.eot?#iefix') format('embedded-opentype'), + url('TTHovesPro-Md.woff2') format('woff2'), + url('TTHovesPro-Md.woff') format('woff'), + url('TTHovesPro-Md.ttf') format('truetype'); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'TTHovesPro'; + src: url('TTHovesPro-Rg.eot'); + src: + url('TTHovesPro-Rg.eot?#iefix') format('embedded-opentype'), + url('TTHovesPro-Rg.woff2') format('woff2'), + url('TTHovesPro-Rg.woff') format('woff'), + url('TTHovesPro-Rg.ttf') format('truetype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} diff --git a/public/img/components/header/Sk.svg b/public/img/components/header/Sk.svg new file mode 100644 index 0000000..076a2ae --- /dev/null +++ b/public/img/components/header/Sk.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/projects/liferes.jpg b/public/img/projects/liferes.jpg new file mode 100644 index 0000000..4b9db2b Binary files /dev/null and b/public/img/projects/liferes.jpg differ diff --git a/public/img/projects/nks.jpg b/public/img/projects/nks.jpg new file mode 100644 index 0000000..5da79d1 Binary files /dev/null and b/public/img/projects/nks.jpg differ diff --git a/public/img/projects/upside.jpg b/public/img/projects/upside.jpg new file mode 100644 index 0000000..656d0ae Binary files /dev/null and b/public/img/projects/upside.jpg differ diff --git a/public/img/showreel.png b/public/img/showreel.png new file mode 100644 index 0000000..0a6e10a Binary files /dev/null and b/public/img/showreel.png differ diff --git a/public/videos/composition.mp4 b/public/videos/composition.mp4 new file mode 100644 index 0000000..9aa4168 Binary files /dev/null and b/public/videos/composition.mp4 differ diff --git a/public/videos/streaming.mp4 b/public/videos/streaming.mp4 new file mode 100644 index 0000000..8260d2c Binary files /dev/null and b/public/videos/streaming.mp4 differ diff --git a/src/App.tsx b/src/App.tsx index 24e4cbd..c628770 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,563 +1,51 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable react-hooks/exhaustive-deps */ -/* eslint-disable no-irregular-whitespace */ -import "./App.css"; -import { Trans, useTranslation } from "react-i18next"; -import FeedbackForm from "./components/FeedbackForm"; -import ArrowRightIcon from "./components/icons/ArrowRightIcon"; -import LogoIcon from "./components/icons/LogoIcon"; -import MailIcon from "./components/icons/MailIcon"; -import PhoneIcon from "./components/icons/PhoneIcon"; -import TelegramIcon from "./components/icons/TelegramIcon"; -import VKIcon from "./components/icons/VKIcon"; -import YouTubeIcon from "./components/icons/YouTubeIcon"; -import Sidebar from "./components/Sidebar"; -import Header from "./components/Header"; -import { Transition } from "react-transition-group"; -import useSidebarStore from "./stores/useSidebarStore"; -import { useEffect, useState } from "react"; -import ky from "ky"; +import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { useNavigate, useSearchParams } from "react-router-dom"; -import { Bounce, ToastContainer, toast } from "react-toastify"; +import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; -import InfoIcon from "./components/icons/InfoIcon"; -import { detectUserRegion, getRegionHeaders, getUserRegion } from "./utils/api"; -import { handleApiError, isErrorResponse } from "./utils/errorHandler"; + +import { Footer } from "@/landing/components/Layout/Footer"; +import Header from "@/landing/components/Layout/Header"; +import { ModalContainer } from "@/landing/components/Layout/ModalContainer"; +import StreamDemo from "@/landing/features/stream-demo/StreamDemo"; +import { useAutoStartFromQuery } from "@/landing/hooks/useAutoStartFromQuery"; function App() { + const { t, i18n } = useTranslation(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); - const [isOpen, setIsOpen] = useSidebarStore((state) => [ - state.isOpen, - state.setIsOpen, - ]); - // const [loading, setLoading] = useState(false); - // const [countdownTimer, setCountdownTimer] = useState(15); - const { t, i18n } = useTranslation(); - const build = searchParams.get("build") || null; - const type = searchParams.get("type") || "demo"; - const endAt = searchParams.get("endAt"); - const [streamUrl, setStreamUrl] = useState(); - const [regionDetected, setRegionDetected] = useState(false); - function toastError(text: string) { - toast.error(text, { - icon: , - position: "top-center", - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, - theme: "light", - transition: Bounce, - }); - } - - - async function startStream(build: string) { - let location = "a1"; - - if (searchParams.has("location")) { - location = searchParams.get("location") as string; - } - - try { - const response: any = await ky - .get( - `${ - import.meta.env.VITE_COORD_URL - }/start?location=${location}&build=${build}&type=${type}&endAt=${endAt}`, - { headers: getRegionHeaders() } - ) - .json(); - - // Проверяем, является ли ответ ошибкой - if (isErrorResponse(response)) { - handleApiError(response, t, navigate); - return; - } - - if (response.stream) { - setStreamUrl(`/stream/${response.stream}`); - } else if (response.error) { - toastError(response.error); - } else { - toastError(t("errors.unknownError")); - } - } catch (error) { - if (error instanceof Error) { - toastError(t("errors.networkError") + `: ${error.message}`); - } - } - } - - // useEffect(() => { - // if (countdownTimer > 0 || !streamUrl) return; - - // navigate(streamUrl); - // }, [countdownTimer]); - - useEffect(() => { - if (!streamUrl) return; - navigate(streamUrl); - }, [streamUrl]); - - // Определяем регион пользователя при первой загрузке (пропускаем API, если ?lang= уже задал регион) - useEffect(() => { - async function initializeRegion() { - if (getUserRegion()) { - setRegionDetected(true); - return; - } - try { - await detectUserRegion(); - setRegionDetected(true); - } catch (error) { - console.error("Failed to detect user region:", error); - setRegionDetected(true); - } - } - - void initializeRegion(); - }, []); - - useEffect(() => { - if (build && regionDetected) { - void startStream(build); - } - }, [regionDetected]); + useAutoStartFromQuery(searchParams, navigate, t); useEffect(() => { document.title = t("title"); + }, [i18n.language, t]); + + /* + * Locale selection (URL `?lang=` → country-code fallback) is handled by the + * top-level `LanguageDetector` wrapper in `src/main.tsx`, which calls + * `detectUserRegion()` once for the whole app. We intentionally don't mount + * the landing's `LocaleSync` here — it would fire a duplicate + * `getCountryCode` request. We only mirror the resulting `i18n.language` + * onto `` for accessibility/SEO. + */ + useEffect(() => { + document.documentElement.lang = i18n.language.startsWith("ru") + ? "ru" + : "en"; }, [i18n.language]); return ( - <> -
-
-
- -
-
- -
- -
-

- - Доступные -
- демонстрации -
-

-

- - Клиент из любой точки мира может посмотреть жилой комплекс, - даже на нулевом этапе строительства. Он выберет лучшую - планировку и оценит вид из окон своей будущей квартиры. - -

-
- -
- {/*
-
- -
-
-

- - ЖК «Upside Towers» - -

-

- - Россия, Москва - -

-
- - -
-
*/} - -
- {i18n.language === "ru" ? ( - <> -
-
- -
-
-

- - МФК «Revolution towers» - -

-

- - Россия, Екатеринбург - -

-
- - -
-
- -
-
- -
-
-

- - ЖК «Life Резиденция» - -

-

- - Россия, Тюмень - -

-
- - -
-
- - {/*
-
- -
-
-

- - ЖК «Айвазовский City» - -

-

- - Россия, Тюмень - -

-
- - -
-
*/} - - ) : ( - <> -
-
- -
-
-

- - Upside Towers - -

-

- - Russia, Moscow - -

-
- - -
-
- - )} -
-
-
- -
-
-
-
-

- - Запись на -
- удаленную -
- демонстрацию -
-

-

- - Запись на демонстрацию может быть -
- оформлена в виде блока на сайте -
- застройщика или жилого комплекса. -
-

- -
-

- - Запись доступна в демонстрационном режиме. -
- Указанные при записи данные не будут сохранены. -
-

-
- -
- -
-
-
- -
-
-
-
-

- - Свяжитесь -
с нами -
-

-

- - Хотите увеличить конверсию? -
- Давайте обсудим детали! -
-

-
-
- -
- -
-
-
- -
-
- -
- -
-
-

- Горячая линия -

-
-
- - - -
-
-

- - Социальные -
- сети -
-

- -
-
-
-
-
- -
-
-
-
-
- -
-
-

- - - Политика конфиденциальности - - - - graff.estate - -

-

- © 2026 GRAFF interactive.{" "} - Все права защищены. -

-
-
- -
-
- -
- RU -
-
-
- -
-
- -
- UAE -
-
-
-
-
-
+
+
+ {/* Без overflow-clip: иначе flex-1 + clip часто даёт пустой/обрезанный экран */} +
+
- - - {(state) => } - - +
+ - +
); } diff --git a/src/i18n.ts b/src/i18n.ts index 0962e02..fb427b5 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -49,22 +49,8 @@ const resources = { "Запись доступна в демонстрационном режиме.
Указанные при записи данные не будут сохранены.", }, feedback: { - title: "Свяжитесь
с нами", - desc: "Хотите увеличить конверсию?
Давайте обсудим детали!", - form: { - field1: "Имя", - field2: "Телефон", - field3: "Опишите вашу задачу", - button: "Отправить", - desc1: { - text1: "Нажимая кнопку «Отправить», вы принимаете", - text1_1: "Нажимая кнопку «Записаться», вы принимаете", - link1: "условия использования", - text2: "и", - link2: "политику конфиденциальности", - }, - desc2: "Звездочкой отмечены обязательные
для заполнения поля", - }, + titleLead: "Хотите увеличить конверсию?", + titleRest: "Давайте обсудим детали.", }, contacts: { title: "Горячая линия", @@ -75,9 +61,97 @@ const resources = { }, }, footer: { - link: "Политика конфиденциальности", - text: "Все права защищены.", + call: "Позвонить", + write: "Написать", + phoneDisplay: "8 800 770 00 67", + phoneTel: "+78007700067", + emailAddress: "info@graff.tech", + legalAddress: "Юридический адрес:", + addressLine1: "620063, г. Екатеринбург,", + addressLine2: "ул. Большакова, д. 66, кв. 6", + mainStack: "Наш основной стек:", + stackLine: "Unreal Engine 5, C++", + requisites: "Реквизиты:", + inn: "ИНН: 6679174128", + kpp: "КПП: 667101001", + company: 'ООО "ГРАФФ.ЭСТЕЙТ"', + ogrn: "ОГРН 1246600010140", + skolkovoAlt: "Сколково", + privacy: "Политика конфиденциальности и обработки персональных данных", + copyright: "© 2026 GRAFF interactive. Все права защищены", + site: "graff.tech", }, + languageSwitcher: { + ru: "RU", + en: "EN", + ariaLabel: "Язык", + }, + legalLinks: { + privacyConsent: "https://graff.estate/privacy-policy", + policy: "https://graff.estate/policy", + }, + demos: { + titleLine1: "Доступные", + titleLine2: "демонстрации", + ctaTitle: "Расскажем и покажем как это работает на\u00a0созвоне", + ctaButton: "Оставить заявку", + description: + "Клиент из любой точки мира может посмотреть жилой комплекс, даже на нулевом этапе строительства. Он выберет лучшую планировку и оценит вид из окон своей будущей квартиры.", + }, + streamingProject: { + watch: "Смотреть", + startDemo: "Начать демонстрацию", + }, + requestDemo: { + titleLine1: "Запись", + titleLine2: "на удаленную", + titleLine3: "демонстрацию", + description: + "Запись на демонстрацию может быть оформлена в виде блока на сайте застройщика или жилого комплекса.", + cta: "Оставить заявку", + }, + streamPlayer: { + caption: + "Модуль удаленных продаж GRAFF.estate доступен на\u00a0любых устройствах, для\u00a0демонстрации нужен только\u00a0интернет.", + }, + leadForm: { + submitError: "Не удалось отправить заявку. Попробуйте позже.", + needTitle: "Нам нужно", + namePlaceholder: "Имя*", + emailPlaceholder: "Email*", + submit: "Оставить заявку", + consentBefore: "*Нажимая кнопку отправить, вы даете", + consentLinkData: "согласие на обработку персональных данных", + consentMiddle: "и принимаете", + consentLinkPolicy: "условия политики", + }, + questionModal: { + phonePlaceholder: "+X (XXX) XXX - XX - XX", + }, + feedbackModal: { + successRich: + "Мы получили заявку и скоро свяжемся с вами!", + sourcesTitle1: "Расскажите, пожалуйста,", + sourcesTitle2: "откуда вы узнали о нас?", + send: "Отправить", + skip: "Пропустить", + }, + products: { + interactivePresentation: "Интерактивная презентация", + remoteDemo: "Удаленная демонстрация", + archViz: "Архитектурная визуализация", + webDev: "Создание сайтов", + webTour360: "Веб-тур по 360 сферам", + }, + modalFeedbackSources: [ + "Увидели на выставке или форуме", + "Видели у других застройщиков", + "Из рейтингов и статей", + "Нашли в интернете", + "Перешли по рекламе", + "Из рассылки", + "Другое", + ], sidebar: { title1: "Дата и время", title2: "Контакты", @@ -288,22 +362,8 @@ const resources = { "The recording is available in demo mode.
The data specified during recording will not be saved.", }, feedback: { - title: "Contact us", - desc: "Want to increase conversion?
Let's discuss the details!", - form: { - field1: "Name", - field2: "Phone", - field3: "Describe your task", - button: "Send", - desc1: { - text1: 'By clicking the "Submit" button, you accept the', - text1_1: 'By clicking the "Sign up" button, you accept the', - link1: "terms of use", - text2: "and", - link2: "privacy policy", - }, - desc2: "Required fields are marked
with an asterisk", - }, + titleLead: "Want to improve conversion?", + titleRest: "Let's discuss the details.", }, contacts: { title: "Hot line", @@ -314,9 +374,97 @@ const resources = { }, }, footer: { - link: "Privacy policy", - text: "All rights reserved.", + call: "Call", + write: "Write", + phoneDisplay: "+971 58 506 0097", + phoneTel: "+971585060097", + emailAddress: "sam@graff.tech", + legalAddress: "Legal address:", + addressLine1: "620063, Yekaterinburg,", + addressLine2: "Bolshakova St., 66, apt. 6", + mainStack: "Our core stack:", + stackLine: "Unreal Engine 5, C++", + requisites: "Company details:", + inn: "TIN: 6679174128", + kpp: "IEC: 667101001", + company: "GRAFF.ESTATE LLC", + ogrn: "PSRN 1246600010140", + skolkovoAlt: "Skolkovo", + privacy: "Privacy and personal data processing policy", + copyright: "© 2026 GRAFF interactive FZCO. All rights reserved", + site: "graff.tech", }, + languageSwitcher: { + ru: "RU", + en: "EN", + ariaLabel: "Language", + }, + legalLinks: { + privacyConsent: "https://graffestate.ae/privacypolicy", + policy: "https://graffestate.ae/terms-conditions", + }, + demos: { + titleLine1: "Available", + titleLine2: "demos", + ctaTitle: "We'll walk you through how it works on\u00a0a call", + ctaButton: "Request a call", + description: + "Clients anywhere in the world can explore a residential complex, even at the zero stage of construction. They can pick the best layout and assess the view from the windows of their future apartment.", + }, + streamingProject: { + watch: "Watch", + startDemo: "Start demo", + }, + requestDemo: { + titleLine1: "Book", + titleLine2: "a remote", + titleLine3: "demo", + description: + "A demo booking can be embedded as a block on the developer's or residential complex's website.", + cta: "Request a call", + }, + streamPlayer: { + caption: + "GRAFF.estate Stream is available on\u00a0any device — all you need for a demo is an internet connection.", + }, + leadForm: { + submitError: "Could not submit the request. Please try again later.", + needTitle: "We need", + namePlaceholder: "Name*", + emailPlaceholder: "Email*", + submit: "Submit request", + consentBefore: "*By submitting, you give", + consentLinkData: "consent to personal data processing", + consentMiddle: "and accept the", + consentLinkPolicy: "policy terms", + }, + questionModal: { + phonePlaceholder: "+X (XXX) XXX - XX - XX", + }, + feedbackModal: { + successRich: + "We've received your request and we'll contact you soon!", + sourcesTitle1: "Please tell us", + sourcesTitle2: "how you heard about us", + send: "Send", + skip: "Skip", + }, + products: { + interactivePresentation: "Interactive presentation", + remoteDemo: "Remote demonstration", + archViz: "Architectural visualization", + webDev: "Website development", + webTour360: "360° web tour", + }, + modalFeedbackSources: [ + "Saw us at an exhibition or forum", + "Saw it with other developers", + "From rankings and articles", + "Found online", + "Came from an ad", + "From a newsletter", + "Other", + ], sidebar: { title1: "Date and time", title2: "Contacts", diff --git a/src/landing/components/Layout/Feedback.tsx b/src/landing/components/Layout/Feedback.tsx new file mode 100644 index 0000000..74ae32d --- /dev/null +++ b/src/landing/components/Layout/Feedback.tsx @@ -0,0 +1,48 @@ +import { useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import type { Product } from "@/landing/types"; +import useAddReferer from "@/landing/hooks/useAddReferer"; +import { useModalStore } from "@/landing/stores/useModalStore"; +import FeedbackModal from "@/landing/components/modals/FeedbackFormModal"; +import { LeadForm } from "@/landing/features/lead-form/LeadForm"; + +export function Feedback() { + useAddReferer(); + const { t } = useTranslation(); + + return ( +
+

+ {t("feedback.titleLead")} +
+ {t("feedback.titleRest")} +

+ +
+ ); +} + +export function FeedbackForm() { + const { t, i18n } = useTranslation(); + const { setModal } = useModalStore(); + + const defaultProducts = useMemo( + (): Product[] => [t("products.remoteDemo")], + [t] + ); + + return ( +
+
+ setModal()} + /> +
+
+ ); +} diff --git a/src/landing/components/Layout/Footer.tsx b/src/landing/components/Layout/Footer.tsx new file mode 100644 index 0000000..ed634a4 --- /dev/null +++ b/src/landing/components/Layout/Footer.tsx @@ -0,0 +1,148 @@ +import { PropsWithChildren } from "react"; +import { useTranslation } from "react-i18next"; +import ArrowMoreIcon from "@/landing/components/icons/ArrowMoreIcon"; +import RutubeIcon from "@/landing/components/icons/RutubeIcon"; +import TelegramIcon from "@/landing/components/icons/TgIcon"; +import VkIcon from "@/landing/components/icons/VKIcon"; +import YoutubeIcon from "@/landing/components/icons/YoutubeIcon"; + +export function Footer() { + const { t, i18n } = useTranslation(); + const showRuLegal = i18n.language.startsWith("ru"); + const isEn = i18n.language.startsWith("en"); + + return ( + + ); +} + +export function ContactLink({ + children, + href, + className = "", +}: PropsWithChildren<{ href: string; className?: string }>) { + return ( + + {children} + + ); +} diff --git a/src/landing/components/Layout/Header.tsx b/src/landing/components/Layout/Header.tsx new file mode 100644 index 0000000..54ea18d --- /dev/null +++ b/src/landing/components/Layout/Header.tsx @@ -0,0 +1,11 @@ +import LanguageSwitchButton from "./LanguageSwitchButton"; + +export default function Header() { + return ( +
+ +
+ ); +} diff --git a/src/landing/components/Layout/LanguageSwitchButton.tsx b/src/landing/components/Layout/LanguageSwitchButton.tsx new file mode 100644 index 0000000..50efd2c --- /dev/null +++ b/src/landing/components/Layout/LanguageSwitchButton.tsx @@ -0,0 +1,34 @@ +import { useTranslation } from "react-i18next"; +import type { AppLocale } from "@/landing/i18n"; +import { setLangInUrl } from "@/landing/lib/urlLang"; + +export default function LanguageSwitchButton({ + className, +}: { + className?: string; +}) { + const { i18n, t } = useTranslation(); + const current = (i18n.language.startsWith("ru") ? "ru" : "en") as AppLocale; + + function handleClick() { + const next: AppLocale = current === "ru" ? "en" : "ru"; + void i18n.changeLanguage(next); + setLangInUrl(next); + } + + return ( + + ); +} diff --git a/src/landing/components/Layout/LineBreak.tsx b/src/landing/components/Layout/LineBreak.tsx new file mode 100644 index 0000000..10b4485 --- /dev/null +++ b/src/landing/components/Layout/LineBreak.tsx @@ -0,0 +1,18 @@ +interface BRProps { + lg?: boolean; + md?: boolean; + sm?: boolean; + className?: string; +} + +export default function BR({ lg, md, sm, className }: BRProps) { + const modifier = + !lg && !md && !sm + ? "" + : `lg:${lg ? `block` : "hidden"} md:${md ? "block" : "hidden"} ${ + sm ? "block" : "hidden" + } `; + const combinedClassName = `${modifier} ${className ?? ""}`; + + return
; +} diff --git a/src/landing/components/Layout/LocaleSync.tsx b/src/landing/components/Layout/LocaleSync.tsx new file mode 100644 index 0000000..3330a32 --- /dev/null +++ b/src/landing/components/Layout/LocaleSync.tsx @@ -0,0 +1,30 @@ +import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import type { AppLocale } from "@/landing/i18n"; +import { useLocationSearch } from "@/landing/hooks/useLocationSearch"; +import { parseLangParam } from "@/landing/lib/urlLang"; +import { useCountryCodeQuery } from "@/landing/queries/getCountryCode"; + +/** Applies resolved locale from `?lang=` or getCountryCode; syncs ``. */ +export function LocaleSync() { + const { i18n } = useTranslation(); + const search = useLocationSearch(); + const langFromUrl = parseLangParam(new URLSearchParams(search).get("lang")); + const { data, isSuccess, isError } = useCountryCodeQuery(); + + useEffect(() => { + if (langFromUrl) { + void i18n.changeLanguage(langFromUrl); + document.documentElement.lang = langFromUrl; + return; + } + if (!isSuccess && !isError) return; + + const locale: AppLocale = + isSuccess && data?.countryCode === "RU" ? "ru" : "en"; + void i18n.changeLanguage(locale); + document.documentElement.lang = locale; + }, [langFromUrl, isSuccess, isError, data, i18n]); + + return null; +} diff --git a/src/landing/components/Layout/ModalContainer.tsx b/src/landing/components/Layout/ModalContainer.tsx new file mode 100644 index 0000000..51d6d92 --- /dev/null +++ b/src/landing/components/Layout/ModalContainer.tsx @@ -0,0 +1,27 @@ +import { useModalStore } from "@/landing/stores/useModalStore"; +import { useEffect } from "react"; +import { createPortal } from "react-dom"; + +export function ModalContainer() { + const { modal, setModal } = useModalStore(); + + useEffect(() => { + const listener = (e: KeyboardEvent) => { + if (e.key === "Escape") setModal(null); + }; + document.addEventListener("keydown", listener); + + return () => { + document.removeEventListener("keydown", listener); + }; + }, [setModal]); + + const jsx = modal ? ( +
+
+ {modal} +
+ ) : null; + + return createPortal(jsx, document.body); +} diff --git a/src/landing/components/icons/ArrowMoreIcon.tsx b/src/landing/components/icons/ArrowMoreIcon.tsx new file mode 100644 index 0000000..ed81890 --- /dev/null +++ b/src/landing/components/icons/ArrowMoreIcon.tsx @@ -0,0 +1,14 @@ +function ArrowMoreIcon() { + return ( + + + + ); +} + +export default ArrowMoreIcon; diff --git a/src/landing/components/icons/CheckIcon.tsx b/src/landing/components/icons/CheckIcon.tsx new file mode 100644 index 0000000..d49662c --- /dev/null +++ b/src/landing/components/icons/CheckIcon.tsx @@ -0,0 +1,14 @@ +function CheckIcon() { + return ( + + + + ); +} + +export default CheckIcon; diff --git a/src/landing/components/icons/CloseIcon.tsx b/src/landing/components/icons/CloseIcon.tsx new file mode 100644 index 0000000..b6d69fc --- /dev/null +++ b/src/landing/components/icons/CloseIcon.tsx @@ -0,0 +1,14 @@ +function CloseIcon() { + return ( + + + + ); +} + +export default CloseIcon; diff --git a/src/landing/components/icons/LogoHorIcon.tsx b/src/landing/components/icons/LogoHorIcon.tsx new file mode 100644 index 0000000..d8f5487 --- /dev/null +++ b/src/landing/components/icons/LogoHorIcon.tsx @@ -0,0 +1,221 @@ +function LogoHorIcon() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +export default LogoHorIcon; diff --git a/src/landing/components/icons/MuteIcon.tsx b/src/landing/components/icons/MuteIcon.tsx new file mode 100644 index 0000000..44569f1 --- /dev/null +++ b/src/landing/components/icons/MuteIcon.tsx @@ -0,0 +1,12 @@ +function MuteIcon() { + return ( + + + + ); +} + +export default MuteIcon; diff --git a/src/landing/components/icons/PauseIcon.tsx b/src/landing/components/icons/PauseIcon.tsx new file mode 100644 index 0000000..b97e2f0 --- /dev/null +++ b/src/landing/components/icons/PauseIcon.tsx @@ -0,0 +1,12 @@ +function PauseIcon() { + return ( + + + + ); +} + +export default PauseIcon; diff --git a/src/landing/components/icons/PlayIcon.tsx b/src/landing/components/icons/PlayIcon.tsx new file mode 100644 index 0000000..a978d9c --- /dev/null +++ b/src/landing/components/icons/PlayIcon.tsx @@ -0,0 +1,9 @@ +function PlayIcon() { + return ( + + + + ); +} + +export default PlayIcon; diff --git a/src/landing/components/icons/RutubeIcon.tsx b/src/landing/components/icons/RutubeIcon.tsx new file mode 100644 index 0000000..0746e9d --- /dev/null +++ b/src/landing/components/icons/RutubeIcon.tsx @@ -0,0 +1,12 @@ +function RutubeIcon() { + return ( + + + + ); +} + +export default RutubeIcon; diff --git a/src/landing/components/icons/TgIcon.tsx b/src/landing/components/icons/TgIcon.tsx new file mode 100644 index 0000000..f18b5dd --- /dev/null +++ b/src/landing/components/icons/TgIcon.tsx @@ -0,0 +1,14 @@ +function TgIcon() { + return ( + + + + ); +} + +export default TgIcon; diff --git a/src/landing/components/icons/UnmutedIcon.tsx b/src/landing/components/icons/UnmutedIcon.tsx new file mode 100644 index 0000000..47c4373 --- /dev/null +++ b/src/landing/components/icons/UnmutedIcon.tsx @@ -0,0 +1,12 @@ +function UnmutedIcon() { + return ( + + + + ); +} + +export default UnmutedIcon; diff --git a/src/landing/components/icons/VKIcon.tsx b/src/landing/components/icons/VKIcon.tsx new file mode 100644 index 0000000..21e2128 --- /dev/null +++ b/src/landing/components/icons/VKIcon.tsx @@ -0,0 +1,14 @@ +function VKIcon() { + return ( + + + + ); +} + +export default VKIcon; diff --git a/src/landing/components/icons/YoutubeIcon.tsx b/src/landing/components/icons/YoutubeIcon.tsx new file mode 100644 index 0000000..24c8d25 --- /dev/null +++ b/src/landing/components/icons/YoutubeIcon.tsx @@ -0,0 +1,14 @@ +function YoutubeIcon() { + return ( + + + + ); +} + +export default YoutubeIcon; diff --git a/src/landing/components/modals/FeedbackFormModal.tsx b/src/landing/components/modals/FeedbackFormModal.tsx new file mode 100644 index 0000000..87213d9 --- /dev/null +++ b/src/landing/components/modals/FeedbackFormModal.tsx @@ -0,0 +1,90 @@ +import { useMemo, useState } from "react"; +import { Trans, useTranslation } from "react-i18next"; +import { Button } from "@/landing/ui/Button"; +import { api } from "@/landing/lib/api"; +import { useModalStore } from "@/landing/stores/useModalStore"; +import CustomCheckbox from "@/landing/ui/CustomCheckbox"; +import CheckIcon from "@/landing/components/icons/CheckIcon"; + +function FeedbackModal({ id }: { id: string }) { + const { t } = useTranslation(); + const { setModal } = useModalStore(); + const [selectedOptions, setSelectedOptions] = useState([]); + + const modalOptions = useMemo( + () => t("modalFeedbackSources", { returnObjects: true }) as string[], + [t] + ); + + async function sendSources() { + await api.put(`mail/${id}`, { json: { source: selectedOptions } }); + setModal(null); + } + + function onCheckboxChange(value: string, checked: boolean) { + if (checked) setSelectedOptions([...selectedOptions, value]); + else { + const updated = [...selectedOptions].filter((item) => item !== value); + setSelectedOptions(updated); + } + } + + return ( +
+
+
+
+
+ +
+
+ + + , + brDesktop:
, + }} + /> +
+
+ +
+ +
+
+ {t("feedbackModal.sourcesTitle1")} +
+ {t("feedbackModal.sourcesTitle2")} +
+ +
    + {modalOptions.map((item) => ( +
  • + +
  • + ))} +
+ +
+ + +
+
+
+ ); +} + +export default FeedbackModal; diff --git a/src/landing/components/modals/QuestionFormModal.tsx b/src/landing/components/modals/QuestionFormModal.tsx new file mode 100644 index 0000000..4ca1833 --- /dev/null +++ b/src/landing/components/modals/QuestionFormModal.tsx @@ -0,0 +1,53 @@ +import { useMemo, useRef, type RefObject } from "react"; +import { useOnClickOutside } from "usehooks-ts"; +import { useTranslation } from "react-i18next"; +import { useModalStore } from "@/landing/stores/useModalStore"; +import type { Product } from "@/landing/types"; +import FeedbackModal from "./FeedbackFormModal"; +import CloseIcon from "@/landing/components/icons/CloseIcon"; +import { LeadForm } from "@/landing/features/lead-form/LeadForm"; + +interface QuestionFormModalProps { + products?: Product[]; +} + +export default function QuestionFormModal({ + products, +}: QuestionFormModalProps) { + const { t, i18n } = useTranslation(); + const { setModal } = useModalStore(); + + const defaultModalProducts = useMemo((): Product[] => { + return [t("products.webDev"), t("products.webTour360")]; + }, [t]); + + const formRef = useRef(null); + + useOnClickOutside(formRef as RefObject, () => { + setModal(null); + }); + + return ( +
+ + setModal()} + /> +
+ ); +} diff --git a/src/landing/data/streamingProjects.ts b/src/landing/data/streamingProjects.ts new file mode 100644 index 0000000..c381c7f --- /dev/null +++ b/src/landing/data/streamingProjects.ts @@ -0,0 +1,58 @@ +import type { IProject } from "@/landing/types"; + +const BASE: Omit< + IProject, + | "id" + | "title" + | "englishTitle" + | "city" + | "englishCity" + | "buildFilename" + | "image" +> = { + description: "", + stage: 0, + releaseDate: "2026-01-01T00:00:00.000Z", + tags: [], +}; + +const RU_PROJECTS: IProject[] = [ + { + ...BASE, + id: "revolution-towers", + title: "МФК «Revolution towers»", + englishTitle: "Revolution Towers", + city: "Россия, Екатеринбург", + englishCity: "Russia, Yekaterinburg", + buildFilename: "nksJukovaDev", + image: "/img/projects/nks.jpg", + }, + { + ...BASE, + id: "life-residence", + title: "ЖК «Life Резиденция»", + englishTitle: "Life Residence", + city: "Россия, Тюмень", + englishCity: "Russia, Tyumen", + buildFilename: "lifeResidence", + image: "/img/projects/liferes.jpg", + }, +]; + +const EN_PROJECTS: IProject[] = [ + { + ...BASE, + id: "upside-towers", + title: "Upside Towers", + englishTitle: "Upside Towers", + city: "Russia, Moscow", + englishCity: "Russia, Moscow", + buildFilename: "upsideTowersDevEn", + image: "/img/projects/upside.jpg", + }, +]; + +/** Demo projects for the streaming section, selected by UI language. */ +export function getStreamingProjects(i18nLanguage: string): IProject[] { + return i18nLanguage.startsWith("ru") ? RU_PROJECTS : EN_PROJECTS; +} diff --git a/src/landing/features/lead-form/LeadForm.tsx b/src/landing/features/lead-form/LeadForm.tsx new file mode 100644 index 0000000..36c9d92 --- /dev/null +++ b/src/landing/features/lead-form/LeadForm.tsx @@ -0,0 +1,150 @@ +import { useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { api } from "@/landing/lib/api"; +import { productOptionsFromT } from "@/landing/lib/productLabels"; +import type { Product } from "@/landing/types"; +import { Button } from "@/landing/ui/Button"; +import { CheckboxesGroup } from "@/landing/ui/CheckboxesGroup"; +import { PhoneInputRu } from "@/landing/ui/PhoneInputRu"; +import { useRefererStore } from "@/landing/stores/useRefererStore"; +import { + Controller, + FormProvider, + useForm, + type SubmitHandler, +} from "react-hook-form"; +import type { LeadFormValues } from "./types"; + +export type { LeadFormValues } from "./types"; + +export function LeadForm({ + defaultProducts, + idPrefix = "", + onSuccess, + phonePlaceholder, + formClassName = "lg:space-y-[1.944vw] md:max-lg:space-y-7 space-y-3", +}: { + defaultProducts: Product[]; + /** Префикс для id полей (например `modal-`), чтобы избежать дублей в DOM */ + idPrefix?: string; + onSuccess: (id: string) => void; + phonePlaceholder?: string; + formClassName?: string; +}) { + const { t } = useTranslation(); + const { referer } = useRefererStore(); + const [submitError, setSubmitError] = useState(null); + const projectOptions = useMemo(() => productOptionsFromT(t), [t]); + + const form = useForm({ + defaultValues: { + fullname: "", + email: "", + phone: "", + products: defaultProducts, + }, + }); + + const { register, handleSubmit, formState, control } = form; + const nameId = idPrefix ? `${idPrefix}name` : "name"; + const emailId = idPrefix ? `${idPrefix}email` : "email"; + + const onSubmit: SubmitHandler = async (data) => { + setSubmitError(null); + try { + const { id } = await api + .post("mail", { json: { ...data, referer } }) + .json<{ id: string }>(); + onSuccess(id); + } catch { + setSubmitError(t("leadForm.submitError")); + } + }; + + return ( + +
+ {submitError ? ( +

+ {submitError} +

+ ) : null} +
+

{t("leadForm.needTitle")}

+ + name="products" + options={projectOptions} + /> +
+ + +
+ ( + + )} + /> +
+
+
+ +
+ {t("leadForm.consentBefore")}{" "} + + {t("leadForm.consentLinkData")} + {" "} + {t("leadForm.consentMiddle")} + + {t("leadForm.consentLinkPolicy")} + +
+
+ + + ); +} diff --git a/src/landing/features/lead-form/types.ts b/src/landing/features/lead-form/types.ts new file mode 100644 index 0000000..02732fd --- /dev/null +++ b/src/landing/features/lead-form/types.ts @@ -0,0 +1,8 @@ +import type { Product } from "@/landing/types"; + +export interface LeadFormValues { + fullname: string; + phone: string; + email: string; + products: Product[]; +} diff --git a/src/landing/features/stream-demo/AvailableDemos.tsx b/src/landing/features/stream-demo/AvailableDemos.tsx new file mode 100644 index 0000000..bd016b2 --- /dev/null +++ b/src/landing/features/stream-demo/AvailableDemos.tsx @@ -0,0 +1,134 @@ +import { + useMemo, + useRef, + useState, + type MouseEvent as ReactMouseEvent, +} from "react"; +import { useTranslation } from "react-i18next"; +import BR from "@/landing/components/Layout/LineBreak"; +import { getStreamingProjects } from "@/landing/data/streamingProjects"; +import { StreamingProject } from "./StreamingProject"; +import { useSwipeable } from "react-swipeable"; +import { useMediaQueries } from "@/landing/hooks/useMediaQueries"; + +export default function AvailableDemos() { + const { t, i18n } = useTranslation(); + const { isMd } = useMediaQueries(); + const projects = useMemo( + () => getStreamingProjects(i18n.language), + [i18n.language] + ); + const [current, setCurrent] = useState(0); + + const slideCount = projects.length + 1; + const handlers = useSwipeable({ + onSwipedLeft: () => + setCurrent((prev) => (prev + 1) % Math.max(slideCount, 1)), + onSwipedRight: () => + setCurrent((prev) => (prev + projects.length) % Math.max(slideCount, 1)), + trackMouse: true, + preventScrollOnSwipe: true, + touchEventOptions: { passive: false }, + }); + + const sliderRef = useRef(null); + + function onSliderMouseDown(e: ReactMouseEvent) { + const root = sliderRef.current; + if (!root) return; + + const startX = e.clientX; + const startScrollLeft = root.scrollLeft; + + function onMouseMove(ev: MouseEvent) { + if (!root) return; + const dx = ev.clientX - startX; + root.scrollLeft = startScrollLeft - dx; + } + + function onMouseUp() { + document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("mouseup", onMouseUp); + } + + document.addEventListener("mousemove", onMouseMove); + document.addEventListener("mouseup", onMouseUp); + } + + return ( +
+
+

+ {t("demos.titleLine1")}
{t("demos.titleLine2")} +

+ +
+ {projects.map((project, index, { length }) => ( + + ))} +
+
+
+

+ {t("demos.ctaTitle")} +

+ + {t("demos.ctaButton")} + +
+
+
+
+
+

{t("demos.description")}

+
+
+ +
+ {projects.map((project, index, { length }) => ( +
+ +
+ ))} +
+
+ ); +} diff --git a/src/landing/features/stream-demo/RequestForDemo.tsx b/src/landing/features/stream-demo/RequestForDemo.tsx new file mode 100644 index 0000000..3657b42 --- /dev/null +++ b/src/landing/features/stream-demo/RequestForDemo.tsx @@ -0,0 +1,53 @@ +import { useTranslation } from "react-i18next"; +import BR from "@/landing/components/Layout/LineBreak"; +import { Button } from "@/landing/ui/Button"; +import QuestionFormModal from "@/landing/components/modals/QuestionFormModal"; +import { useModalStore } from "@/landing/stores/useModalStore"; + +export default function RequestForDemo() { + const { t } = useTranslation(); + const { setModal } = useModalStore(); + + return ( +
+
+

+ {t("requestDemo.titleLine1")}
{t("requestDemo.titleLine2")} +
{t("requestDemo.titleLine3")} +

+ +
+

+ {t("requestDemo.description")} +

+ +
+
+ +
+ ); +} diff --git a/src/landing/features/stream-demo/StreamDemo.tsx b/src/landing/features/stream-demo/StreamDemo.tsx new file mode 100644 index 0000000..e2cfe48 --- /dev/null +++ b/src/landing/features/stream-demo/StreamDemo.tsx @@ -0,0 +1,15 @@ +import { Feedback } from "@/landing/components/Layout/Feedback"; +import AvailableDemos from "./AvailableDemos"; +import StreamPlayer from "./StreamPlayer"; + +export default function StreamDemo() { + return ( +
+ +
+ +
+ +
+ ); +} diff --git a/src/landing/features/stream-demo/StreamPlayer.tsx b/src/landing/features/stream-demo/StreamPlayer.tsx new file mode 100644 index 0000000..9251682 --- /dev/null +++ b/src/landing/features/stream-demo/StreamPlayer.tsx @@ -0,0 +1,29 @@ +import { useTranslation } from "react-i18next"; +import { VideoPlayer } from "@/landing/ui/VideoPlayer"; + +const viteBase = import.meta.env.BASE_URL; +const STREAMING_VIDEO_SRC = + !viteBase || viteBase === "/" + ? "/videos/streaming.mp4" + : `${viteBase.replace(/\/$/, "")}/videos/streaming.mp4`; + +export default function StreamPlayer({ className }: { className?: string }) { + const { t } = useTranslation(); + + return ( +
+ +

+ {t("streamPlayer.caption")} +

+
+
+ ); +} diff --git a/src/landing/features/stream-demo/StreamingProject.tsx b/src/landing/features/stream-demo/StreamingProject.tsx new file mode 100644 index 0000000..0f934f2 --- /dev/null +++ b/src/landing/features/stream-demo/StreamingProject.tsx @@ -0,0 +1,98 @@ +import { useTranslation } from "react-i18next"; +import { streamDemoUrlFromBuild } from "@/landing/lib/streamDemoUrl"; +import { resolveProjectImageSrc } from "@/landing/lib/resolveProjectImageSrc"; +import type { IProject } from "@/landing/types"; +import ArrowMoreIcon from "@/landing/components/icons/ArrowMoreIcon"; + +export function StreamingProject({ + city, + title, + image, + href, + buildFilename, + company, + index, + current, + count, + className, +}: Pick & { + href: string; + index: number; + current: number; + count: number; + className?: string; +}) { + const { t } = useTranslation(); + const imgSrc = resolveProjectImageSrc(image); + const build = buildFilename?.trim() ?? ""; + const streamHref = build ? streamDemoUrlFromBuild(build) : href; + + return ( + +
+ +
+
+
+

{title}

+
+ {company && ( +
+
+ {company.title} +
+ )} +

+ {city} +

+
+
+
+ +
+ {t("streamingProject.startDemo")}{" "} +
+ +
+
+
+ + ); +} diff --git a/src/landing/hooks/useAddReferer.ts b/src/landing/hooks/useAddReferer.ts new file mode 100644 index 0000000..04c9d30 --- /dev/null +++ b/src/landing/hooks/useAddReferer.ts @@ -0,0 +1,14 @@ +import { useRefererStore } from "@/landing/stores/useRefererStore"; +import { useEffect } from "react"; + +export default function useAddReferer() { + const { setReferer } = useRefererStore(); + + useEffect(() => { + const referer = new URLSearchParams(window.location.search).get("ref"); + if (!referer) return; + setReferer(referer); + }, [setReferer]); + + return null; +} diff --git a/src/landing/hooks/useAutoStartFromQuery.ts b/src/landing/hooks/useAutoStartFromQuery.ts new file mode 100644 index 0000000..9149a81 --- /dev/null +++ b/src/landing/hooks/useAutoStartFromQuery.ts @@ -0,0 +1,107 @@ +import { useEffect, useState } from "react"; +import ky from "ky"; +import { Bounce, toast } from "react-toastify"; +import type { TFunction } from "i18next"; +import type { NavigateFunction } from "react-router-dom"; +import { + detectUserRegion, + getRegionHeaders, + getUserRegion, +} from "@/utils/api"; +import { handleApiError, isErrorResponse } from "@/utils/errorHandler"; + +type AnyRecord = Record; + +/** + * Landing-level side-effect: when `?build=...` is present in the URL, + * reproduce the legacy behavior of the old main page — detect region, + * call the coord `/start` endpoint and navigate to `/stream/:id`. + * + * This keeps existing marketing links (`/?build=nksJukovaDev&type=demo&...`) + * working after replacing the main page design. + */ +export function useAutoStartFromQuery( + searchParams: URLSearchParams, + navigate: NavigateFunction, + t: TFunction +) { + const build = searchParams.get("build"); + const type = searchParams.get("type") || "demo"; + const endAt = searchParams.get("endAt"); + const location = searchParams.get("location") || "a1"; + + const [streamUrl, setStreamUrl] = useState(); + const [regionDetected, setRegionDetected] = useState(false); + + useEffect(() => { + async function initializeRegion() { + if (getUserRegion()) { + setRegionDetected(true); + return; + } + try { + await detectUserRegion(); + } catch (error) { + console.error("Failed to detect user region:", error); + } finally { + setRegionDetected(true); + } + } + void initializeRegion(); + }, []); + + useEffect(() => { + if (!build || !regionDetected) return; + + async function startStream(buildFilename: string) { + try { + const response = (await ky + .get( + `${ + import.meta.env.VITE_COORD_URL + }/start?location=${location}&build=${buildFilename}&type=${type}&endAt=${endAt ?? ""}`, + { headers: getRegionHeaders() } + ) + .json()) as AnyRecord; + + if (isErrorResponse(response)) { + handleApiError(response, t, navigate); + return; + } + + if (typeof response.stream === "string" && response.stream) { + setStreamUrl(`/stream/${response.stream}`); + } else if (typeof response.error === "string" && response.error) { + toastError(response.error); + } else { + toastError(t("errors.unknownError") as string); + } + } catch (error) { + if (error instanceof Error) { + toastError(`${t("errors.networkError")}: ${error.message}`); + } + } + } + + void startStream(build); + }, [build, type, endAt, location, regionDetected, navigate, t]); + + useEffect(() => { + if (!streamUrl) return; + navigate(streamUrl); + }, [streamUrl, navigate]); +} + +function toastError(text: string) { + toast.error(text, { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + theme: "light", + transition: Bounce, + }); +} diff --git a/src/landing/hooks/useLocationSearch.ts b/src/landing/hooks/useLocationSearch.ts new file mode 100644 index 0000000..fad84bb --- /dev/null +++ b/src/landing/hooks/useLocationSearch.ts @@ -0,0 +1,18 @@ +import { useEffect, useState } from "react"; + +/** Re-renders when `location.search` changes (popstate or custom `locationchange`). */ +export function useLocationSearch(): string { + const [search, setSearch] = useState(() => window.location.search); + + useEffect(() => { + const sync = () => setSearch(window.location.search); + window.addEventListener("popstate", sync); + window.addEventListener("locationchange", sync); + return () => { + window.removeEventListener("popstate", sync); + window.removeEventListener("locationchange", sync); + }; + }, []); + + return search; +} diff --git a/src/landing/hooks/useMediaQueries.ts b/src/landing/hooks/useMediaQueries.ts new file mode 100644 index 0000000..d1783bf --- /dev/null +++ b/src/landing/hooks/useMediaQueries.ts @@ -0,0 +1,66 @@ +import { useEffect, useState } from "react"; + +function readBreakpoints(lg: number, md: number, sm: number) { + if (typeof window === "undefined" || typeof window.matchMedia === "undefined") { + return { + isLg: false, + isMd: false, + isSm: false, + isXs: false, + }; + } + + const lgMedia = matchMedia(`(min-width: ${lg}px)`); + const mdMedia = matchMedia( + `(max-width: ${lg - 1}px) and (min-width: ${md}px)` + ); + const smMedia = matchMedia( + `(max-width: ${md - 1}px) and (min-width: ${sm}px)` + ); + const xsMedia = matchMedia(`(max-width: ${sm - 1}px)`); + + return { + isLg: lgMedia.matches, + isMd: mdMedia.matches, + isSm: smMedia.matches, + isXs: xsMedia.matches, + }; +} + +export function useMediaQueries(lg = 1440, md = 768, sm = 640) { + const [state, setState] = useState(() => readBreakpoints(lg, md, sm)); + + useEffect(() => { + const lgMedia = matchMedia(`(min-width: ${lg}px)`); + const mdMedia = matchMedia( + `(max-width: ${lg - 1}px) and (min-width: ${md}px)` + ); + const smMedia = matchMedia( + `(max-width: ${md - 1}px) and (min-width: ${sm}px)` + ); + const xsMedia = matchMedia(`(max-width: ${sm - 1}px)`); + + const sync = () => setState(readBreakpoints(lg, md, sm)); + + lgMedia.addEventListener("change", sync); + mdMedia.addEventListener("change", sync); + smMedia.addEventListener("change", sync); + xsMedia.addEventListener("change", sync); + + sync(); + + return () => { + lgMedia.removeEventListener("change", sync); + mdMedia.removeEventListener("change", sync); + smMedia.removeEventListener("change", sync); + xsMedia.removeEventListener("change", sync); + }; + }, [lg, md, sm]); + + return { + isLg: state.isLg, + isMd: state.isMd, + isSm: state.isSm, + isXs: state.isXs, + }; +} diff --git a/src/landing/i18n/index.ts b/src/landing/i18n/index.ts new file mode 100644 index 0000000..a2f159e --- /dev/null +++ b/src/landing/i18n/index.ts @@ -0,0 +1 @@ +export type AppLocale = "ru" | "en"; diff --git a/src/landing/i18n/locales/en.json b/src/landing/i18n/locales/en.json new file mode 100644 index 0000000..1e3e85f --- /dev/null +++ b/src/landing/i18n/locales/en.json @@ -0,0 +1,94 @@ +{ + "languageSwitcher": { + "ru": "RU", + "en": "EN", + "ariaLabel": "Language" + }, + "legalLinks": { + "privacyConsent": "https://graffestate.ae/privacypolicy", + "policy": "https://graffestate.ae/terms-conditions" + }, + "footer": { + "call": "Call", + "write": "Write", + "phoneDisplay": "+971 58 506 0097", + "phoneTel": "+971585060097", + "emailAddress": "sam@graff.tech", + "legalAddress": "Legal address:", + "addressLine1": "620063, Yekaterinburg,", + "addressLine2": "Bolshakova St., 66, apt. 6", + "mainStack": "Our core stack:", + "stackLine": "Unreal Engine 5, C++", + "requisites": "Company details:", + "inn": "TIN: 6679174128", + "kpp": "IEC: 667101001", + "company": "GRAFF.ESTATE LLC", + "ogrn": "PSRN 1246600010140", + "skolkovoAlt": "Skolkovo", + "privacy": "Privacy and personal data processing policy", + "copyright": "© 2026 GRAFF interactive FZCO. All rights reserved", + "site": "graff.tech" + }, + "demos": { + "titleLine1": "Available", + "titleLine2": "demos", + "ctaTitle": "We’ll walk you through how it works on\u00a0a call", + "ctaButton": "Request a call", + "description": "Clients anywhere in the world can explore a residential complex, even at the zero stage of construction. They can pick the best layout and assess the view from the windows of their future apartment." + }, + "streamingProject": { + "watch": "Watch", + "startDemo": "Start demo" + }, + "requestDemo": { + "titleLine1": "Book", + "titleLine2": "a remote", + "titleLine3": "demo", + "description": "A demo booking can be embedded as a block on the developer’s or residential complex’s website.", + "cta": "Request a call" + }, + "streamPlayer": { + "caption": "GRAFF.estate Stream is available on\u00a0any device — all you need for a demo is an internet connection." + }, + "feedback": { + "titleLead": "Want to improve conversion?", + "titleRest": "Let’s discuss the details." + }, + "leadForm": { + "submitError": "Could not submit the request. Please try again later.", + "needTitle": "We need", + "namePlaceholder": "Name*", + "emailPlaceholder": "Email*", + "submit": "Submit request", + "consentBefore": "*By submitting, you give", + "consentLinkData": "consent to personal data processing", + "consentMiddle": "and accept the", + "consentLinkPolicy": "policy terms" + }, + "questionModal": { + "phonePlaceholder": "+X (XXX) XXX - XX - XX" + }, + "feedbackModal": { + "successRich": "We’ve received your request and we’ll contact you soon!", + "sourcesTitle1": "Please tell us", + "sourcesTitle2": "how you heard about us", + "send": "Send", + "skip": "Skip" + }, + "products": { + "interactivePresentation": "Interactive presentation", + "remoteDemo": "Remote demonstration", + "archViz": "Architectural visualization", + "webDev": "Website development", + "webTour360": "360° web tour" + }, + "modalFeedbackSources": [ + "Saw us at an exhibition or forum", + "Saw it with other developers", + "From rankings and articles", + "Found online", + "Came from an ad", + "From a newsletter", + "Other" + ] +} diff --git a/src/landing/i18n/locales/ru.json b/src/landing/i18n/locales/ru.json new file mode 100644 index 0000000..7aa62b3 --- /dev/null +++ b/src/landing/i18n/locales/ru.json @@ -0,0 +1,94 @@ +{ + "languageSwitcher": { + "ru": "RU", + "en": "EN", + "ariaLabel": "Язык" + }, + "legalLinks": { + "privacyConsent": "https://graff.estate/privacy-policy", + "policy": "https://graff.estate/policy" + }, + "footer": { + "call": "Позвонить", + "write": "Написать", + "phoneDisplay": "8 800 770 00 67", + "phoneTel": "+78007700067", + "emailAddress": "info@graff.tech", + "legalAddress": "Юридический адрес:", + "addressLine1": "620063, г. Екатеринбург,", + "addressLine2": "ул. Большакова, д. 66, кв. 6", + "mainStack": "Наш основной стек:", + "stackLine": "Unreal Engine 5, C++", + "requisites": "Реквизиты:", + "inn": "ИНН: 6679174128", + "kpp": "КПП: 667101001", + "company": "ООО \"ГРАФФ.ЭСТЕЙТ\"", + "ogrn": "ОГРН 1246600010140", + "skolkovoAlt": "Сколково", + "privacy": "Политика конфиденциальности и обработки персональных данных", + "copyright": "© 2026 GRAFF interactive. Все права защищены", + "site": "graff.tech" + }, + "demos": { + "titleLine1": "Доступные", + "titleLine2": "демонстрации", + "ctaTitle": "Расскажем и покажем как это работает на\u00a0созвоне", + "ctaButton": "Оставить заявку", + "description": "Клиент из любой точки мира может посмотреть жилой комплекс, даже на нулевом этапе строительства. Он выберет лучшую планировку и оценит вид из окон своей будущей квартиры." + }, + "streamingProject": { + "watch": "Смотреть", + "startDemo": "Начать демонстрацию" + }, + "requestDemo": { + "titleLine1": "Запись", + "titleLine2": "на удаленную", + "titleLine3": "демонстрацию", + "description": "Запись на демонстрацию может быть оформлена в виде блока на сайте застройщика или жилого комплекса.", + "cta": "Оставить заявку" + }, + "streamPlayer": { + "caption": "Модуль удаленных продаж GRAFF.estate доступен на\u00a0любых устройствах, для\u00a0демонстрации нужен только\u00a0интернет." + }, + "feedback": { + "titleLead": "Хотите увеличить конверсию?", + "titleRest": "Давайте обсудим детали." + }, + "leadForm": { + "submitError": "Не удалось отправить заявку. Попробуйте позже.", + "needTitle": "Нам нужно", + "namePlaceholder": "Имя*", + "emailPlaceholder": "Email*", + "submit": "Оставить заявку", + "consentBefore": "*Нажимая кнопку отправить, вы даете", + "consentLinkData": "согласие на обработку персональных данных", + "consentMiddle": "и принимаете", + "consentLinkPolicy": "условия политики" + }, + "questionModal": { + "phonePlaceholder": "+X (XXX) XXX - XX - XX" + }, + "feedbackModal": { + "successRich": "Мы получили заявку и скоро свяжемся с вами!", + "sourcesTitle1": "Расскажите, пожалуйста,", + "sourcesTitle2": "откуда вы узнали о нас?", + "send": "Отправить", + "skip": "Пропустить" + }, + "products": { + "interactivePresentation": "Интерактивная презентация", + "remoteDemo": "Удаленная демонстрация", + "archViz": "Архитектурная визуализация", + "webDev": "Создание сайтов", + "webTour360": "Веб-тур по 360 сферам" + }, + "modalFeedbackSources": [ + "Увидели на выставке или форуме", + "Видели у других застройщиков", + "Из рейтингов и статей", + "Нашли в интернете", + "Перешли по рекламе", + "Из рассылки", + "Другое" + ] +} diff --git a/src/landing/landing.css b/src/landing/landing.css new file mode 100644 index 0000000..7718df3 --- /dev/null +++ b/src/landing/landing.css @@ -0,0 +1,116 @@ +@import url("/fonts/TTHovesProAll/stylesheet.css"); + +/* + * Landing-only wrapper. Applied by `src/App.tsx` (the `/` route) on the root + * container. Keeps TTHovesPro font + dark background + overflow behavior + * scoped to the landing so that /stream, /history, /scheduled pages keep + * their Inter/Gilroy styles from `src/index.css`. + */ +.landing-shell { + font-family: "TTHovesPro", system-ui, -apple-system, "Segoe UI", Roboto, + sans-serif; + color: #fff; + background-color: #0f1011; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: none; + min-width: 0; + overflow-x: clip; +} + +.landing-shell *::-webkit-scrollbar { + width: 12px; +} + +.landing-shell *::-webkit-scrollbar-thumb { + background-color: #798fff; + border: none; + border-radius: 4px; +} + +.landing-shell .scrollbar-gradient::-webkit-scrollbar-thumb { + background: linear-gradient(87deg, #798fff 15%, #d375ff 100%); +} + +.landing-shell *::-webkit-scrollbar-thumb:hover { + border-width: 2px; +} + +.landing-shell .hide-scrollbars { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.landing-shell .hide-scrollbars::-webkit-scrollbar { + width: 0; + height: 0; +} + +/* + * Landing utility classes. We don't wrap these in `@layer utilities` because + * the `@tailwind utilities` directive lives in `src/index.css` (a different + * file) and PostCSS would error on a lone `@layer utilities` declaration. + * Plain class definitions still support `@apply` fine. + */ +.line1 { + @apply 2xl:text-[128px] lg:text-[clamp(96px,96px+(100vw-1440px)/96*32,128px)] md:text-[clamp(56px,56px+(100vw-768px)/672*40,96px)] xs:text-[clamp(40px,40px+(100vw-360px)/408*16,56px)] text-[40px] leading-[85%]; + } + + .line2 { + @apply lg:text-[clamp(64px,4.444vw,88px)] md:text-[clamp(40px,40px+(100vw-768px)/672*24,64px)] xs:text-[clamp(32px,32px+(100vw-360px)/408*8,40px)] max-xs:text-[32px] leading-[95%]; + } + + .heading1 { + @apply lg:text-[clamp(28px,1.944vw,42px)] md:text-[clamp(24px,24px+(100vw-768px)/672*4,28px)] text-2xl leading-[1.167]; + } + + .heading2 { + @apply lg:text-[clamp(24px,1.667vw,36px)] md:text-[clamp(20px,20px+(100vw-768px)/672*4,24px)] xs:text-[clamp(16px,16px+(100vw-360px)/408*4,20px)] text-base lg:leading-[1.2] leading-[1.125]; + } + + .accent { + @apply lg:text-[clamp(32px,2.222vw,56px)] md:text-[clamp(24px,24px+(100vw-768px)/672*8,32px)] text-2xl lg:leading-[1.1] leading-none; + } + + .text1 { + @apply lg:text-[clamp(18px,1.25vw,24px)] md:text-[clamp(14px,14px+(100vw-768px)/672*4,18px)] text-sm leading-[1.35]; + } + + .text2 { + @apply lg:text-[clamp(12px,0.972vw,20px)] md:text-[clamp(12px,12px+(100vw-768px)/672*2,14px)] text-xs leading-[1.35]; + } + + .btnl { + @apply lg:text-[clamp(18px,1.25vw,28px)] md:text-[clamp(16px,16+(100vw-768px)/256*2,18px)] text-base leading-none; + } + + .btnm { + @apply lg:text-[clamp(16px,1.111vw,24px)] md:text-[clamp(14px,14px+(100vw-768px)/256*2,16px)] text-sm leading-none; + } + + .btns { + @apply lg:text-[clamp(14px,0.972vw,20px)] md:text-[clamp(12px,12px+(100vw-768px)/256*2,14px)] text-xs leading-none; + } + + .headline1 { + @apply font-medium text-[1.667vw] leading-[1.944vw] tracking-[-0.02em] md:max-lg:text-[3.125vw] md:max-lg:leading-[3.646vw] max-md:text-[6.667vw] max-md:leading-[7.778vw]; + } + + .headline2 { + @apply font-medium text-[1.389vw] leading-[1.667vw] tracking-[-0.02em] md:max-lg:text-[2.083vw] md:max-lg:leading-[2.344vw] max-md:text-base max-md:leading-[4.444vw] max-md:font-normal; + } + + /* + * `.bg-gradient` is already defined globally in `src/index.css` with a + * slightly different angle and `!important` — we reuse it here and skip + * redeclaring to avoid fighting the cascade. + */ + + .bg-gradient-saturated { + background: linear-gradient(45deg, #7a55ff 0%, #c932e8 75%, #ff79d2 95%); + } + +@media screen and (max-device-width: 480px) { + .landing-shell { + -webkit-text-size-adjust: 100%; + } +} diff --git a/src/landing/lib/api.ts b/src/landing/lib/api.ts new file mode 100644 index 0000000..e425c82 --- /dev/null +++ b/src/landing/lib/api.ts @@ -0,0 +1,15 @@ +import ky from "ky"; + +function str(v: unknown): string { + return typeof v === "string" ? v.trim() : ""; +} + +const raw = str(import.meta.env.VITE_API_URL); +const base = raw ? raw.replace(/\/?$/, "/") : ""; + +export const hasApiConfigured = base.length > 0; + +export const api = ky.create({ + prefixUrl: base || undefined, + credentials: "include", +}); diff --git a/src/landing/lib/phoneRu.ts b/src/landing/lib/phoneRu.ts new file mode 100644 index 0000000..78235b7 --- /dev/null +++ b/src/landing/lib/phoneRu.ts @@ -0,0 +1,64 @@ +import { getExampleNumber } from "libphonenumber-js"; +import examples from "libphonenumber-js/mobile/examples"; + +export const PHONE_CODE_RU = "+7"; +export const PHONE_COUNTRY_RU = "RU" as const; + +/** Локальная часть примера номера (без кода страны) для маски */ +export function getRuMobileExampleLocal(): string | undefined { + return getExampleNumber(PHONE_COUNTRY_RU, examples) + ?.formatInternational() + .split(" ") + .slice(1) + .join(" "); +} + +export function buildRuPhoneMask(placeholderLocal: string | undefined): string { + return `${PHONE_CODE_RU} ${(placeholderLocal?.replace(/\d/g, "9") ?? "")}`; +} + +/** Только цифры: 7 + до 10 цифр номера (без +) */ +export function ruPhoneDigits(stored: string): string { + let d = stored.replace(/\D/g, ""); + if (d.startsWith("8")) d = "7" + d.slice(1); + if (d.length === 0) return ""; + if (!d.startsWith("7")) d = "7" + d; + return d.slice(0, 11); +} + +/** Отображение +7 (XXX) XXX-XX-XX без react-input-mask (совместимо с React 19) */ +export function formatRuPhoneDisplay(stored: string): string { + const d = ruPhoneDigits(stored); + if (!d) return ""; + const n = d.slice(1); + if (n.length === 0) return "+7"; + + const a = n.slice(0, 3); + const b = n.slice(3, 6); + const c = n.slice(6, 8); + const e = n.slice(8, 10); + + let s = "+7 (" + a; + if (n.length <= 3) return s; + s += ") " + b; + if (n.length <= 6) return s; + s += "-" + c; + if (n.length <= 8) return s; + s += "-" + e; + return s; +} + +export function normalizeRuPhoneFromInput( + cleanValue: string, + inputType: string | undefined +): string { + const shouldAddPhoneCode = + inputType !== "insertFromPaste" && + inputType !== "insertFromDrop" && + inputType !== "insertCompositionText" && + !cleanValue.startsWith("+") && + !cleanValue.startsWith("7") && + !cleanValue.startsWith(PHONE_CODE_RU.replace("+", "")); + + return (shouldAddPhoneCode ? PHONE_CODE_RU : "") + cleanValue; +} diff --git a/src/landing/lib/productLabels.ts b/src/landing/lib/productLabels.ts new file mode 100644 index 0000000..3951cf9 --- /dev/null +++ b/src/landing/lib/productLabels.ts @@ -0,0 +1,14 @@ +import type { TFunction } from "i18next"; + +/** Order of product checkboxes in lead forms. */ +export const PRODUCT_I18N_KEYS = [ + "products.interactivePresentation", + "products.remoteDemo", + "products.archViz", + "products.webDev", + "products.webTour360", +] as const; + +export function productOptionsFromT(t: TFunction): string[] { + return PRODUCT_I18N_KEYS.map((key) => t(key)); +} diff --git a/src/landing/lib/resolveProjectImageSrc.ts b/src/landing/lib/resolveProjectImageSrc.ts new file mode 100644 index 0000000..ed2e2c0 --- /dev/null +++ b/src/landing/lib/resolveProjectImageSrc.ts @@ -0,0 +1,43 @@ +/** + * Как на основном сайте: в API может прийти уже полный URL + * (`https://storage.yandexcloud.net/bucket/projects/uuid.jpg`) или ключ + * (`projects/uuid.jpg`) — тогда к нему дописывается VITE_S3_BUCKET. + */ +export function resolveProjectImageSrc(image: string): string { + let src = image + .trim() + .replaceAll(""", '"') + .replace(/^["']+|["']+$/g, ""); + + try { + if (src.includes("%")) src = decodeURIComponent(src); + } catch { + /* оставляем как есть */ + } + + if (src.startsWith("//")) { + src = `https:${src}`; + } + if ( + src.startsWith("http://") || + src.startsWith("https://") || + src.startsWith("data:") + ) { + return src; + } + + if (src.startsWith("/")) { + const base = import.meta.env.BASE_URL; + if (!base || base === "/") return src; + return `${base.replace(/\/$/, "")}${src}`; + } + + const s3BaseRaw = + typeof import.meta.env.VITE_S3_BUCKET === "string" + ? import.meta.env.VITE_S3_BUCKET.trim() + : ""; + if (!s3BaseRaw) return src; + const base = s3BaseRaw.replace(/\/?$/, "/"); + const path = src.replace(/^\//, ""); + return `${base}${path}`; +} diff --git a/src/landing/lib/streamDemoUrl.ts b/src/landing/lib/streamDemoUrl.ts new file mode 100644 index 0000000..8db2e78 --- /dev/null +++ b/src/landing/lib/streamDemoUrl.ts @@ -0,0 +1,14 @@ +/** + * Строим ссылку запуска демо-стрима. + * + * Ничего не захардкоживаем: клиент сам обслуживается на stream.graff.tech, + * поэтому используем относительный путь — навигация остаётся в том же origin, + * а `useAutoStartFromQuery` на маршруте `/` подхватит `?build=...` и + * отредиректит на `/stream/:id`. + */ +export function streamDemoUrlFromBuild(buildFilename: string): string { + const build = buildFilename.trim(); + const params = new URLSearchParams({ location: "a1" }); + if (build) params.set("build", build); + return `/?${params.toString()}`; +} diff --git a/src/landing/lib/urlLang.ts b/src/landing/lib/urlLang.ts new file mode 100644 index 0000000..89dcb0c --- /dev/null +++ b/src/landing/lib/urlLang.ts @@ -0,0 +1,15 @@ +import type { AppLocale } from "@/landing/i18n"; + +export function parseLangParam(v: string | null): AppLocale | null { + const x = v?.trim().toLowerCase(); + if (x === "ru" || x === "en") return x; + return null; +} + +/** Updates `?lang=` without reload; fires `locationchange` for listeners. */ +export function setLangInUrl(lang: AppLocale): void { + const url = new URL(window.location.href); + url.searchParams.set("lang", lang); + window.history.replaceState({}, "", url.toString()); + window.dispatchEvent(new Event("locationchange")); +} diff --git a/src/landing/queries/getCountryCode.ts b/src/landing/queries/getCountryCode.ts new file mode 100644 index 0000000..83a1abf --- /dev/null +++ b/src/landing/queries/getCountryCode.ts @@ -0,0 +1,32 @@ +import { useQuery } from "@tanstack/react-query"; +import ky from "ky"; +import { useLocationSearch } from "@/landing/hooks/useLocationSearch"; +import { parseLangParam } from "@/landing/lib/urlLang"; +import { queryKeys } from "@/landing/queries/keys"; + +/* + * Клиент обслуживается на том же origin, что и API, поэтому ходим + * относительным путём `/api/getCountryCode` — так запрос не привязан к + * конкретному домену stream.graff.tech и корректно работает под любым + * окружением (локальный vite-proxy, staging, prod). + */ +const COUNTRY_CODE_URL = "/api/getCountryCode"; + +export async function fetchCountryCode(): Promise<{ countryCode: string }> { + return ky.get(COUNTRY_CODE_URL).json<{ countryCode: string }>(); +} + +export function useCountryCodeQuery() { + const search = useLocationSearch(); + const langFromUrl = parseLangParam( + new URLSearchParams(search).get("lang") + ); + + return useQuery({ + queryKey: queryKeys.countryCode, + queryFn: fetchCountryCode, + enabled: langFromUrl === null, + staleTime: 24 * 60 * 60 * 1000, + retry: 2, + }); +} diff --git a/src/landing/queries/keys.ts b/src/landing/queries/keys.ts new file mode 100644 index 0000000..dcfe023 --- /dev/null +++ b/src/landing/queries/keys.ts @@ -0,0 +1,3 @@ +export const queryKeys = { + countryCode: ["countryCode"] as const, +}; diff --git a/src/landing/stores/useModalStore.ts b/src/landing/stores/useModalStore.ts new file mode 100644 index 0000000..bde5ffc --- /dev/null +++ b/src/landing/stores/useModalStore.ts @@ -0,0 +1,12 @@ +import { ReactNode } from "react"; +import { create } from "zustand"; + +interface IModalState { + modal: ReactNode | null; + setModal: (modal: ReactNode | null) => void; +} + +export const useModalStore = create((set) => ({ + modal: null, + setModal: (modal) => set({ modal }), +})); diff --git a/src/landing/stores/useRefererStore.ts b/src/landing/stores/useRefererStore.ts new file mode 100644 index 0000000..3d8d8bb --- /dev/null +++ b/src/landing/stores/useRefererStore.ts @@ -0,0 +1,17 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; + +export const useRefererStore = create<{ + referer: string | null; + setReferer: (referer: string | null) => void; +}>()( + persist( + (set) => ({ + referer: null, + setReferer: (referer) => set({ referer }), + }), + { + name: "referer-stream-demo", + } + ) +); diff --git a/src/landing/types/ICompany.ts b/src/landing/types/ICompany.ts new file mode 100644 index 0000000..740e01a --- /dev/null +++ b/src/landing/types/ICompany.ts @@ -0,0 +1,10 @@ +import { IProject } from "./IProject"; + +export interface ICompany { + id: string; + title: string; + color: string; + mapIcon?: string; + logo?: string; + projects: IProject[]; +} diff --git a/src/landing/types/IProject.ts b/src/landing/types/IProject.ts new file mode 100644 index 0000000..235170d --- /dev/null +++ b/src/landing/types/IProject.ts @@ -0,0 +1,21 @@ +import { ICompany } from "./ICompany"; +import { Product } from "./Product"; + +export type Device = "Stream" | "Touch" | "Mobile" | "VR"; + +export interface IProject { + id: string; + title: string; + englishTitle: string; + description: string; + company?: ICompany; + companyId?: string; + city: string; + englishCity: string; + image: string; + /** Имя билда для URL-параметра `?build=...` на главной клиента. */ + buildFilename?: string; + stage: number; + releaseDate: string; + tags: Product[]; +} diff --git a/src/landing/types/Product.ts b/src/landing/types/Product.ts new file mode 100644 index 0000000..2d9c946 --- /dev/null +++ b/src/landing/types/Product.ts @@ -0,0 +1,2 @@ +/** Localized product label in the API payload (matches `t('products.*')` for the active locale). */ +export type Product = string; diff --git a/src/landing/types/index.ts b/src/landing/types/index.ts new file mode 100644 index 0000000..9450f61 --- /dev/null +++ b/src/landing/types/index.ts @@ -0,0 +1,3 @@ +export type { ICompany } from "./ICompany"; +export type { Device, IProject } from "./IProject"; +export type { Product } from "./Product"; diff --git a/src/landing/ui/Button.tsx b/src/landing/ui/Button.tsx new file mode 100644 index 0000000..f751625 --- /dev/null +++ b/src/landing/ui/Button.tsx @@ -0,0 +1,53 @@ +import { type ReactElement, type ReactNode } from "react"; + +interface ButtonProps { + children: ReactNode; + icon?: ReactElement; + color?: "primary" | "secondary"; + width?: "fit" | "full"; + disabled?: boolean; + className?: string; + onClick?: () => void; + type?: "submit" | "reset" | "button"; + rounded?: string; +} + +export function Button({ + children, + color = "primary", + icon, + width = "fit", + disabled = false, + className, + onClick, + type, + rounded, +}: ButtonProps) { + const widthClass = width === "full" ? "w-full" : "w-fit"; + return ( + + ); +} diff --git a/src/landing/ui/CheckboxesGroup.tsx b/src/landing/ui/CheckboxesGroup.tsx new file mode 100644 index 0000000..a32e34f --- /dev/null +++ b/src/landing/ui/CheckboxesGroup.tsx @@ -0,0 +1,56 @@ +import { + FieldValues, + Path, + useController, + useFormContext, + useWatch, +} from "react-hook-form"; + +export function CheckboxesGroup({ + options, + name, +}: { + options: string[]; + name: Path; +}) { + const { control } = useFormContext(); + + const { + field: { ref, onChange, ...inputProps }, + } = useController({ control, name }); + + const values: string[] = useWatch({ control, name }); + + return ( +
+ {options.map((option) => ( + + ))} +
+ ); +} diff --git a/src/landing/ui/CustomCheckbox.tsx b/src/landing/ui/CustomCheckbox.tsx new file mode 100644 index 0000000..8868662 --- /dev/null +++ b/src/landing/ui/CustomCheckbox.tsx @@ -0,0 +1,40 @@ +import { useEffect, useState } from "react"; +import CheckIcon from "@/landing/components/icons/CheckIcon"; + +function CustomCheckbox({ + value, + onChange, +}: { + value: string; + onChange: (value: string, checked: boolean) => void; +}) { + const [checked, setChecked] = useState(false); + + useEffect(() => { + onChange(value, checked); + }, [checked, onChange, value]); + + return ( + <> +
setChecked(!checked)} + className="flex gap-x-[10px] items-center hover:cursor-pointer" + > +
+ {checked && ( +
+ +
+ )} +
+ {value} +
+ + ); +} + +export default CustomCheckbox; diff --git a/src/landing/ui/PhoneInputRu.tsx b/src/landing/ui/PhoneInputRu.tsx new file mode 100644 index 0000000..082f0e5 --- /dev/null +++ b/src/landing/ui/PhoneInputRu.tsx @@ -0,0 +1,45 @@ +import { type Ref } from "react"; +import { + formatRuPhoneDisplay, + normalizeRuPhoneFromInput, +} from "@/landing/lib/phoneRu"; + +const inputClassName = + "placeholder:btnl placeholder:font-medium placeholder:select-none peer btnl w-full h-full bg-transparent rounded-none transition-all outline-none"; + +interface PhoneInputRuProps { + value: string; + onChange: (value: string) => void; + onBlur?: () => void; + inputRef?: Ref; + id?: string; + placeholder?: string; +} + +export function PhoneInputRu({ + value, + onChange, + onBlur, + inputRef, + id = "tel", + placeholder = "+7 (XXX) XXX - XX - XX", +}: PhoneInputRuProps) { + return ( + { + if (!e.nativeEvent.type.startsWith("input")) return; + const cleanValue = e.target.value.replace(/\s/g, ""); + const inputType = (e.nativeEvent as InputEvent).inputType; + onChange(normalizeRuPhoneFromInput(cleanValue, inputType)); + }} + /> + ); +} diff --git a/src/landing/ui/VideoMutingBtn.tsx b/src/landing/ui/VideoMutingBtn.tsx new file mode 100644 index 0000000..6ed2869 --- /dev/null +++ b/src/landing/ui/VideoMutingBtn.tsx @@ -0,0 +1,48 @@ +import { useEffect, useRef, useState } from "react"; +import MuteIcon from "@/landing/components/icons/MuteIcon"; +import UnmutedIcon from "@/landing/components/icons/UnmutedIcon"; + +export function VideoMutingBtn({ + handleClick, + muted, +}: { + muted: boolean; + handleClick: () => void; +}) { + const ref = useRef(null); + + const [point, setPoint] = useState([0, 0]); + + useEffect(() => { + const el = ref.current; + const move = (e: MouseEvent) => setPoint([e.clientX, e.clientY]); + el?.addEventListener("mousemove", move); + + return () => { + el?.removeEventListener("mousemove", move); + }; + }, []); + + return ( +
+
+ +
+
+ ); +} diff --git a/src/landing/ui/VideoPlayer.tsx b/src/landing/ui/VideoPlayer.tsx new file mode 100644 index 0000000..5d455b3 --- /dev/null +++ b/src/landing/ui/VideoPlayer.tsx @@ -0,0 +1,115 @@ +import { AnimatePresence, motion } from "framer-motion"; +import { + ComponentProps, + forwardRef, + useEffect, + useImperativeHandle, + useRef, + useState, +} from "react"; +import { VideoMutingBtn } from "./VideoMutingBtn"; +import { VideoProgressBar } from "./VideoProgressBar"; + +export const VideoPlayer = forwardRef< + HTMLVideoElement, + { + src: string; + showMutingBtn: boolean; + children?: React.ReactNode; + } & ComponentProps<"video"> +>( + ( + { + src, + showMutingBtn, + children, + loop = true, + autoPlay = true, + className, + muted: mutedProp, + }, + ref + ) => { + const progressbarRef = useRef(null); + const videoRef = useRef(null); + + useImperativeHandle(ref, () => videoRef.current!); + + /** Начальное значение из `muted`; дальше громкость только из состояния (кнопка плеера). */ + const [muted, setMuted] = useState(() => mutedProp ?? autoPlay); + const [playing, setPlaying] = useState(autoPlay); + const [progress, setProgress] = useState(0); + + function handleProgressbarClick(e: React.MouseEvent) { + const video = videoRef.current; + const bar = progressbarRef.current; + if (!video || !bar) return; + video.currentTime = + (video.duration * (e.clientX - bar.getBoundingClientRect().x)) / + bar.clientWidth; + setProgress( + ((video.currentTime ?? 0) / (video.duration ?? 1)) * 100 + ); + } + + function handlePlaybackClick() { + if (!videoRef.current) return; + setPlaying(videoRef.current.paused); + videoRef.current[videoRef.current.paused ? "play" : "pause"](); + } + + useEffect(() => { + const video = videoRef.current; + if (!video) return; + const timeUpdateHandler = () => + setProgress(((video.currentTime ?? 0) / (video.duration ?? 1)) * 100); + + video.addEventListener("timeupdate", timeUpdateHandler); + return () => video.removeEventListener("timeupdate", timeUpdateHandler); + }, []); + + return ( +
+