mirror of
https://github.com/shadps4-emu/shadPS4-launcher.git
synced 2026-01-31 00:55:20 +01:00
style: replaced prettier/eslint to biomejs
This commit is contained in:
@@ -1 +0,0 @@
|
||||
src-tauri/
|
||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||
}
|
||||
|
||||
135
biome.jsonc
Normal file
135
biome.jsonc
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"$schema": "https://next.biomejs.dev/schemas/2.0.0-beta/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false,
|
||||
"includes": ["**/*.tsx", "**/*.jsx", "!dist/**", "!src-tauri"],
|
||||
},
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"recommended": true,
|
||||
"source": {
|
||||
"useSortedAttributes": "on",
|
||||
},
|
||||
},
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 4,
|
||||
"lineEnding": "lf",
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"complexity": {
|
||||
"noUselessThisAlias": "error",
|
||||
"noUselessTypeConstraint": "error",
|
||||
"useArrowFunction": "off",
|
||||
"useLiteralKeys": "error",
|
||||
"useOptionalChain": "error",
|
||||
},
|
||||
"correctness": {
|
||||
"noConstAssign": "error",
|
||||
"noGlobalObjectCalls": "off",
|
||||
"noInvalidBuiltinInstantiation": "off",
|
||||
"noInvalidConstructorSuper": "off",
|
||||
"noNewSymbol": "off",
|
||||
"noSetterReturn": "off",
|
||||
"noUndeclaredVariables": "off",
|
||||
"noUnreachable": "off",
|
||||
"noUnreachableSuper": "off",
|
||||
"noUnusedVariables": "error",
|
||||
"noUnusedImports": "error",
|
||||
"useArrayLiterals": "off",
|
||||
"useExhaustiveDependencies": "warn",
|
||||
"useHookAtTopLevel": "error",
|
||||
},
|
||||
"style": {
|
||||
"noArguments": "error",
|
||||
"noInferrableTypes": "error",
|
||||
"noNamespace": "error",
|
||||
"useAsConstAssertion": "error",
|
||||
"useBlockStatements": "warn",
|
||||
"useConsistentArrayType": "error",
|
||||
"useConst": "error",
|
||||
"useForOf": "error",
|
||||
"useImportType": "error",
|
||||
"useShorthandFunctionType": "error",
|
||||
"useThrowOnlyError": "error",
|
||||
"useFilenamingConvention": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"strictCase": true,
|
||||
"requireAscii": true,
|
||||
"filenameCases": ["kebab-case"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"suspicious": {
|
||||
"noClassAssign": "off",
|
||||
"noDuplicateClassMembers": "off",
|
||||
"noDuplicateObjectKeys": "off",
|
||||
"noDuplicateParameters": "off",
|
||||
"noEmptyBlockStatements": "error",
|
||||
"noExplicitAny": "error",
|
||||
"noExtraNonNullAssertion": "error",
|
||||
"noVar": "error",
|
||||
"noFunctionAssign": "off",
|
||||
"noImportAssign": "off",
|
||||
"noMisleadingInstantiator": "error",
|
||||
"noRedeclare": "off",
|
||||
"noUnsafeDeclarationMerging": "error",
|
||||
"noUnsafeNegation": "off",
|
||||
"useAwait": "error",
|
||||
"useGetterReturn": "off",
|
||||
"useNamespaceKeyword": "error",
|
||||
},
|
||||
"nursery": {
|
||||
"useSortedClasses": "warn",
|
||||
},
|
||||
"a11y": {
|
||||
"useKeyWithClickEvents": "off",
|
||||
},
|
||||
},
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
"semicolons": "always",
|
||||
"trailingCommas": "all",
|
||||
},
|
||||
"globals": [],
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"trailingCommas": "all",
|
||||
},
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["src/hooks/**/*.tsx"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"style": {
|
||||
"useFilenamingConvention": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"strictCase": true,
|
||||
"requireAscii": true,
|
||||
"match": "use.*",
|
||||
"filenameCases": ["camelCase"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
735
bun.lock
735
bun.lock
@@ -7,11 +7,12 @@
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/vite": "^4.0.17",
|
||||
"@tanstack/query-core": "^5.67.2",
|
||||
"@tanstack/react-query": "^5.67.2",
|
||||
"@tauri-apps/api": "^2",
|
||||
@@ -29,48 +30,34 @@
|
||||
"jotai": "^2.11.1",
|
||||
"jotai-optics": "^0.4.0",
|
||||
"jotai-tanstack-query": "^0.9.0",
|
||||
"lucide-react": "^0.474.0",
|
||||
"lucide-react": "^0.485.0",
|
||||
"next-themes": "^0.4.5",
|
||||
"octokit": "^4.1.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sonner": "^2.0.1",
|
||||
"superjson": "^2.2.2",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||
"@biomejs/biome": "2.0.0-beta.1",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/node": "^22.12.0",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
||||
"@typescript-eslint/parser": "^8.22.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"postcss": "^8.5.1",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss": "3",
|
||||
"tailwindcss": "^4.0.17",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"@biomejs/biome",
|
||||
],
|
||||
"packages": {
|
||||
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
||||
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
"@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
|
||||
@@ -109,23 +96,23 @@
|
||||
|
||||
"@babel/types": ["@babel/types@7.26.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA=="],
|
||||
|
||||
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
|
||||
"@biomejs/biome": ["@biomejs/biome@2.0.0-beta.1", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0-beta.1", "@biomejs/cli-darwin-x64": "2.0.0-beta.1", "@biomejs/cli-linux-arm64": "2.0.0-beta.1", "@biomejs/cli-linux-arm64-musl": "2.0.0-beta.1", "@biomejs/cli-linux-x64": "2.0.0-beta.1", "@biomejs/cli-linux-x64-musl": "2.0.0-beta.1", "@biomejs/cli-win32-arm64": "2.0.0-beta.1", "@biomejs/cli-win32-x64": "2.0.0-beta.1" }, "bin": { "biome": "bin/biome" } }, "sha512-MqRoy9CbTkrS45zW+S4u8p4kQUIFx0mGUWi789W1R3b1kXYIudEqsTKgXKtTGsI0kWOlvnjuKqwTrabjaGchhQ=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0-beta.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RaGmpNLl5NFooXaoCwvgvcuU6Am/rMZ3R48pQeCVxjrCcz1BIlKLTai5UosiedazW7JbXAvgXdSNizYG7ITlAQ=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0-beta.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-sTzSshkne7HKZFNfiIhmAji7gjtCBXvkTujZELCZWIZC7oj1Tjw/gvAzbdFj2UyHd5/i90pND4ybFOLQZm9gpg=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0-beta.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-bxce2O4nooBmp20Ey0+IFIZyy/b0RVnciIQk9euCfAi9evq7SvFtMBYo3YUZej0KIvrau5H7tJk5OqmRJk2l+g=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0-beta.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-0MPUKzz9uBBxAYSJ+OlFi4+yGwiRcZeFqq39H0MxXCQ9MMpKJFH2Ek72fw8sXwG7Prn7EsW/3u1b7najyn1XGQ=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0-beta.1", "", { "os": "linux", "cpu": "x64" }, "sha512-6P/AtJv4hOH8mu8ez0c4UInUpiet9NEoF25+O7OPyb4w6ZHJMp2qzvayJS7TKrTQzE5KUvSiNsACGRz34DzUkg=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0-beta.1", "", { "os": "linux", "cpu": "x64" }, "sha512-dFvisnP1hFpVILNw0PZfs8piBwe8+aykO04Tb/4AJDVVzKkGgJfwSefwo4jqzO/Wk/Zruvhcp1nKbjgRXM+vDg=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0-beta.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-0C9YSqWHf2cJGnjKDbLi49xv6H9IfqbDsFav7X557PqwY64O6IKWqcmZzi/PkDFHjQM9opU6uhKapeGKGDxziQ=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0-beta.1", "", { "os": "win32", "cpu": "x64" }, "sha512-o8W6+DX0YRjt1kS8Y3ismq6EkjwiVDv7X0TEpfnFywoVG8HoJ7G7/m9r8LM1yE46WI3maPH2A0MoVpQ1ZNG++A=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="],
|
||||
|
||||
@@ -177,24 +164,6 @@
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA=="],
|
||||
|
||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
||||
|
||||
"@eslint/compat": ["@eslint/compat@1.2.6", "", { "peerDependencies": { "eslint": "^9.10.0" }, "optionalPeers": ["eslint"] }, "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q=="],
|
||||
|
||||
"@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="],
|
||||
|
||||
"@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="],
|
||||
|
||||
"@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.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" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="],
|
||||
|
||||
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
|
||||
|
||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="],
|
||||
|
||||
"@floating-ui/core": ["@floating-ui/core@1.6.9", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw=="],
|
||||
|
||||
"@floating-ui/dom": ["@floating-ui/dom@1.6.13", "", { "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.9" } }, "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w=="],
|
||||
@@ -203,18 +172,6 @@
|
||||
|
||||
"@floating-ui/utils": ["@floating-ui/utils@0.2.9", "", {}, "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="],
|
||||
|
||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||
|
||||
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
|
||||
|
||||
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="],
|
||||
|
||||
"@ianvs/prettier-plugin-sort-imports": ["@ianvs/prettier-plugin-sort-imports@4.4.1", "", { "dependencies": { "@babel/generator": "^7.26.2", "@babel/parser": "^7.26.2", "@babel/traverse": "^7.25.9", "@babel/types": "^7.26.0", "semver": "^7.5.2" }, "peerDependencies": { "@vue/compiler-sfc": "2.7.x || 3.x", "prettier": "2 || 3" }, "optionalPeers": ["@vue/compiler-sfc"] }, "sha512-F0/Hrcfpy8WuxlQyAWJTEren/uxKhYonOGY4OyWmwRdeTvkh9mMSCxowZLjNkhwi/2ipqCgtXwwOk7tW0mWXkA=="],
|
||||
|
||||
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "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" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
@@ -225,12 +182,6 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@octokit/app": ["@octokit/app@15.1.5", "", { "dependencies": { "@octokit/auth-app": "^7.1.5", "@octokit/auth-unauthenticated": "^6.1.2", "@octokit/core": "^6.1.4", "@octokit/oauth-app": "^7.1.6", "@octokit/plugin-paginate-rest": "^11.4.2", "@octokit/types": "^13.8.0", "@octokit/webhooks": "^13.6.1" } }, "sha512-6cxLT9U8x7GGQ7lNWsKtFr4ccg9oLkGvowk373sX9HvX5U37kql5d55SzaQUxPE8PwgX2cqkzDm5NF5aPKevqg=="],
|
||||
|
||||
"@octokit/auth-app": ["@octokit/auth-app@7.1.5", "", { "dependencies": { "@octokit/auth-oauth-app": "^8.1.3", "@octokit/auth-oauth-user": "^5.1.3", "@octokit/request": "^9.2.1", "@octokit/request-error": "^6.1.7", "@octokit/types": "^13.8.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" } }, "sha512-boklS4E6LpbA3nRx+SU2fRKRGZJdOGoSZne/i3Y0B5rfHOcGwFgcXrwDLdtbv4igfDSnAkZaoNBv1GYjPDKRNw=="],
|
||||
@@ -281,10 +232,6 @@
|
||||
|
||||
"@octokit/webhooks-methods": ["@octokit/webhooks-methods@5.1.1", "", {}, "sha512-NGlEHZDseJTCj8TMMFehzwa9g7On4KJMPVHDSrHxCQumL6uSQR8wIkP/qesv52fXqV1BPf4pTxwtS31ldAt9Xg=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
"@pkgr/core": ["@pkgr/core@0.1.1", "", {}, "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.0", "", {}, "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="],
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
|
||||
@@ -389,7 +336,33 @@
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.6", "", { "os": "win32", "cpu": "x64" }, "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w=="],
|
||||
|
||||
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.0.17", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "tailwindcss": "4.0.17" } }, "sha512-LIdNwcqyY7578VpofXyqjH6f+3fP4nrz7FBLki5HpzqjYfXdF2m/eW18ZfoKePtDGg90Bvvfpov9d2gy5XVCbg=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.17", "@tailwindcss/oxide-darwin-arm64": "4.0.17", "@tailwindcss/oxide-darwin-x64": "4.0.17", "@tailwindcss/oxide-freebsd-x64": "4.0.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.17", "@tailwindcss/oxide-linux-arm64-musl": "4.0.17", "@tailwindcss/oxide-linux-x64-gnu": "4.0.17", "@tailwindcss/oxide-linux-x64-musl": "4.0.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.17", "@tailwindcss/oxide-win32-x64-msvc": "4.0.17" } }, "sha512-B4OaUIRD2uVrULpAD1Yksx2+wNarQr2rQh65nXqaqbLY1jCd8fO+3KLh/+TH4Hzh2NTHQvgxVbPdUDOtLk7vAw=="],
|
||||
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.17", "", { "os": "android", "cpu": "arm64" }, "sha512-3RfO0ZK64WAhop+EbHeyxGThyDr/fYhxPzDbEQjD2+v7ZhKTb2svTWy+KK+J1PHATus2/CQGAGp7pHY/8M8ugg=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-e1uayxFQCCDuzTk9s8q7MC5jFN42IY7nzcr5n0Mw/AcUHwD6JaBkXnATkD924ZsHyPDvddnusIEvkgLd2CiREg=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-d6z7HSdOKfXQ0HPlVx1jduUf/YtBuCCtEDIEFeBCzgRRtDsUuRtofPqxIVaSCUTOk5+OfRLonje6n9dF6AH8wQ=="],
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EjrVa6lx3wzXz3l5MsdOGtYIsRjgs5Mru6lDv4RuiXpguWeOb3UzGJ7vw7PEzcFadKNvNslEQqoAABeMezprxQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.17", "", { "os": "linux", "cpu": "arm" }, "sha512-65zXfCOdi8wuaY0Ye6qMR5LAXokHYtrGvo9t/NmxvSZtCCitXV/gzJ/WP5ksXPhff1SV5rov0S+ZIZU+/4eyCQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-+aaq6hJ8ioTdbJV5IA1WjWgLmun4T7eYLTvJIToiXLHy5JzUERRbIZjAcjgK9qXMwnvuu7rqpxzej+hGoEcG5g=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-/FhWgZCdUGAeYHYnZKekiOC0aXFiBIoNCA0bwzkICiMYS5Rtx2KxFfMUXQVnl4uZRblG5ypt5vpPhVaXgGk80w=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.17", "", { "os": "linux", "cpu": "x64" }, "sha512-gELJzOHK6GDoIpm/539Golvk+QWZjxQcbkKq9eB2kzNkOvrP0xc5UPgO9bIMNt1M48mO8ZeNenCMGt6tfkvVBg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.17", "", { "os": "linux", "cpu": "x64" }, "sha512-68NwxcJrZn94IOW4TysMIbYv5AlM6So1luTlbYUDIGnKma1yTFGBRNEJ+SacJ3PZE2rgcTBNRHX1TB4EQ/XEHw=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-AkBO8efP2/7wkEXkNlXzRD4f/7WerqKHlc6PWb5v0jGbbm22DFBLbIM19IJQ3b+tNewQZa+WnPOaGm0SmwMNjw=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.17", "", { "os": "win32", "cpu": "x64" }, "sha512-7/DTEvXcoWlqX0dAlcN0zlmcEu9xSermuo7VNGX9tJ3nYMdo735SHvbrHDln1+LYfF6NhJ3hjbpbjkMOAGmkDg=="],
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.0.17", "", { "dependencies": { "@tailwindcss/node": "4.0.17", "@tailwindcss/oxide": "4.0.17", "lightningcss": "1.29.2", "tailwindcss": "4.0.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-HJbBYDlDVg5cvYZzECb6xwc1IDCEM3uJi3hEZp3BjZGCNGJcTsnCpan+z+VMW0zo6gR0U6O6ElqU1OoZ74Dhww=="],
|
||||
|
||||
"@tanstack/query-core": ["@tanstack/query-core@5.67.2", "", {}, "sha512-+iaFJ/pt8TaApCk6LuZ0WHS/ECVfTzrxDOEL9HH9Dayyb5OVuomLzDXeSaI2GlGT/8HN7bDGiRXDts3LV+u6ww=="],
|
||||
|
||||
@@ -447,358 +420,66 @@
|
||||
|
||||
"@types/gensync": ["@types/gensync@1.0.4", "", {}, "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
|
||||
|
||||
"@types/node": ["@types/node@22.13.1", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="],
|
||||
|
||||
"@types/react": ["@types/react@19.0.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw=="],
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@19.0.3", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.23.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/type-utils": "8.23.0", "@typescript-eslint/utils": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.23.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/types": "8.23.0", "@typescript-eslint/typescript-estree": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q=="],
|
||||
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0" } }, "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw=="],
|
||||
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.23.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.23.0", "@typescript-eslint/utils": "8.23.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA=="],
|
||||
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.23.0", "", {}, "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ=="],
|
||||
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.23.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/types": "8.23.0", "@typescript-eslint/typescript-estree": "8.23.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
|
||||
|
||||
"acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
||||
|
||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||
|
||||
"arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
|
||||
|
||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"aria-hidden": ["aria-hidden@1.2.4", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A=="],
|
||||
|
||||
"array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
|
||||
|
||||
"array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="],
|
||||
|
||||
"array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="],
|
||||
|
||||
"array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ=="],
|
||||
|
||||
"array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="],
|
||||
|
||||
"array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="],
|
||||
|
||||
"array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="],
|
||||
|
||||
"arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],
|
||||
|
||||
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
|
||||
|
||||
"autoprefixer": ["autoprefixer@10.4.20", "", { "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g=="],
|
||||
|
||||
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"before-after-hook": ["before-after-hook@3.0.2", "", {}, "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="],
|
||||
|
||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||
|
||||
"bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
|
||||
|
||||
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
||||
|
||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g=="],
|
||||
|
||||
"call-bound": ["call-bound@1.0.3", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "get-intrinsic": "^1.2.6" } }, "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA=="],
|
||||
|
||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||
|
||||
"camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001698", "", {}, "sha512-xJ3km2oiG/MbNU8G6zIq6XRZ6HtAOVXsbOrP/blGazi52kc5Yy7b6sDA5O+FbROzRrV7BSTllLHuNvmawYUJjw=="],
|
||||
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"chokidar": ["chokidar@3.6.0", "", { "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" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
|
||||
|
||||
"data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="],
|
||||
|
||||
"data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="],
|
||||
|
||||
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
|
||||
|
||||
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||
|
||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||
|
||||
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
|
||||
|
||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
||||
|
||||
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||
|
||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
||||
|
||||
"didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="],
|
||||
|
||||
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
|
||||
|
||||
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.96", "", {}, "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||
|
||||
"es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="],
|
||||
|
||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
|
||||
"es-shim-unscopables": ["es-shim-unscopables@1.0.2", "", { "dependencies": { "hasown": "^2.0.0" } }, "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw=="],
|
||||
|
||||
"es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@9.20.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA=="],
|
||||
|
||||
"eslint-config-prettier": ["eslint-config-prettier@10.0.1", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "build/bin/cli.js" } }, "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw=="],
|
||||
|
||||
"eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="],
|
||||
|
||||
"eslint-module-utils": ["eslint-module-utils@2.12.0", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg=="],
|
||||
|
||||
"eslint-plugin-import": ["eslint-plugin-import@2.31.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.0", "hasown": "^2.0.2", "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.0", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A=="],
|
||||
|
||||
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.2.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": "*", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw=="],
|
||||
|
||||
"eslint-plugin-react": ["eslint-plugin-react@7.37.4", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ=="],
|
||||
|
||||
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.1.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="],
|
||||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
|
||||
|
||||
"espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="],
|
||||
|
||||
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"fast-content-type-parse": ["fast-content-type-parse@2.0.1", "", {}, "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||
|
||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||
|
||||
"flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="],
|
||||
|
||||
"for-each": ["for-each@0.3.4", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="],
|
||||
|
||||
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="],
|
||||
|
||||
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
|
||||
|
||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.2.7", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", "get-proto": "^1.0.0", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA=="],
|
||||
|
||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||
|
||||
"get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
|
||||
|
||||
"glob": ["glob@10.4.5", "", { "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" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
||||
|
||||
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
||||
|
||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||
|
||||
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
||||
|
||||
"has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
|
||||
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
|
||||
|
||||
"has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||
|
||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
||||
|
||||
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
|
||||
|
||||
"is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="],
|
||||
|
||||
"is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="],
|
||||
|
||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||
|
||||
"is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="],
|
||||
|
||||
"is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="],
|
||||
|
||||
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
|
||||
|
||||
"is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="],
|
||||
|
||||
"is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="],
|
||||
|
||||
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
|
||||
|
||||
"is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="],
|
||||
|
||||
"is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="],
|
||||
|
||||
"is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="],
|
||||
|
||||
"is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="],
|
||||
|
||||
"is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="],
|
||||
|
||||
"is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="],
|
||||
|
||||
"is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="],
|
||||
|
||||
"is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="],
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
|
||||
|
||||
"isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="],
|
||||
|
||||
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||
|
||||
"jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="],
|
||||
|
||||
"jotai": ["jotai@2.11.3", "", { "peerDependencies": { "@types/react": ">=17.0.0", "react": ">=17.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-B/PsewAQ0UOS5e2+TTWegUPQ3SCLPCjPY24LYUjfn2EorGlluTA2dFjVLgF1+xHLjK9Jit3y5mKHyMG3Xq/GZg=="],
|
||||
@@ -809,152 +490,56 @@
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||
|
||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="],
|
||||
"lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="],
|
||||
|
||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="],
|
||||
|
||||
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="],
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="],
|
||||
|
||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="],
|
||||
|
||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="],
|
||||
|
||||
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="],
|
||||
|
||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="],
|
||||
|
||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="],
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"lucide-react": ["lucide-react@0.474.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||
|
||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
"lucide-react": ["lucide-react@0.485.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NvyQJ0LKyyCxL23nPKESlr/jmz8r7fJO1bkuptSNYSy0s8VVj4ojhX0YAgmE1e0ewfxUZjIlZpvH+otfTnla8Q=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
||||
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"next-themes": ["next-themes@0.4.5", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-E8/gYKBxZknOXBiDk/sRokAvkOw35PTUD4Gxtq1eBhd0r4Dx5S42zU65/q8ozR5rcSG2ZlE1E3+ShlUpC7an+A=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
||||
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
|
||||
|
||||
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
|
||||
|
||||
"object.entries": ["object.entries@1.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ=="],
|
||||
|
||||
"object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="],
|
||||
|
||||
"object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="],
|
||||
|
||||
"object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="],
|
||||
|
||||
"octokit": ["octokit@4.1.2", "", { "dependencies": { "@octokit/app": "^15.1.4", "@octokit/core": "^6.1.4", "@octokit/oauth-app": "^7.1.6", "@octokit/plugin-paginate-graphql": "^5.2.4", "@octokit/plugin-paginate-rest": "^11.4.2", "@octokit/plugin-rest-endpoint-methods": "^13.3.1", "@octokit/plugin-retry": "^7.1.4", "@octokit/plugin-throttling": "^9.4.0", "@octokit/request-error": "^6.1.7", "@octokit/types": "^13.7.0" } }, "sha512-0kcTxJOK3yQrJsRb8wKa28hlTze4QOz4sLuUnfXXnhboDhFKgv8LxS86tFwbsafDW9JZ08ByuVAE8kQbYJIZkA=="],
|
||||
|
||||
"optics-ts": ["optics-ts@2.4.1", "", {}, "sha512-HaYzMHvC80r7U/LqAd4hQyopDezC60PO2qF5GuIwALut2cl5rK1VWHsqTp0oqoJJWjiv6uXKqsO+Q2OO0C3MmQ=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "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" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
|
||||
|
||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||
|
||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||
|
||||
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||
|
||||
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||
|
||||
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="],
|
||||
|
||||
"pirates": ["pirates@4.0.6", "", {}, "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="],
|
||||
|
||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||
|
||||
"postcss": ["postcss@8.5.1", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ=="],
|
||||
|
||||
"postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="],
|
||||
|
||||
"postcss-js": ["postcss-js@4.0.1", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw=="],
|
||||
|
||||
"postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="],
|
||||
|
||||
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
|
||||
|
||||
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||
|
||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.4.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="],
|
||||
|
||||
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||
|
||||
"prettier-plugin-tailwindcss": ["prettier-plugin-tailwindcss@0.6.11", "", { "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", "@zackad/prettier-plugin-twig": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-import-sort": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", "prettier-plugin-sort-imports": "*", "prettier-plugin-style-order": "*", "prettier-plugin-svelte": "*" }, "optionalPeers": ["@ianvs/prettier-plugin-sort-imports", "@prettier/plugin-pug", "@shopify/prettier-plugin-liquid", "@trivago/prettier-plugin-sort-imports", "@zackad/prettier-plugin-twig", "prettier-plugin-astro", "prettier-plugin-css-order", "prettier-plugin-import-sort", "prettier-plugin-jsdoc", "prettier-plugin-marko", "prettier-plugin-multiline-arrays", "prettier-plugin-organize-attributes", "prettier-plugin-organize-imports", "prettier-plugin-sort-imports", "prettier-plugin-style-order", "prettier-plugin-svelte"] }, "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA=="],
|
||||
|
||||
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"react": ["react@19.0.0", "", {}, "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="],
|
||||
|
||||
"react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="],
|
||||
|
||||
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
|
||||
|
||||
"react-remove-scroll": ["react-remove-scroll@2.6.3", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ=="],
|
||||
@@ -963,126 +548,34 @@
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
||||
|
||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||
|
||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||
|
||||
"regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
|
||||
|
||||
"resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
|
||||
|
||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||
|
||||
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
||||
|
||||
"rollup": ["rollup@4.34.6", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.6", "@rollup/rollup-android-arm64": "4.34.6", "@rollup/rollup-darwin-arm64": "4.34.6", "@rollup/rollup-darwin-x64": "4.34.6", "@rollup/rollup-freebsd-arm64": "4.34.6", "@rollup/rollup-freebsd-x64": "4.34.6", "@rollup/rollup-linux-arm-gnueabihf": "4.34.6", "@rollup/rollup-linux-arm-musleabihf": "4.34.6", "@rollup/rollup-linux-arm64-gnu": "4.34.6", "@rollup/rollup-linux-arm64-musl": "4.34.6", "@rollup/rollup-linux-loongarch64-gnu": "4.34.6", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.6", "@rollup/rollup-linux-riscv64-gnu": "4.34.6", "@rollup/rollup-linux-s390x-gnu": "4.34.6", "@rollup/rollup-linux-x64-gnu": "4.34.6", "@rollup/rollup-linux-x64-musl": "4.34.6", "@rollup/rollup-win32-arm64-msvc": "4.34.6", "@rollup/rollup-win32-ia32-msvc": "4.34.6", "@rollup/rollup-win32-x64-msvc": "4.34.6", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
|
||||
|
||||
"safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="],
|
||||
|
||||
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
|
||||
|
||||
"scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="],
|
||||
|
||||
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||
|
||||
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
|
||||
|
||||
"set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
|
||||
|
||||
"set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||
|
||||
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
||||
|
||||
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||
|
||||
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"sonner": ["sonner@2.0.1", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-FRBphaehZ5tLdLcQ8g2WOIRE+Y7BCfWi5Zyd8bCvBjiW8TxxAyoWZIxS661Yz6TGPqFQ4VLzOF89WEYhfynSFQ=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||
|
||||
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="],
|
||||
|
||||
"string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="],
|
||||
|
||||
"string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="],
|
||||
|
||||
"string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="],
|
||||
|
||||
"string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||
|
||||
"sucrase": ["sucrase@3.35.0", "", { "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" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
|
||||
|
||||
"superjson": ["superjson@2.2.2", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q=="],
|
||||
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
"tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="],
|
||||
|
||||
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||
|
||||
"synckit": ["synckit@0.9.2", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw=="],
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@3.4.17", "", { "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" } }, "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og=="],
|
||||
"tailwindcss": ["tailwindcss@4.0.17", "", {}, "sha512-OErSiGzRa6rLiOvaipsDZvLMSpsBZ4ysB4f0VKGXUrjw2jfkJRd6kjRKV2+ZmTCNvwtvgdDam5D7w6WXsdLJZw=="],
|
||||
|
||||
"tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="],
|
||||
|
||||
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
|
||||
|
||||
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
||||
|
||||
"toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
|
||||
|
||||
"ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
|
||||
|
||||
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
||||
|
||||
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
|
||||
|
||||
"typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="],
|
||||
|
||||
"typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="],
|
||||
|
||||
"typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="],
|
||||
"tw-animate-css": ["tw-animate-css@1.2.5", "", {}, "sha512-ABzjfgVo+fDbhRREGL4KQZUqqdPgvc5zVrLyeW9/6mVqvaDepXc7EvedA+pYmMnIOsUAQMwcWzNvom26J2qYvQ=="],
|
||||
|
||||
"typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
||||
|
||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||
|
||||
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
|
||||
|
||||
"universal-github-app-jwt": ["universal-github-app-jwt@2.2.0", "", {}, "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ=="],
|
||||
@@ -1091,98 +584,16 @@
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="],
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
|
||||
|
||||
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"vite": ["vite@6.1.0", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.5.1", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
|
||||
|
||||
"which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="],
|
||||
|
||||
"which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="],
|
||||
|
||||
"which-typed-array": ["which-typed-array@1.1.18", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA=="],
|
||||
|
||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||
|
||||
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="],
|
||||
|
||||
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
|
||||
"eslint-import-resolver-node/resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
|
||||
|
||||
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
|
||||
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
|
||||
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"postcss-import/resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
|
||||
|
||||
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"tailwindcss/resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
|
||||
|
||||
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
|
||||
|
||||
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||
|
||||
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||
|
||||
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||
|
||||
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
"@tailwindcss/node/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/App.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/App.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import _import from "eslint-plugin-import";
|
||||
import { fixupPluginRules } from "@eslint/compat";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all,
|
||||
});
|
||||
|
||||
export default [
|
||||
...compat.extends(
|
||||
"plugin:@typescript-eslint/recommended-type-checked",
|
||||
"plugin:@typescript-eslint/stylistic-type-checked",
|
||||
"plugin:prettier/recommended",
|
||||
),
|
||||
{
|
||||
plugins: {
|
||||
import: fixupPluginRules(_import),
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
|
||||
parserOptions: {
|
||||
tsconfigRootDir: "C:\\Projects\\shadPS4-launcher",
|
||||
projectService: true,
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
prefer: "type-imports",
|
||||
fixStyle: "inline-type-imports",
|
||||
},
|
||||
],
|
||||
|
||||
"import/consistent-type-specifier-style": ["error", "prefer-inline"],
|
||||
"@typescript-eslint/no-confusing-void-expression": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
||||
},
|
||||
},
|
||||
...compat
|
||||
.extends("plugin:@typescript-eslint/disable-type-checked")
|
||||
.map((config) => ({
|
||||
...config,
|
||||
files: ["./cli/template/**/*.{ts,tsx}"],
|
||||
})),
|
||||
{
|
||||
ignores: [
|
||||
"src-tauri/*",
|
||||
"eslint.config.mjs",
|
||||
"postcss.config.js",
|
||||
"prettier.config.mjs",
|
||||
"tailwind.config.js",
|
||||
"vite.config.ts",
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -2,9 +2,8 @@
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri + React + Typescript</title>
|
||||
<title>ShadPS4 Launcher</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
144
package.json
144
package.json
@@ -1,80 +1,68 @@
|
||||
{
|
||||
"name": "shadps4-launcher",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tauri dev --config ./src-tauri/tauri.dev.conf.json",
|
||||
"build": "tauri build",
|
||||
"vite:dev": "vite",
|
||||
"vite:build": "tsc && vite build",
|
||||
"tauri": "tauri",
|
||||
"lint": "eslint . && prettier . --check",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/vite": "^4.0.17",
|
||||
"@tanstack/query-core": "^5.67.2",
|
||||
"@tanstack/react-query": "^5.67.2",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.2.0",
|
||||
"@tauri-apps/plugin-fs": "~2",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/plugin-os": "^2.2.0",
|
||||
"@tauri-apps/plugin-shell": "~2.2.0",
|
||||
"@tauri-apps/plugin-store": "~2",
|
||||
"@tauri-apps/plugin-upload": "^2.2.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dequal": "^2.0.3",
|
||||
"jotai": "^2.11.1",
|
||||
"jotai-optics": "^0.4.0",
|
||||
"jotai-tanstack-query": "^0.9.0",
|
||||
"lucide-react": "^0.485.0",
|
||||
"next-themes": "^0.4.5",
|
||||
"octokit": "^4.1.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sonner": "^2.0.1",
|
||||
"superjson": "^2.2.2",
|
||||
"tailwind-merge": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/node": "^22.12.0",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
||||
"@typescript-eslint/parser": "^8.22.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"postcss": "^8.5.1",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.3"
|
||||
}
|
||||
"name": "shadps4-launcher",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tauri dev --config ./src-tauri/tauri.dev.conf.json",
|
||||
"build": "tauri build",
|
||||
"vite:dev": "vite",
|
||||
"vite:build": "tsc && vite build",
|
||||
"tauri": "tauri",
|
||||
"check": "biome check --write",
|
||||
"ci": "biome ci"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/vite": "^4.0.17",
|
||||
"@tanstack/query-core": "^5.67.2",
|
||||
"@tanstack/react-query": "^5.67.2",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.2.0",
|
||||
"@tauri-apps/plugin-fs": "~2",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/plugin-os": "^2.2.0",
|
||||
"@tauri-apps/plugin-shell": "~2.2.0",
|
||||
"@tauri-apps/plugin-store": "~2",
|
||||
"@tauri-apps/plugin-upload": "^2.2.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dequal": "^2.0.3",
|
||||
"jotai": "^2.11.1",
|
||||
"jotai-optics": "^0.4.0",
|
||||
"jotai-tanstack-query": "^0.9.0",
|
||||
"lucide-react": "^0.485.0",
|
||||
"next-themes": "^0.4.5",
|
||||
"octokit": "^4.1.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sonner": "^2.0.1",
|
||||
"superjson": "^2.2.2",
|
||||
"tailwind-merge": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0-beta.1",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/node": "^22.12.0",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"tailwindcss": "^4.0.17",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.3"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"@biomejs/biome",
|
||||
"@swc/core"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* @type {import('prettier').Config & import("@ianvs/prettier-plugin-sort-imports").PluginConfig}
|
||||
*/
|
||||
const config = {
|
||||
arrowParens: "always",
|
||||
printWidth: 80,
|
||||
singleQuote: false,
|
||||
jsxSingleQuote: false,
|
||||
semi: true,
|
||||
trailingComma: "all",
|
||||
tabWidth: 2,
|
||||
plugins: ["prettier-plugin-tailwindcss"],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,47 +1,47 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"dialog:allow-open",
|
||||
"fs:allow-copy-file",
|
||||
"fs:allow-exists",
|
||||
"fs:allow-mkdir",
|
||||
"fs:allow-read-dir",
|
||||
"fs:allow-read-file",
|
||||
"fs:allow-read-text-file",
|
||||
"fs:allow-resource-read-recursive",
|
||||
"fs:allow-watch",
|
||||
"fs:allow-unwatch",
|
||||
"fs:allow-write-file",
|
||||
"fs:allow-write-text-file",
|
||||
"opener:allow-open-path",
|
||||
"opener:allow-reveal-item-in-dir",
|
||||
"opener:default",
|
||||
"os:default",
|
||||
"store:default",
|
||||
"upload:default",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": ["**/*"]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:read-files",
|
||||
"allow": [
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"dialog:allow-open",
|
||||
"fs:allow-copy-file",
|
||||
"fs:allow-exists",
|
||||
"fs:allow-mkdir",
|
||||
"fs:allow-read-dir",
|
||||
"fs:allow-read-file",
|
||||
"fs:allow-read-text-file",
|
||||
"fs:allow-resource-read-recursive",
|
||||
"fs:allow-watch",
|
||||
"fs:allow-unwatch",
|
||||
"fs:allow-write-file",
|
||||
"fs:allow-write-text-file",
|
||||
"opener:allow-open-path",
|
||||
"opener:allow-reveal-item-in-dir",
|
||||
"opener:default",
|
||||
"os:default",
|
||||
"store:default",
|
||||
"upload:default",
|
||||
{
|
||||
"path": "$RESOURCE/mock/**/*"
|
||||
"identifier": "fs:scope",
|
||||
"allow": ["**/*"]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:read-files",
|
||||
"allow": [
|
||||
{
|
||||
"path": "$RESOURCE/mock/**/*"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"identifier": "opener:allow-open-path",
|
||||
"allow": [
|
||||
{
|
||||
"path": "**/*"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"identifier": "opener:allow-open-path",
|
||||
"allow": [{
|
||||
"path": "**/*"
|
||||
}]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "shadps4-launcher",
|
||||
"version": "0.1.0",
|
||||
"identifier": "net.shadps4.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun vite:dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "bun vite:build",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "shadps4-launcher",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null,
|
||||
"assetProtocol": {
|
||||
"enable": true,
|
||||
"scope": ["**/*"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "shadps4-launcher",
|
||||
"version": "0.1.0",
|
||||
"identifier": "net.shadps4.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun vite:dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "bun vite:build",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"exceptionDomain": "",
|
||||
"signingIdentity": "-",
|
||||
"providerShortName": null,
|
||||
"entitlements": null
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "shadps4-launcher",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null,
|
||||
"assetProtocol": {
|
||||
"enable": true,
|
||||
"scope": ["**/*"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
},
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"exceptionDomain": "",
|
||||
"signingIdentity": "-",
|
||||
"providerShortName": null,
|
||||
"entitlements": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"bundle": {
|
||||
"resources": {
|
||||
"../mock/": "mock/"
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"bundle": {
|
||||
"resources": {
|
||||
"../mock/": "mock/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
228
src/App.css
228
src/App.css
@@ -1,130 +1,130 @@
|
||||
@import 'tailwindcss';
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@utility center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.129 0.042 264.695);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.129 0.042 264.695);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.129 0.042 264.695);
|
||||
--primary: oklch(0.208 0.042 265.755);
|
||||
--primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--secondary: oklch(0.968 0.007 247.896);
|
||||
--secondary-foreground: oklch(0.208 0.042 265.755);
|
||||
--muted: oklch(0.968 0.007 247.896);
|
||||
--muted-foreground: oklch(0.554 0.046 257.417);
|
||||
--accent: oklch(0.968 0.007 247.896);
|
||||
--accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.929 0.013 255.508);
|
||||
--input: oklch(0.929 0.013 255.508);
|
||||
--ring: oklch(0.704 0.04 256.788);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.984 0.003 247.858);
|
||||
--sidebar-foreground: oklch(0.129 0.042 264.695);
|
||||
--sidebar-primary: oklch(0.208 0.042 265.755);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.968 0.007 247.896);
|
||||
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--sidebar-border: oklch(0.929 0.013 255.508);
|
||||
--sidebar-ring: oklch(0.704 0.04 256.788);
|
||||
}
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.129 0.042 264.695);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.129 0.042 264.695);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.129 0.042 264.695);
|
||||
--primary: oklch(0.208 0.042 265.755);
|
||||
--primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--secondary: oklch(0.968 0.007 247.896);
|
||||
--secondary-foreground: oklch(0.208 0.042 265.755);
|
||||
--muted: oklch(0.968 0.007 247.896);
|
||||
--muted-foreground: oklch(0.554 0.046 257.417);
|
||||
--accent: oklch(0.968 0.007 247.896);
|
||||
--accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.929 0.013 255.508);
|
||||
--input: oklch(0.929 0.013 255.508);
|
||||
--ring: oklch(0.704 0.04 256.788);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.984 0.003 247.858);
|
||||
--sidebar-foreground: oklch(0.129 0.042 264.695);
|
||||
--sidebar-primary: oklch(0.208 0.042 265.755);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.968 0.007 247.896);
|
||||
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--sidebar-border: oklch(0.929 0.013 255.508);
|
||||
--sidebar-ring: oklch(0.704 0.04 256.788);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.129 0.042 264.695);
|
||||
--foreground: oklch(0.984 0.003 247.858);
|
||||
--card: oklch(0.208 0.042 265.755);
|
||||
--card-foreground: oklch(0.984 0.003 247.858);
|
||||
--popover: oklch(0.208 0.042 265.755);
|
||||
--popover-foreground: oklch(0.984 0.003 247.858);
|
||||
--primary: oklch(0.929 0.013 255.508);
|
||||
--primary-foreground: oklch(0.208 0.042 265.755);
|
||||
--secondary: oklch(0.279 0.041 260.031);
|
||||
--secondary-foreground: oklch(0.984 0.003 247.858);
|
||||
--muted: oklch(0.279 0.041 260.031);
|
||||
--muted-foreground: oklch(0.704 0.04 256.788);
|
||||
--accent: oklch(0.279 0.041 260.031);
|
||||
--accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.551 0.027 264.364);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.208 0.042 265.755);
|
||||
--sidebar-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.279 0.041 260.031);
|
||||
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.551 0.027 264.364);
|
||||
}
|
||||
.dark {
|
||||
--background: oklch(0.129 0.042 264.695);
|
||||
--foreground: oklch(0.984 0.003 247.858);
|
||||
--card: oklch(0.208 0.042 265.755);
|
||||
--card-foreground: oklch(0.984 0.003 247.858);
|
||||
--popover: oklch(0.208 0.042 265.755);
|
||||
--popover-foreground: oklch(0.984 0.003 247.858);
|
||||
--primary: oklch(0.929 0.013 255.508);
|
||||
--primary-foreground: oklch(0.208 0.042 265.755);
|
||||
--secondary: oklch(0.279 0.041 260.031);
|
||||
--secondary-foreground: oklch(0.984 0.003 247.858);
|
||||
--muted: oklch(0.279 0.041 260.031);
|
||||
--muted-foreground: oklch(0.704 0.04 256.788);
|
||||
--accent: oklch(0.279 0.041 260.031);
|
||||
--accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.551 0.027 264.364);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.208 0.042 265.755);
|
||||
--sidebar-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.279 0.041 260.031);
|
||||
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.551 0.027 264.364);
|
||||
}
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
30
src/App.tsx
30
src/App.tsx
@@ -8,21 +8,21 @@ import { Toolbar } from "./components/toolbar";
|
||||
import { VersionManagerModal } from "./components/version-manager-modal";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<main
|
||||
className="flex h-screen max-h-screen flex-col justify-stretch align-top"
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
>
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
<ConfigModal />
|
||||
<VersionManagerModal />
|
||||
<GamepadNavField className="flex h-full flex-col">
|
||||
<Toolbar />
|
||||
<GameLibrary />
|
||||
</GamepadNavField>
|
||||
</Suspense>
|
||||
</main>
|
||||
);
|
||||
return (
|
||||
<main
|
||||
className="flex h-screen max-h-screen flex-col justify-stretch align-top"
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
>
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
<ConfigModal />
|
||||
<VersionManagerModal />
|
||||
<GamepadNavField className="flex h-full flex-col">
|
||||
<Toolbar />
|
||||
<GameLibrary />
|
||||
</GamepadNavField>
|
||||
</Suspense>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { atomModalConfigIsOpen } from "@/store/common";
|
||||
import { atomGamesPath } from "@/store/paths";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
import { open as openDialog } from "@tauri-apps/plugin-dialog";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { atomModalConfigIsOpen } from "@/store/common";
|
||||
import { atomGamesPath } from "@/store/paths";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
import { Button } from "./ui/button";
|
||||
import { Dialog, DialogContent, DialogTitle } from "./ui/dialog";
|
||||
import { Input } from "./ui/input";
|
||||
@@ -12,72 +12,71 @@ import { Label } from "./ui/label";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs";
|
||||
|
||||
function PathConfig() {
|
||||
const [gamePath, setGamePath] = useAtom(atomGamesPath);
|
||||
const [inputGamePath, setInputGamePath] = useState("");
|
||||
const [gamePath, setGamePath] = useAtom(atomGamesPath);
|
||||
const [inputGamePath, setInputGamePath] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
setInputGamePath(gamePath || "");
|
||||
}, [gamePath]);
|
||||
useEffect(() => {
|
||||
setInputGamePath(gamePath || "");
|
||||
}, [gamePath]);
|
||||
|
||||
function askDir() {
|
||||
openDialog({
|
||||
directory: true,
|
||||
})
|
||||
.then((e) => {
|
||||
if (e) {
|
||||
setGamePath(e);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
toast.error(stringifyError(e));
|
||||
console.error(e);
|
||||
debugger;
|
||||
});
|
||||
}
|
||||
function askDir() {
|
||||
openDialog({
|
||||
directory: true,
|
||||
})
|
||||
.then((e) => {
|
||||
if (e) {
|
||||
setGamePath(e);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
toast.error(stringifyError(e));
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col p-4">
|
||||
<div className="grid w-full max-w-sm grid-cols-4 items-center gap-1.5">
|
||||
<Label className="col-span-2" htmlFor="game_path">
|
||||
Games installation
|
||||
</Label>
|
||||
<Input
|
||||
className="col-span-3"
|
||||
type="text"
|
||||
id="game_path"
|
||||
placeholder="/game/path"
|
||||
value={inputGamePath}
|
||||
onChange={(e) => setInputGamePath(e.target.value)}
|
||||
onBlur={() => setGamePath(inputGamePath)}
|
||||
/>
|
||||
<Button onClick={askDir}>Select</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="flex w-full flex-col p-4">
|
||||
<div className="grid w-full max-w-sm grid-cols-4 items-center gap-1.5">
|
||||
<Label className="col-span-2" htmlFor="game_path">
|
||||
Games installation
|
||||
</Label>
|
||||
<Input
|
||||
className="col-span-3"
|
||||
id="game_path"
|
||||
onBlur={() => setGamePath(inputGamePath)}
|
||||
onChange={(e) => setInputGamePath(e.target.value)}
|
||||
placeholder="/game/path"
|
||||
type="text"
|
||||
value={inputGamePath}
|
||||
/>
|
||||
<Button onClick={askDir}>Select</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ConfigModal() {
|
||||
const [isOpen, setIsOpen] = useAtom(atomModalConfigIsOpen);
|
||||
const [isOpen, setIsOpen] = useAtom(atomModalConfigIsOpen);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTitle className="hidden">Configuration</DialogTitle>
|
||||
<DialogContent>
|
||||
<Tabs defaultValue="general">
|
||||
<TabsList>
|
||||
<TabsTrigger value="general">General</TabsTrigger>
|
||||
<TabsTrigger value="paths">Directories</TabsTrigger>
|
||||
<TabsTrigger value="debug">Debug</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="general">GENERAL STUFF</TabsContent>
|
||||
<TabsContent value="paths">
|
||||
<PathConfig />
|
||||
</TabsContent>
|
||||
<TabsContent value="debug">Debug</TabsContent>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Dialog onOpenChange={setIsOpen} open={isOpen}>
|
||||
<DialogTitle className="hidden">Configuration</DialogTitle>
|
||||
<DialogContent>
|
||||
<Tabs defaultValue="general">
|
||||
<TabsList>
|
||||
<TabsTrigger value="general">General</TabsTrigger>
|
||||
<TabsTrigger value="paths">Directories</TabsTrigger>
|
||||
<TabsTrigger value="debug">Debug</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="general">GENERAL STUFF</TabsContent>
|
||||
<TabsContent value="paths">
|
||||
<PathConfig />
|
||||
</TabsContent>
|
||||
<TabsContent value="debug">Debug</TabsContent>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,188 +1,198 @@
|
||||
import CN from "@/assets/flags/cn.svg";
|
||||
import EU from "@/assets/flags/eu.svg";
|
||||
import JP from "@/assets/flags/jp.svg";
|
||||
import US from "@/assets/flags/us.svg";
|
||||
import { startGame } from "@/handlers/run_emu";
|
||||
import { type GameEntry, atomGameLibrary } from "@/store/game-library";
|
||||
import { gamepadActiveAtom } from "@/store/gamepad";
|
||||
import { atomGamesPath } from "@/store/paths";
|
||||
import { atomSelectedVersion } from "@/store/version-manager";
|
||||
import { exists, mkdir } from "@tauri-apps/plugin-fs";
|
||||
import { openPath } from "@tauri-apps/plugin-opener";
|
||||
import { useAtom, useStore } from "jotai";
|
||||
import { CircleHelp, Globe, ImageOff, Play } from "lucide-react";
|
||||
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import CN from "@/assets/flags/cn.svg";
|
||||
import EU from "@/assets/flags/eu.svg";
|
||||
import JP from "@/assets/flags/jp.svg";
|
||||
import US from "@/assets/flags/us.svg";
|
||||
import { startGame } from "@/handlers/run-emu";
|
||||
import { atomGameLibrary, type GameEntry } from "@/store/game-library";
|
||||
import { gamepadActiveAtom } from "@/store/gamepad";
|
||||
import { atomGamesPath } from "@/store/paths";
|
||||
import { atomSelectedVersion } from "@/store/version-manager";
|
||||
import GamepadIcon from "./gamepad-icon";
|
||||
import { ScrollArea } from "./ui/scroll-area";
|
||||
import { Skeleton } from "./ui/skeleton";
|
||||
|
||||
function Flag({
|
||||
sfo,
|
||||
className,
|
||||
sfo,
|
||||
className,
|
||||
}: Pick<GameEntry, "sfo"> & { className?: string }) {
|
||||
const region = useMemo(() => {
|
||||
const { CONTENT_ID } = sfo?.entries ?? {};
|
||||
return CONTENT_ID?.Text?.[0] ?? undefined;
|
||||
}, [sfo]);
|
||||
const region = useMemo(() => {
|
||||
const { CONTENT_ID } = sfo?.entries ?? {};
|
||||
return CONTENT_ID?.Text?.[0] ?? undefined;
|
||||
}, [sfo]);
|
||||
|
||||
switch (region) {
|
||||
case "U":
|
||||
return <img className={className} src={US} alt="US" />;
|
||||
case "E":
|
||||
return <img className={className} src={EU} alt="EU" />;
|
||||
case "J":
|
||||
return <img className={className} src={JP} alt="JP" />;
|
||||
case "H":
|
||||
return <img className={className} src={CN} alt="CN" />;
|
||||
case "I":
|
||||
return <Globe className={className} />;
|
||||
default:
|
||||
return <CircleHelp className={className} />;
|
||||
}
|
||||
switch (region) {
|
||||
case "U":
|
||||
return <img alt="US" className={className} src={US} />;
|
||||
case "E":
|
||||
return <img alt="EU" className={className} src={EU} />;
|
||||
case "J":
|
||||
return <img alt="JP" className={className} src={JP} />;
|
||||
case "H":
|
||||
return <img alt="CN" className={className} src={CN} />;
|
||||
case "I":
|
||||
return <Globe className={className} />;
|
||||
default:
|
||||
return <CircleHelp className={className} />;
|
||||
}
|
||||
}
|
||||
|
||||
function GameBox({ game, isFirst }: { game: GameEntry; isFirst?: boolean }) {
|
||||
const isGamepad = useAtom(gamepadActiveAtom);
|
||||
const store = useStore();
|
||||
const isGamepad = useAtom(gamepadActiveAtom);
|
||||
const store = useStore();
|
||||
|
||||
const [clickCount, setClickCount] = useState<number>(0);
|
||||
const [clickCount, setClickCount] = useState<number>(0);
|
||||
|
||||
const openGame = useCallback(
|
||||
() =>
|
||||
void (async () => {
|
||||
const openGame = useCallback(
|
||||
() =>
|
||||
void (async () => {
|
||||
setClickCount(0);
|
||||
const selectEmu = store.get(atomSelectedVersion);
|
||||
if (!selectEmu) {
|
||||
toast.warning("No emulator selected");
|
||||
return;
|
||||
}
|
||||
await startGame(selectEmu, game.path);
|
||||
toast.success("Game started");
|
||||
})(),
|
||||
[game, store],
|
||||
);
|
||||
|
||||
const onClick = () => {
|
||||
setClickCount((prev) => prev + 1);
|
||||
};
|
||||
|
||||
const onBlur = () => {
|
||||
setClickCount(0);
|
||||
const selectEmu = store.get(atomSelectedVersion);
|
||||
if (!selectEmu) {
|
||||
toast.warning("No emulator selected");
|
||||
return;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (clickCount >= 3) {
|
||||
setClickCount(0);
|
||||
toast.info("Do a double click to start the game");
|
||||
}
|
||||
await startGame(selectEmu, game.path);
|
||||
toast.success("Game started");
|
||||
})(),
|
||||
[game, store],
|
||||
);
|
||||
}, [clickCount]);
|
||||
|
||||
const onClick = () => {
|
||||
setClickCount((prev) => prev + 1);
|
||||
};
|
||||
|
||||
const onBlur = () => {
|
||||
setClickCount(0);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (clickCount >= 3) {
|
||||
setClickCount(0);
|
||||
toast.info("Do a double click to start the game");
|
||||
}
|
||||
}, [clickCount]);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={game.id}
|
||||
className="group aspect-square h-auto w-full max-w-[200px] cursor-pointer overflow-hidden rounded-lg bg-zinc-800 transition-transform stack focus-within:scale-110 hover:scale-110"
|
||||
onDoubleClick={openGame}
|
||||
onClick={onClick}
|
||||
onBlur={onBlur}
|
||||
data-gamepad-selectable
|
||||
tabIndex={0}
|
||||
>
|
||||
{game.cover ? (
|
||||
<img
|
||||
src={game.cover}
|
||||
alt={game.title}
|
||||
className="col-span-full row-span-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<ImageOff className="col-span-full row-span-full h-8 w-full self-center" />
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-3 grid-rows-3 bg-black/50 opacity-0 backdrop-blur-[2px] transition-opacity group-focus-within:opacity-100 group-hover:opacity-100">
|
||||
<span className="col-span-full row-start-1 row-end-2 truncate px-3 py-2 text-center text-lg font-semibold">
|
||||
{/* TODO: scroll text on overflow */}
|
||||
{game.title}
|
||||
</span>
|
||||
|
||||
<div className="col-start-3 col-end-4 row-start-3 row-end-4 m-2 size-6 place-self-end">
|
||||
<Flag sfo={game.sfo} className="rounded-full" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="col-span-full row-span-full grid size-16 place-items-center place-self-center rounded-full bg-black/75"
|
||||
data-play-game={""}
|
||||
data-initial-focus={isFirst ? "" : undefined}
|
||||
return (
|
||||
<div
|
||||
className="group stack aspect-square h-auto w-full max-w-[200px] cursor-pointer overflow-hidden rounded-lg bg-zinc-800 transition-transform focus-within:scale-110 hover:scale-110"
|
||||
data-gamepad-selectable
|
||||
key={game.id}
|
||||
onBlur={onBlur}
|
||||
onClick={onClick}
|
||||
onDoubleClick={openGame}
|
||||
>
|
||||
<Play className="size-10" fill="currentColor" />
|
||||
</button>
|
||||
{game.cover ? (
|
||||
<img
|
||||
alt={game.title}
|
||||
className="col-span-full row-span-full object-cover"
|
||||
src={game.cover}
|
||||
/>
|
||||
) : (
|
||||
<ImageOff className="col-span-full row-span-full h-8 w-full self-center" />
|
||||
)}
|
||||
|
||||
<button className="col-span-full row-start-3 row-end-4 flex flex-row items-center justify-center gap-x-2 self-end py-2 transition-colors hover:bg-secondary/75 focus:bg-secondary/75">
|
||||
{isGamepad && <GamepadIcon icon="options" className="size-6" />}
|
||||
View More
|
||||
{isGamepad && <div className="size-6" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<div className="grid grid-cols-3 grid-rows-3 bg-black/50 opacity-0 backdrop-blur-[2px] transition-opacity group-focus-within:opacity-100 group-hover:opacity-100">
|
||||
<span className="col-span-full row-start-1 row-end-2 truncate px-3 py-2 text-center font-semibold text-lg">
|
||||
{/* TODO: scroll text on overflow */}
|
||||
{game.title}
|
||||
</span>
|
||||
|
||||
<div className="col-start-3 col-end-4 row-start-3 row-end-4 m-2 size-6 place-self-end">
|
||||
<Flag className="rounded-full" sfo={game.sfo} />
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="col-span-full row-span-full grid size-16 place-items-center place-self-center rounded-full bg-black/75"
|
||||
data-initial-focus={isFirst ? "" : undefined}
|
||||
data-play-game={""}
|
||||
type="button"
|
||||
>
|
||||
<Play className="size-10" fill="currentColor" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="col-span-full row-start-3 row-end-4 flex flex-row items-center justify-center gap-x-2 self-end py-2 transition-colors hover:bg-secondary/75 focus:bg-secondary/75"
|
||||
type="button"
|
||||
>
|
||||
{isGamepad && (
|
||||
<GamepadIcon className="size-6" icon="options" />
|
||||
)}
|
||||
View More
|
||||
{isGamepad && <div className="size-6" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Grid() {
|
||||
const [games] = useAtom(atomGameLibrary);
|
||||
const store = useStore();
|
||||
const [games] = useAtom(atomGameLibrary);
|
||||
const store = useStore();
|
||||
|
||||
if (games.length === 0) {
|
||||
async function openGameFolder() {
|
||||
const path = store.get(atomGamesPath);
|
||||
if (path) {
|
||||
if (!(await exists(path))) {
|
||||
await mkdir(path, { recursive: true });
|
||||
if (games.length === 0) {
|
||||
async function openGameFolder() {
|
||||
const path = store.get(atomGamesPath);
|
||||
if (path) {
|
||||
if (!(await exists(path))) {
|
||||
await mkdir(path, { recursive: true });
|
||||
}
|
||||
await openPath(path);
|
||||
}
|
||||
}
|
||||
await openPath(path);
|
||||
}
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div
|
||||
className="flex h-[150px] w-[300px] cursor-pointer flex-col items-center justify-center rounded-md border border-dashed text-sm"
|
||||
onClick={() => void openGameFolder()}
|
||||
>
|
||||
<span>No game found :(</span>
|
||||
<span>Click here to open game folder</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div
|
||||
className="flex h-[150px] w-[300px] cursor-pointer flex-col items-center justify-center rounded-md border border-dashed text-sm"
|
||||
onClick={() => void openGameFolder()}
|
||||
>
|
||||
<span>No game found :(</span>
|
||||
<span>Click here to open game folder</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollArea type="scroll" className="z-20 flex-1">
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4 p-8">
|
||||
{games.map((game, index) => (
|
||||
<GameBox key={game.path} game={game} isFirst={index === 0} />
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
);
|
||||
return (
|
||||
<ScrollArea className="z-20 flex-1" type="scroll">
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4 p-8">
|
||||
{games.map((game, index) => (
|
||||
<GameBox
|
||||
game={game}
|
||||
isFirst={index === 0}
|
||||
key={game.path}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
);
|
||||
}
|
||||
|
||||
function GridSkeleton() {
|
||||
return (
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4 overflow-hidden p-8">
|
||||
{Array(50)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<Skeleton
|
||||
key={i}
|
||||
className="relative aspect-square rounded-md bg-zinc-800"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4 overflow-hidden p-8">
|
||||
{Array(50)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<Skeleton
|
||||
className="relative aspect-square rounded-md bg-zinc-800"
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Just skeleton, order doesn't matter
|
||||
key={i}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function GameLibrary() {
|
||||
return (
|
||||
<Suspense fallback={<GridSkeleton />}>
|
||||
<Grid />
|
||||
</Suspense>
|
||||
);
|
||||
return (
|
||||
<Suspense fallback={<GridSkeleton />}>
|
||||
<Grid />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,48 +1,52 @@
|
||||
import { createAbort } from "@/utils/events";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
import { CircleHelp } from "lucide-react";
|
||||
import { type GamepadButtons } from "./gamepad-nav-field";
|
||||
import { useEffect, useState } from "react";
|
||||
import { createAbort } from "@/utils/events";
|
||||
import { cn } from "@/utils/ui";
|
||||
import type { GamepadButtons } from "./gamepad-nav-field";
|
||||
|
||||
export interface GamepadIconProps {
|
||||
icon: GamepadButtons;
|
||||
type?: "xbox";
|
||||
outline?: boolean;
|
||||
className?: string;
|
||||
icon: GamepadButtons;
|
||||
type?: "xbox";
|
||||
outline?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function GamepadIcon({
|
||||
icon,
|
||||
type = "xbox",
|
||||
outline,
|
||||
...rest
|
||||
icon,
|
||||
type = "xbox",
|
||||
outline,
|
||||
...rest
|
||||
}: GamepadIconProps) {
|
||||
const [loadedIcon, setLoadedIcon] = useState<string | undefined | null>();
|
||||
const [loadedIcon, setLoadedIcon] = useState<string | undefined | null>();
|
||||
|
||||
useEffect(() => {
|
||||
const { abort, signal } = createAbort();
|
||||
useEffect(() => {
|
||||
const { abort, signal } = createAbort();
|
||||
|
||||
void import(
|
||||
`@/assets/gamepad/${type}/${icon}${outline ? "_outline" : ""}.svg`
|
||||
)
|
||||
.then((module: { default: string }) => {
|
||||
if (signal.aborted) return;
|
||||
setLoadedIcon(module.default);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoadedIcon(null);
|
||||
});
|
||||
void import(
|
||||
`@/assets/gamepad/${type}/${icon}${outline ? "_outline" : ""}.svg`
|
||||
)
|
||||
.then((module: { default: string }) => {
|
||||
if (signal.aborted) {
|
||||
return;
|
||||
}
|
||||
setLoadedIcon(module.default);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoadedIcon(null);
|
||||
});
|
||||
|
||||
return () => {
|
||||
abort();
|
||||
setLoadedIcon(undefined);
|
||||
};
|
||||
}, [icon]);
|
||||
return () => {
|
||||
abort();
|
||||
setLoadedIcon(undefined);
|
||||
};
|
||||
}, [icon, outline, type]);
|
||||
|
||||
if (loadedIcon === undefined) return null;
|
||||
if (loadedIcon === null)
|
||||
return <CircleHelp {...rest} className={cn("scale-90")} />;
|
||||
if (loadedIcon === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (loadedIcon === null) {
|
||||
return <CircleHelp {...rest} className={cn("scale-90")} />;
|
||||
}
|
||||
|
||||
return <img src={loadedIcon} {...rest} />;
|
||||
return <img src={loadedIcon} {...rest} alt={icon} />;
|
||||
}
|
||||
|
||||
@@ -1,231 +1,246 @@
|
||||
import { type GamepadButtonEvent } from "@/handlers/gamepad";
|
||||
import { useGamepadInputStack } from "@/hooks/useGamepadInputStack";
|
||||
import {
|
||||
type ComponentProps,
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
type ComponentProps,
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
import type { GamepadButtonEvent } from "@/handlers/gamepad";
|
||||
import { useGamepadInputStack } from "@/hooks/useGamepadInputStack";
|
||||
|
||||
export const BUTTON_MAP = {
|
||||
confirm: 0,
|
||||
back: 1,
|
||||
extra: 2,
|
||||
options: 3,
|
||||
dpad_up: 12,
|
||||
dpad_down: 13,
|
||||
dpad_left: 14,
|
||||
dpad_right: 15,
|
||||
confirm: 0,
|
||||
back: 1,
|
||||
extra: 2,
|
||||
options: 3,
|
||||
dpad_up: 12,
|
||||
dpad_down: 13,
|
||||
dpad_left: 14,
|
||||
dpad_right: 15,
|
||||
} as const;
|
||||
|
||||
export const BUTTON_MAP_REVERSE = {
|
||||
0: "confirm",
|
||||
1: "back",
|
||||
2: "extra",
|
||||
3: "options",
|
||||
12: "dpad_up",
|
||||
13: "dpad_down",
|
||||
14: "dpad_left",
|
||||
15: "dpad_right",
|
||||
0: "confirm",
|
||||
1: "back",
|
||||
2: "extra",
|
||||
3: "options",
|
||||
12: "dpad_up",
|
||||
13: "dpad_down",
|
||||
14: "dpad_left",
|
||||
15: "dpad_right",
|
||||
} as const;
|
||||
|
||||
export type GamepadButtons =
|
||||
(typeof BUTTON_MAP_REVERSE)[keyof typeof BUTTON_MAP_REVERSE];
|
||||
(typeof BUTTON_MAP_REVERSE)[keyof typeof BUTTON_MAP_REVERSE];
|
||||
|
||||
const SELECTABLE_DATA_ATTR = "data-gamepad-selectable";
|
||||
const SELECTION_ANGLE = (60 * Math.PI) / 180;
|
||||
|
||||
interface Props {
|
||||
zIndex?: number;
|
||||
zIndex?: number;
|
||||
}
|
||||
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
const rectAnchors = {
|
||||
TOP_LEFT: [0, 0],
|
||||
TOP_CENTER: [0.5, 0],
|
||||
TOP_RIGHT: [1, 0],
|
||||
CENTER_LEFT: [0, 0.5],
|
||||
CENTER: [0.5, 0.5],
|
||||
CENTER_RIGHT: [1, 0.5],
|
||||
BOTTOM_LEFT: [0, 1],
|
||||
BOTTOM_CENTER: [0.5, 1],
|
||||
BOTTOM_RIGHT: [1, 1],
|
||||
TOP_LEFT: [0, 0],
|
||||
TOP_CENTER: [0.5, 0],
|
||||
TOP_RIGHT: [1, 0],
|
||||
CENTER_LEFT: [0, 0.5],
|
||||
CENTER: [0.5, 0.5],
|
||||
CENTER_RIGHT: [1, 0.5],
|
||||
BOTTOM_LEFT: [0, 1],
|
||||
BOTTOM_CENTER: [0.5, 1],
|
||||
BOTTOM_RIGHT: [1, 1],
|
||||
} as const;
|
||||
|
||||
function rectCenter(rect: DOMRect, anchor?: string | null): Point {
|
||||
const a = rectAnchors[(anchor || "CENTER") as keyof typeof rectAnchors] || [
|
||||
0.5, 0.5,
|
||||
];
|
||||
const width = rect.width * a[0];
|
||||
const height = rect.height * a[1];
|
||||
return { x: rect.x + width, y: rect.y + height };
|
||||
const a = rectAnchors[(anchor || "CENTER") as keyof typeof rectAnchors] || [
|
||||
0.5, 0.5,
|
||||
];
|
||||
const width = rect.width * a[0];
|
||||
const height = rect.height * a[1];
|
||||
return { x: rect.x + width, y: rect.y + height };
|
||||
}
|
||||
|
||||
function pointDiff(p1: Point, p2: Point): Point {
|
||||
const x = p2.x - p1.x;
|
||||
const y = p2.y - p1.y;
|
||||
return { x, y };
|
||||
const x = p2.x - p1.x;
|
||||
const y = p2.y - p1.y;
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
function distSquared({ x, y }: Point): number {
|
||||
return x * x + y * y;
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
export function GamepadNavField({
|
||||
zIndex,
|
||||
...props
|
||||
zIndex,
|
||||
...props
|
||||
}: PropsWithChildren<Props & ComponentProps<"div">>) {
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
const availableElements = useRef(new Set<HTMLElement>());
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
const availableElements = useRef(new Set<HTMLElement>());
|
||||
|
||||
const onMove = useCallback((x: number, y: number) => {
|
||||
const elements = availableElements.current;
|
||||
if (!elements) return;
|
||||
|
||||
const focus = (el: HTMLElement | undefined) => {
|
||||
if (!el) return;
|
||||
el.focus();
|
||||
};
|
||||
|
||||
const active = document.activeElement;
|
||||
if (!active?.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
focus(elements.values().next().value);
|
||||
return;
|
||||
}
|
||||
|
||||
const angleOffset = Math.atan2(y, x);
|
||||
|
||||
const activeCenter = rectCenter(
|
||||
active.getBoundingClientRect(),
|
||||
active.getAttribute(SELECTABLE_DATA_ATTR),
|
||||
);
|
||||
|
||||
let next: HTMLElement | null = null;
|
||||
let nextAngle = Number.MAX_VALUE;
|
||||
let nextDistance = Number.MAX_VALUE;
|
||||
let fallback: HTMLElement | null = null;
|
||||
let fallbackDistance = Number.MAX_VALUE;
|
||||
for (const e of elements) {
|
||||
if (e == active) continue;
|
||||
|
||||
const c = rectCenter(
|
||||
e.getBoundingClientRect(),
|
||||
e.getAttribute(SELECTABLE_DATA_ATTR),
|
||||
);
|
||||
const diff = pointDiff(activeCenter, c);
|
||||
|
||||
let angle = Math.abs(angleOffset - Math.atan2(diff.y, diff.x));
|
||||
if (angle > Math.PI) {
|
||||
angle = Math.PI * 2 - angle;
|
||||
}
|
||||
const dist = distSquared(diff);
|
||||
if (
|
||||
angle < SELECTION_ANGLE &&
|
||||
(angle - nextAngle < 0.1 || angle < 0.01) &&
|
||||
(dist < nextDistance || (angle < 0.01 && nextAngle > 0.15))
|
||||
) {
|
||||
next = e;
|
||||
nextAngle = angle;
|
||||
nextDistance = dist;
|
||||
}
|
||||
|
||||
const offset = { x: diff.x * x, y: diff.y * y };
|
||||
if (
|
||||
offset.x >= 0 &&
|
||||
offset.y >= 0 &&
|
||||
(offset.x > 10 || offset.y > 10) &&
|
||||
dist < fallbackDistance
|
||||
) {
|
||||
fallback = e;
|
||||
fallbackDistance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
focus(next);
|
||||
} else if (fallback) {
|
||||
focus(fallback);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const { listen: listenButton } = useGamepadInputStack(zIndex);
|
||||
useEffect(() => {
|
||||
const bindMove = (x: number, y: number) => (e: GamepadButtonEvent) => {
|
||||
if (e.justPressed) {
|
||||
onMove(x, y);
|
||||
}
|
||||
};
|
||||
listenButton(BUTTON_MAP.dpad_up, bindMove(0, -1));
|
||||
listenButton(BUTTON_MAP.dpad_down, bindMove(0, 1));
|
||||
listenButton(BUTTON_MAP.dpad_left, bindMove(-1, 0));
|
||||
listenButton(BUTTON_MAP.dpad_right, bindMove(1, 0));
|
||||
}, [listenButton]);
|
||||
|
||||
useEffect(() => {
|
||||
const targetEl = divRef.current;
|
||||
if (!targetEl) return;
|
||||
|
||||
const list = availableElements.current;
|
||||
|
||||
function iter(node: HTMLElement, toRemove = false) {
|
||||
if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
if (toRemove) {
|
||||
list.delete(node);
|
||||
} else {
|
||||
list.add(node);
|
||||
const onMove = useCallback((x: number, y: number) => {
|
||||
const elements = availableElements.current;
|
||||
if (!elements) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const c of node.children) {
|
||||
if (c instanceof HTMLElement) {
|
||||
iter(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const o = new MutationObserver((mutationList: MutationRecord[]) => {
|
||||
for (const mutation of mutationList) {
|
||||
if (mutation.type == "childList") {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (node instanceof HTMLElement) {
|
||||
iter(node);
|
||||
const focus = (el: HTMLElement | undefined) => {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const node of mutation.removedNodes) {
|
||||
if (node instanceof HTMLElement) {
|
||||
iter(node, true);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
mutation.type == "attributes" &&
|
||||
mutation.attributeName == SELECTABLE_DATA_ATTR &&
|
||||
mutation.target instanceof HTMLElement
|
||||
) {
|
||||
const node = mutation.target;
|
||||
if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
list.add(node);
|
||||
} else if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
list.delete(node);
|
||||
}
|
||||
el.focus();
|
||||
};
|
||||
|
||||
const active = document.activeElement;
|
||||
if (!active?.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
focus(elements.values().next().value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
o.observe(targetEl, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributeFilter: [SELECTABLE_DATA_ATTR],
|
||||
});
|
||||
const angleOffset = Math.atan2(y, x);
|
||||
|
||||
iter(targetEl);
|
||||
const activeCenter = rectCenter(
|
||||
active.getBoundingClientRect(),
|
||||
active.getAttribute(SELECTABLE_DATA_ATTR),
|
||||
);
|
||||
|
||||
return () => o.disconnect();
|
||||
}, [divRef]);
|
||||
let next: HTMLElement | null = null;
|
||||
let nextAngle = Number.MAX_VALUE;
|
||||
let nextDistance = Number.MAX_VALUE;
|
||||
let fallback: HTMLElement | null = null;
|
||||
let fallbackDistance = Number.MAX_VALUE;
|
||||
for (const e of elements) {
|
||||
if (e === active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return <div ref={divRef} {...props} />;
|
||||
const c = rectCenter(
|
||||
e.getBoundingClientRect(),
|
||||
e.getAttribute(SELECTABLE_DATA_ATTR),
|
||||
);
|
||||
const diff = pointDiff(activeCenter, c);
|
||||
|
||||
let angle = Math.abs(angleOffset - Math.atan2(diff.y, diff.x));
|
||||
if (angle > Math.PI) {
|
||||
angle = Math.PI * 2 - angle;
|
||||
}
|
||||
const dist = distSquared(diff);
|
||||
if (
|
||||
angle < SELECTION_ANGLE &&
|
||||
(angle - nextAngle < 0.1 || angle < 0.01) &&
|
||||
(dist < nextDistance || (angle < 0.01 && nextAngle > 0.15))
|
||||
) {
|
||||
next = e;
|
||||
nextAngle = angle;
|
||||
nextDistance = dist;
|
||||
}
|
||||
|
||||
const offset = { x: diff.x * x, y: diff.y * y };
|
||||
if (
|
||||
offset.x >= 0 &&
|
||||
offset.y >= 0 &&
|
||||
(offset.x > 10 || offset.y > 10) &&
|
||||
dist < fallbackDistance
|
||||
) {
|
||||
fallback = e;
|
||||
fallbackDistance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
focus(next);
|
||||
} else if (fallback) {
|
||||
focus(fallback);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const { listen: listenButton } = useGamepadInputStack(zIndex);
|
||||
useEffect(() => {
|
||||
const bindMove = (x: number, y: number) => (e: GamepadButtonEvent) => {
|
||||
if (e.justPressed) {
|
||||
onMove(x, y);
|
||||
}
|
||||
};
|
||||
const unsub = [
|
||||
listenButton(BUTTON_MAP.dpad_up, bindMove(0, -1)),
|
||||
listenButton(BUTTON_MAP.dpad_down, bindMove(0, 1)),
|
||||
listenButton(BUTTON_MAP.dpad_left, bindMove(-1, 0)),
|
||||
listenButton(BUTTON_MAP.dpad_right, bindMove(1, 0)),
|
||||
];
|
||||
return () => {
|
||||
for (const u of unsub) {
|
||||
u();
|
||||
}
|
||||
};
|
||||
}, [listenButton, onMove]);
|
||||
|
||||
useEffect(() => {
|
||||
const targetEl = divRef.current;
|
||||
if (!targetEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const list = availableElements.current;
|
||||
|
||||
function iter(node: HTMLElement, toRemove = false) {
|
||||
if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
if (toRemove) {
|
||||
list.delete(node);
|
||||
} else {
|
||||
list.add(node);
|
||||
}
|
||||
}
|
||||
for (const c of node.children) {
|
||||
if (c instanceof HTMLElement) {
|
||||
iter(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const o = new MutationObserver((mutationList: MutationRecord[]) => {
|
||||
for (const mutation of mutationList) {
|
||||
if (mutation.type === "childList") {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (node instanceof HTMLElement) {
|
||||
iter(node);
|
||||
}
|
||||
}
|
||||
for (const node of mutation.removedNodes) {
|
||||
if (node instanceof HTMLElement) {
|
||||
iter(node, true);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
mutation.type === "attributes" &&
|
||||
mutation.attributeName === SELECTABLE_DATA_ATTR &&
|
||||
mutation.target instanceof HTMLElement
|
||||
) {
|
||||
const node = mutation.target;
|
||||
if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
list.add(node);
|
||||
} else if (node.hasAttribute(SELECTABLE_DATA_ATTR)) {
|
||||
list.delete(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
o.observe(targetEl, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributeFilter: [SELECTABLE_DATA_ATTR],
|
||||
});
|
||||
|
||||
iter(targetEl);
|
||||
|
||||
return () => o.disconnect();
|
||||
}, []);
|
||||
|
||||
return <div ref={divRef} {...props} />;
|
||||
}
|
||||
|
||||
@@ -1,105 +1,106 @@
|
||||
import { useAtomValue } from "jotai";
|
||||
import type { ReactElement } from "react";
|
||||
import { atomDownloadingOverlay } from "@/store/common";
|
||||
import { cn } from "@/utils/ui";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { Progress } from "./ui/progress";
|
||||
import { Spinner } from "./ui/spinner";
|
||||
|
||||
interface LoadingProps {
|
||||
message?: string;
|
||||
percent?: number;
|
||||
progress?: number;
|
||||
total?: number;
|
||||
format?: keyof typeof progressFormats;
|
||||
message?: string;
|
||||
percent?: number;
|
||||
progress?: number;
|
||||
total?: number;
|
||||
format?: keyof typeof progressFormats;
|
||||
}
|
||||
|
||||
const progressFormats = {
|
||||
data: (v: number) => {
|
||||
if (v > 1024 * 1024 * 1024) {
|
||||
return `${(v / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
||||
}
|
||||
if (v > 1024 * 1024) {
|
||||
return `${(v / (1024 * 1024)).toFixed(2)}MB`;
|
||||
}
|
||||
if (v > 1024) {
|
||||
return `${(v / 1024).toFixed(2)}KB`;
|
||||
}
|
||||
return `${v}B`;
|
||||
},
|
||||
"": (v: number) => v.toString(),
|
||||
data: (v: number) => {
|
||||
if (v > 1024 * 1024 * 1024) {
|
||||
return `${(v / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
||||
}
|
||||
if (v > 1024 * 1024) {
|
||||
return `${(v / (1024 * 1024)).toFixed(2)}MB`;
|
||||
}
|
||||
if (v > 1024) {
|
||||
return `${(v / 1024).toFixed(2)}KB`;
|
||||
}
|
||||
return `${v}B`;
|
||||
},
|
||||
"": (v: number) => v.toString(),
|
||||
} as const;
|
||||
|
||||
export function LoadingScreen({
|
||||
message,
|
||||
percent,
|
||||
progress,
|
||||
total,
|
||||
format,
|
||||
message,
|
||||
percent,
|
||||
progress,
|
||||
total,
|
||||
format,
|
||||
}: LoadingProps) {
|
||||
let indicator;
|
||||
let subText;
|
||||
let center = false;
|
||||
let indicator: ReactElement;
|
||||
let subText: string | undefined;
|
||||
let center = false;
|
||||
|
||||
if (typeof percent === "number") {
|
||||
indicator = <Progress value={percent} />;
|
||||
} else if (typeof progress === "number" && typeof total === "number") {
|
||||
indicator = <Progress value={(progress / total) * 100} />;
|
||||
} else {
|
||||
center = true;
|
||||
indicator = <Spinner size="large" />;
|
||||
}
|
||||
|
||||
const fmt = progressFormats[format || ""];
|
||||
|
||||
if (typeof progress !== "undefined") {
|
||||
if (typeof total !== "undefined") {
|
||||
subText = `${fmt(progress)}/${fmt(total)}`;
|
||||
if (typeof percent === "number") {
|
||||
indicator = <Progress value={percent} />;
|
||||
} else if (typeof progress === "number" && typeof total === "number") {
|
||||
indicator = <Progress value={(progress / total) * 100} />;
|
||||
} else {
|
||||
subText = `${fmt(progress)}`;
|
||||
center = true;
|
||||
indicator = <Spinner size="large" />;
|
||||
}
|
||||
} else if (typeof percent !== "undefined") {
|
||||
subText = `${percent}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="fixed inset-0 z-70 overflow-hidden bg-secondary opacity-70"></div>
|
||||
<div className="fixed inset-0 z-70 flex h-screen w-screen flex-col items-center justify-center overflow-hidden text-secondary-foreground">
|
||||
{message && <span className="text-xl">{message}</span>}
|
||||
<div
|
||||
className={cn("mt-2 flex h-12 flex-col", {
|
||||
"items-center": center,
|
||||
"w-2/3": !center,
|
||||
})}
|
||||
>
|
||||
{indicator}
|
||||
{subText && <span>{subText}</span>}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
const fmt = progressFormats[format || ""];
|
||||
|
||||
if (typeof progress !== "undefined") {
|
||||
if (typeof total !== "undefined") {
|
||||
subText = `${fmt(progress)}/${fmt(total)}`;
|
||||
} else {
|
||||
subText = `${fmt(progress)}`;
|
||||
}
|
||||
} else if (typeof percent !== "undefined") {
|
||||
subText = `${percent}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="fixed inset-0 z-70 overflow-hidden bg-secondary opacity-70" />
|
||||
<div className="fixed inset-0 z-70 flex h-screen w-screen flex-col items-center justify-center overflow-hidden text-secondary-foreground">
|
||||
{message && <span className="text-xl">{message}</span>}
|
||||
<div
|
||||
className={cn("mt-2 flex h-12 flex-col", {
|
||||
"items-center": center,
|
||||
"w-2/3": !center,
|
||||
})}
|
||||
>
|
||||
{indicator}
|
||||
{subText && <span>{subText}</span>}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function LoadingOverlay() {
|
||||
const value = useAtomValue(atomDownloadingOverlay);
|
||||
const value = useAtomValue(atomDownloadingOverlay);
|
||||
|
||||
if (!value) {
|
||||
return <></>;
|
||||
}
|
||||
if (!value) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const props: LoadingProps = {};
|
||||
const props: LoadingProps = {};
|
||||
|
||||
if ("percent" in value) {
|
||||
props.percent = value.percent;
|
||||
}
|
||||
if ("progress" in value && value.progress !== "infinity") {
|
||||
props.progress = value.progress;
|
||||
}
|
||||
if ("total" in value) {
|
||||
props.total = value.total;
|
||||
}
|
||||
if ("format" in value) {
|
||||
props.format = value.format;
|
||||
}
|
||||
if ("percent" in value) {
|
||||
props.percent = value.percent;
|
||||
}
|
||||
if ("progress" in value && value.progress !== "infinity") {
|
||||
props.progress = value.progress;
|
||||
}
|
||||
if ("total" in value) {
|
||||
props.total = value.total;
|
||||
}
|
||||
if ("format" in value) {
|
||||
props.format = value.format;
|
||||
}
|
||||
|
||||
return <LoadingScreen message={value.message} {...props} />;
|
||||
return <LoadingScreen message={value.message} {...props} />;
|
||||
}
|
||||
|
||||
@@ -1,149 +1,152 @@
|
||||
import { atomModalConfigIsOpen, oficialRepo } from "@/store/common";
|
||||
import { refreshGameLibrary } from "@/store/game-library";
|
||||
import {
|
||||
atomInstalledVersions,
|
||||
atomModalVersionManagerIsOpen,
|
||||
atomSelectedVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { cn } from "@/utils/ui";
|
||||
import { TooltipTrigger } from "@radix-ui/react-tooltip";
|
||||
import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
|
||||
import {
|
||||
Gamepad2,
|
||||
Pause,
|
||||
Play,
|
||||
RotateCcw,
|
||||
Search,
|
||||
Settings,
|
||||
Square,
|
||||
Gamepad2,
|
||||
Pause,
|
||||
Play,
|
||||
RotateCcw,
|
||||
Search,
|
||||
Settings,
|
||||
Square,
|
||||
} from "lucide-react";
|
||||
import { type ComponentProps, useState } from "react";
|
||||
import { atomModalConfigIsOpen, oficialRepo } from "@/store/common";
|
||||
import { refreshGameLibrary } from "@/store/game-library";
|
||||
import {
|
||||
atomInstalledVersions,
|
||||
atomModalVersionManagerIsOpen,
|
||||
atomSelectedVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { cn } from "@/utils/ui";
|
||||
import { Button } from "./ui/button";
|
||||
import { Input } from "./ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "./ui/select";
|
||||
import { Tooltip, TooltipContent } from "./ui/tooltip";
|
||||
|
||||
function VersionSelector() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const setVersionManagerModalOpen = useSetAtom(atomModalVersionManagerIsOpen);
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
const [selectVersion, setSelectedVersion] = useAtom(atomSelectedVersion);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const setVersionManagerModalOpen = useSetAtom(
|
||||
atomModalVersionManagerIsOpen,
|
||||
);
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
const [selectVersion, setSelectedVersion] = useAtom(atomSelectedVersion);
|
||||
|
||||
return (
|
||||
<Select
|
||||
open={isOpen}
|
||||
onOpenChange={(e) => setIsOpen(e)}
|
||||
value={selectVersion?.path}
|
||||
onValueChange={setSelectedVersion}
|
||||
>
|
||||
<SelectTrigger className="w-[180px] border-secondary-foreground">
|
||||
<SelectValue placeholder="No version selected" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Emulator Version</SelectLabel>
|
||||
{installedVersions.map((v) => (
|
||||
<SelectItem key={v.path} value={v.path}>
|
||||
{v.version} {v.repo != oficialRepo && `(${v.repo})`}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
setVersionManagerModalOpen(true);
|
||||
}}
|
||||
return (
|
||||
<Select
|
||||
onOpenChange={(e) => setIsOpen(e)}
|
||||
onValueChange={setSelectedVersion}
|
||||
open={isOpen}
|
||||
value={selectVersion?.path}
|
||||
>
|
||||
Open Version Manager
|
||||
</Button>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
<SelectTrigger className="w-[180px] border-secondary-foreground">
|
||||
<SelectValue placeholder="No version selected" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Emulator Version</SelectLabel>
|
||||
{installedVersions.map((v) => (
|
||||
<SelectItem key={v.path} value={v.path}>
|
||||
{v.version}{" "}
|
||||
{v.repo !== oficialRepo && `(${v.repo})`}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
setVersionManagerModalOpen(true);
|
||||
}}
|
||||
variant="ghost"
|
||||
>
|
||||
Open Version Manager
|
||||
</Button>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
function ToolbarButton({
|
||||
className,
|
||||
tooltip,
|
||||
...props
|
||||
className,
|
||||
tooltip,
|
||||
...props
|
||||
}: ComponentProps<typeof Button> & { tooltip?: string }) {
|
||||
const content = (
|
||||
<button
|
||||
className={cn(
|
||||
"rounded-md p-2 *:size-6 focus-within:bg-muted hover:bg-muted",
|
||||
className,
|
||||
)}
|
||||
data-gamepad-selectable
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
if (!tooltip) {
|
||||
return content;
|
||||
}
|
||||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
||||
<TooltipContent>{tooltip}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
const content = (
|
||||
<button
|
||||
className={cn(
|
||||
"rounded-md p-2 *:size-6 focus-within:bg-muted hover:bg-muted",
|
||||
className,
|
||||
)}
|
||||
data-gamepad-selectable
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
if (!tooltip) {
|
||||
return content;
|
||||
}
|
||||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
||||
<TooltipContent>{tooltip}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export function Toolbar() {
|
||||
const setConfigModalOpen = useSetAtom(atomModalConfigIsOpen);
|
||||
const store = useStore();
|
||||
const setConfigModalOpen = useSetAtom(atomModalConfigIsOpen);
|
||||
const store = useStore();
|
||||
|
||||
return (
|
||||
<div className="sticky top-0 z-30 flex justify-between bg-secondary p-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<ToolbarButton>
|
||||
<Play className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Pause className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Square className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
tooltip="Refresh Game Library"
|
||||
onClick={() => refreshGameLibrary(store)}
|
||||
>
|
||||
<RotateCcw className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
tooltip="Settings"
|
||||
onClick={() => setConfigModalOpen(true)}
|
||||
>
|
||||
<Settings className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Gamepad2 className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<VersionSelector />
|
||||
return (
|
||||
<div className="sticky top-0 z-30 flex justify-between bg-secondary p-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<ToolbarButton>
|
||||
<Play className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Pause className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Square className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => refreshGameLibrary(store)}
|
||||
tooltip="Refresh Game Library"
|
||||
>
|
||||
<RotateCcw className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => setConfigModalOpen(true)}
|
||||
tooltip="Settings"
|
||||
>
|
||||
<Settings className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton>
|
||||
<Gamepad2 className="h-6 w-6" />
|
||||
</ToolbarButton>
|
||||
<VersionSelector />
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-md flex-1">
|
||||
<div className="relative">
|
||||
<Search className="absolute top-2.5 left-2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
className="w-full border-muted bg-muted pl-8"
|
||||
data-gamepad-selectable="CENTER_LEFT"
|
||||
placeholder="Search..."
|
||||
type="search"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-md flex-1">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
data-gamepad-selectable="CENTER_LEFT"
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
className="w-full border-muted bg-muted pl-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow-sm hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow-sm hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants };
|
||||
|
||||
@@ -5,52 +5,52 @@ import * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
@@ -13,108 +13,108 @@ const DialogPortal = DialogPrimitive.Portal;
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<DialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=open]:animate-in",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
className={cn(
|
||||
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
));
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DialogHeader.displayName = "DialogHeader";
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DialogFooter.displayName = "DialogFooter";
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<DialogPrimitive.Title
|
||||
className={cn(
|
||||
"font-semibold text-lg leading-none tracking-tight",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
<DialogPrimitive.Description
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogTrigger,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogTrigger,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
};
|
||||
|
||||
@@ -3,19 +3,19 @@ import * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-colors file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
type={type}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
|
||||
@@ -5,19 +5,19 @@ import * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
<LabelPrimitive.Root
|
||||
className={cn(labelVariants(), className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import * as React from "react";
|
||||
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const Progress = React.forwardRef<
|
||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||
>(({ className, value, ...props }, ref) => (
|
||||
<ProgressPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ProgressPrimitive.Indicator
|
||||
className="h-full w-full flex-1 bg-primary transition-all"
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
<ProgressPrimitive.Root
|
||||
className={cn(
|
||||
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<ProgressPrimitive.Indicator
|
||||
className="h-full w-full flex-1 bg-primary transition-all"
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
));
|
||||
Progress.displayName = ProgressPrimitive.Root.displayName;
|
||||
|
||||
|
||||
@@ -4,42 +4,44 @@ import * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
<ScrollAreaPrimitive.Root
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
));
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<
|
||||
typeof ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className,
|
||||
)}
|
||||
orientation={orientation}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
));
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
@@ -11,147 +11,147 @@ const SelectGroup = SelectPrimitive.Group;
|
||||
const SelectValue = SelectPrimitive.Value;
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-placeholder:text-muted-foreground [&>span]:line-clamp-1",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
<SelectPrimitive.Trigger
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-placeholder:text-muted-foreground [&>span]:line-clamp-1",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
));
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
|
||||
const SelectScrollUpButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
));
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||
|
||||
const SelectScrollDownButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
));
|
||||
SelectScrollDownButton.displayName =
|
||||
SelectPrimitive.ScrollDownButton.displayName;
|
||||
SelectPrimitive.ScrollDownButton.displayName;
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
className={cn(
|
||||
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in",
|
||||
position === "popper" &&
|
||||
"data-[side=left]:-translate-x-1 data-[side=top]:-translate-y-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1",
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
));
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
<SelectPrimitive.Label
|
||||
className={cn("px-2 py-1.5 font-semibold text-sm", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
<SelectPrimitive.Item
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
));
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
<SelectPrimitive.Separator
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
};
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
function Skeleton({
|
||||
className,
|
||||
...props
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-primary/10", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-primary/10", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Skeleton };
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
import { useTheme } from "next-themes"
|
||||
import { Toaster as Sonner } from "sonner"
|
||||
import { useTheme } from "next-themes";
|
||||
import { Toaster as Sonner } from "sonner";
|
||||
|
||||
type ToasterProps = React.ComponentProps<typeof Sonner>
|
||||
type ToasterProps = React.ComponentProps<typeof Sonner>;
|
||||
|
||||
const Toaster = ({ ...props }: ToasterProps) => {
|
||||
const { theme = "system" } = useTheme()
|
||||
const { theme = "system" } = useTheme();
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
className="toaster group"
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast:
|
||||
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
||||
description: "group-[.toast]:text-muted-foreground",
|
||||
actionButton:
|
||||
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
||||
cancelButton:
|
||||
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Sonner
|
||||
className="toaster group"
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
||||
description: "group-[.toast]:text-muted-foreground",
|
||||
actionButton:
|
||||
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
||||
cancelButton:
|
||||
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export { Toaster }
|
||||
export { Toaster };
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
import { cn } from "@/utils/ui";
|
||||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import type * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const spinnerVariants = cva("flex-col items-center justify-center", {
|
||||
variants: {
|
||||
show: {
|
||||
true: "flex",
|
||||
false: "hidden",
|
||||
variants: {
|
||||
show: {
|
||||
true: "flex",
|
||||
false: "hidden",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
show: true,
|
||||
},
|
||||
});
|
||||
|
||||
const loaderVariants = cva("animate-spin text-primary", {
|
||||
variants: {
|
||||
size: {
|
||||
small: "size-6",
|
||||
medium: "size-8",
|
||||
large: "size-12",
|
||||
variants: {
|
||||
size: {
|
||||
small: "size-6",
|
||||
medium: "size-8",
|
||||
large: "size-12",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "medium",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "medium",
|
||||
},
|
||||
});
|
||||
|
||||
interface SpinnerContentProps
|
||||
extends VariantProps<typeof spinnerVariants>,
|
||||
VariantProps<typeof loaderVariants> {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
extends VariantProps<typeof spinnerVariants>,
|
||||
VariantProps<typeof loaderVariants> {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Spinner({
|
||||
size,
|
||||
show,
|
||||
children,
|
||||
className,
|
||||
size,
|
||||
show,
|
||||
children,
|
||||
className,
|
||||
}: SpinnerContentProps) {
|
||||
return (
|
||||
<span className={spinnerVariants({ show })}>
|
||||
<Loader2 className={cn(loaderVariants({ size }), className)} />
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<span className={spinnerVariants({ show })}>
|
||||
<Loader2 className={cn(loaderVariants({ size }), className)} />
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,118 +3,118 @@ import * as React from "react";
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
ref={ref}
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
Table.displayName = "Table";
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
<thead className={cn("[&_tr]:border-b", className)} ref={ref} {...props} />
|
||||
));
|
||||
TableHeader.displayName = "TableHeader";
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody
|
||||
ref={ref}
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
<tbody
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableBody.displayName = "TableBody";
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium last:[&>tr]:border-b-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<tfoot
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium last:[&>tr]:border-b-0",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableFooter.displayName = "TableFooter";
|
||||
|
||||
const TableRow = React.forwardRef<
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<tr
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableRow.displayName = "TableRow";
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<th
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableHead.displayName = "TableHead";
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<td
|
||||
className={cn(
|
||||
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableCell.displayName = "TableCell";
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
<caption
|
||||
className={cn("mt-4 text-muted-foreground text-sm", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TableCaption.displayName = "TableCaption";
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
};
|
||||
|
||||
@@ -6,47 +6,47 @@ import { cn } from "@/utils/ui";
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.List
|
||||
className={cn(
|
||||
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.Trigger
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 font-medium text-sm ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.Content
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
@@ -10,20 +10,20 @@ const Tooltip = TooltipPrimitive.Root;
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
className={cn(
|
||||
"fade-in-0 zoom-in-95 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 animate-in overflow-hidden rounded-md bg-primary px-3 py-1.5 text-primary-foreground text-xs data-[state=closed]:animate-out",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
{...props}
|
||||
/>
|
||||
</TooltipPrimitive.Portal>
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
|
||||
@@ -1,237 +1,246 @@
|
||||
import { installNewVersion } from "@/handlers/version-manager";
|
||||
import { atomEmuInstallsPath } from "@/store/paths";
|
||||
import {
|
||||
atomAvailableVersions,
|
||||
atomInstalledVersions,
|
||||
atomModalVersionManagerIsOpen,
|
||||
type RemoteEmulatorVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { format } from "date-fns";
|
||||
import { useAtom, useAtomValue, useStore } from "jotai";
|
||||
import { Check, CircleSlash, Plus } from "lucide-react";
|
||||
import { type ReactNode, useEffect, useState } from "react";
|
||||
import { installNewVersion } from "@/handlers/version-manager";
|
||||
import { atomEmuInstallsPath } from "@/store/paths";
|
||||
import {
|
||||
atomAvailableVersions,
|
||||
atomInstalledVersions,
|
||||
atomModalVersionManagerIsOpen,
|
||||
type RemoteEmulatorVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Button } from "./ui/button";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog";
|
||||
import { ScrollArea } from "./ui/scroll-area";
|
||||
import { Spinner } from "./ui/spinner";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "./ui/table";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
||||
|
||||
function VersionTableRow({
|
||||
source,
|
||||
date,
|
||||
version,
|
||||
release,
|
||||
prePelease: preRelease,
|
||||
children,
|
||||
source,
|
||||
date,
|
||||
version,
|
||||
release,
|
||||
prePelease: preRelease,
|
||||
children,
|
||||
}: {
|
||||
source: string;
|
||||
date: string;
|
||||
version: string;
|
||||
release?: string;
|
||||
prePelease?: boolean;
|
||||
children?: ReactNode;
|
||||
source: string;
|
||||
date: string;
|
||||
version: string;
|
||||
release?: string;
|
||||
prePelease?: boolean;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell>{source}</TableCell>
|
||||
<TableCell>{date}</TableCell>
|
||||
<TableCell>{version}</TableCell>
|
||||
<TableCell>
|
||||
{preRelease === true ? (
|
||||
<Badge variant="destructive">Pre-release</Badge>
|
||||
) : (
|
||||
release
|
||||
)}
|
||||
</TableCell>
|
||||
{children}
|
||||
</TableRow>
|
||||
);
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell>{source}</TableCell>
|
||||
<TableCell>{date}</TableCell>
|
||||
<TableCell>{version}</TableCell>
|
||||
<TableCell>
|
||||
{preRelease === true ? (
|
||||
<Badge variant="destructive">Pre-release</Badge>
|
||||
) : (
|
||||
release
|
||||
)}
|
||||
</TableCell>
|
||||
{children}
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
function DownloadButton({
|
||||
version: v,
|
||||
onClick,
|
||||
version: v,
|
||||
onClick,
|
||||
}: {
|
||||
version: RemoteEmulatorVersion;
|
||||
onClick: () => void;
|
||||
version: RemoteEmulatorVersion;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
|
||||
const alreadyInstalled = installedVersions.some(
|
||||
(e) => e.repo == v.repo && e.version == v.version,
|
||||
);
|
||||
|
||||
if (alreadyInstalled) {
|
||||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="cursor-default hover:bg-inherit"
|
||||
>
|
||||
{" "}
|
||||
<Check />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<span>Already Installed</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
const alreadyInstalled = installedVersions.some(
|
||||
(e) => e.repo === v.repo && e.version === v.version,
|
||||
);
|
||||
}
|
||||
|
||||
if (v.notSupported) {
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button size="icon" variant="outline" disabled>
|
||||
<CircleSlash />
|
||||
if (alreadyInstalled) {
|
||||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="cursor-default hover:bg-inherit"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
{" "}
|
||||
<Check />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<span>Already Installed</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
if (v.notSupported) {
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button disabled size="icon" variant="outline">
|
||||
<CircleSlash />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<span>Not Supported In Your Platform</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button onClick={onClick} size="icon" variant="outline">
|
||||
<Plus />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<span>Not Supported In Your Platform</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button size="icon" variant="outline" onClick={onClick}>
|
||||
<Plus />
|
||||
</Button>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
function AddNewVersion() {
|
||||
const { data, isLoading, error } = useAtomValue(atomAvailableVersions);
|
||||
const rootInstallPath = useAtomValue(atomEmuInstallsPath);
|
||||
const store = useStore();
|
||||
const { data, isLoading, error } = useAtomValue(atomAvailableVersions);
|
||||
const rootInstallPath = useAtomValue(atomEmuInstallsPath);
|
||||
const store = useStore();
|
||||
|
||||
const install = (v: RemoteEmulatorVersion) => {
|
||||
if (rootInstallPath) {
|
||||
void installNewVersion(v, rootInstallPath);
|
||||
const install = (v: RemoteEmulatorVersion) => {
|
||||
if (rootInstallPath) {
|
||||
void installNewVersion(v, rootInstallPath);
|
||||
}
|
||||
store.set(atomModalVersionManagerIsOpen, false);
|
||||
};
|
||||
|
||||
let content = null;
|
||||
if (isLoading) {
|
||||
content = <Spinner />;
|
||||
} else if (error) {
|
||||
content = <span className="text-red-500">{error.message}</span>;
|
||||
} else {
|
||||
content = (
|
||||
<Table className="gap-4">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Source</TableHead>
|
||||
<TableHead>Date</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Release</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.map((v) => (
|
||||
<VersionTableRow
|
||||
date={format(v.date, "PP")}
|
||||
key={JSON.stringify(v)}
|
||||
prePelease={v.prerelease}
|
||||
release={v.name}
|
||||
source={v.repo}
|
||||
version={v.version}
|
||||
>
|
||||
<TableCell>
|
||||
<DownloadButton
|
||||
onClick={() => install(v)}
|
||||
version={v}
|
||||
/>
|
||||
</TableCell>
|
||||
</VersionTableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
store.set(atomModalVersionManagerIsOpen, false);
|
||||
};
|
||||
|
||||
let content = null;
|
||||
if (isLoading) {
|
||||
content = <Spinner />;
|
||||
} else if (error) {
|
||||
content = <span className="text-red-500">{error.message}</span>;
|
||||
} else {
|
||||
content = (
|
||||
<Table className="gap-4">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Source</TableHead>
|
||||
<TableHead>Date</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Release</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.map((v, i) => (
|
||||
<VersionTableRow
|
||||
key={i}
|
||||
source={v.repo}
|
||||
date={format(v.date, "PP")}
|
||||
version={v.version}
|
||||
release={v.name}
|
||||
prePelease={v.prerelease}
|
||||
>
|
||||
<TableCell>
|
||||
<DownloadButton version={v} onClick={() => install(v)} />
|
||||
</TableCell>
|
||||
</VersionTableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
return (
|
||||
<DialogContent className="min-w-[525px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Add New Version</DialogTitle>
|
||||
</DialogHeader>
|
||||
<ScrollArea className="max-h-[60vh]">{content}</ScrollArea>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DialogContent className="min-w-[525px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Add New Version</DialogTitle>
|
||||
</DialogHeader>
|
||||
<ScrollArea className="max-h-[60vh]">{content}</ScrollArea>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
export function VersionManagerModal() {
|
||||
const [isOpen, setIsOpen] = useAtom(atomModalVersionManagerIsOpen);
|
||||
const [isNew, setIsNew] = useState(false);
|
||||
const [isOpen, setIsOpen] = useAtom(atomModalVersionManagerIsOpen);
|
||||
const [isNew, setIsNew] = useState(false);
|
||||
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
const installedVersions = useAtomValue(atomInstalledVersions);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setIsNew(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setIsNew(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
{isNew ? (
|
||||
<AddNewVersion />
|
||||
) : (
|
||||
<DialogContent className="min-w-[525px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<div className="flex items-center gap-4">
|
||||
<span>Version Manager</span>
|
||||
<Button size="sm" onClick={() => setIsNew(true)}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex">
|
||||
<Table className="gap-4">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Source</TableHead>
|
||||
<TableHead>Date</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Release</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{installedVersions.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} className="text-center">
|
||||
No version installed
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
installedVersions.map((v, i) => (
|
||||
<VersionTableRow
|
||||
key={i}
|
||||
source={v.repo}
|
||||
date={format(v.date, "PP")}
|
||||
version={v.version}
|
||||
release={v.name}
|
||||
prePelease={v.prerelease}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</DialogContent>
|
||||
)}
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Dialog onOpenChange={setIsOpen} open={isOpen}>
|
||||
{isNew ? (
|
||||
<AddNewVersion />
|
||||
) : (
|
||||
<DialogContent className="min-w-[525px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<div className="flex items-center gap-4">
|
||||
<span>Version Manager</span>
|
||||
<Button
|
||||
onClick={() => setIsNew(true)}
|
||||
size="sm"
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex">
|
||||
<Table className="gap-4">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Source</TableHead>
|
||||
<TableHead>Date</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Release</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{installedVersions.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
className="text-center"
|
||||
colSpan={4}
|
||||
>
|
||||
No version installed
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
installedVersions.map((v) => (
|
||||
<VersionTableRow
|
||||
date={format(v.date, "PP")}
|
||||
key={JSON.stringify(v)}
|
||||
prePelease={v.prerelease}
|
||||
release={v.name}
|
||||
source={v.repo}
|
||||
version={v.version}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</DialogContent>
|
||||
)}
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { gamepadActiveAtom } from "@/store/gamepad";
|
||||
import { defaultStore } from "@/store";
|
||||
import { gamepadActiveAtom } from "@/store/gamepad";
|
||||
|
||||
export interface GamepadButtonEvent {
|
||||
button: number;
|
||||
pressed: boolean;
|
||||
justPressed: boolean;
|
||||
repeating: boolean;
|
||||
button: number;
|
||||
pressed: boolean;
|
||||
justPressed: boolean;
|
||||
repeating: boolean;
|
||||
}
|
||||
|
||||
// Axis is 100+ buttons e.g. axis 0 is button 100, axis 1 is button 101
|
||||
@@ -17,87 +17,99 @@ const buttonRepeatTime: number[] = [];
|
||||
const deadZone = 0.4;
|
||||
|
||||
const gamepadRelease = () => {
|
||||
defaultStore.set(gamepadActiveAtom, false);
|
||||
defaultStore.set(gamepadActiveAtom, false);
|
||||
};
|
||||
|
||||
const gamepadAcquire = () => {
|
||||
defaultStore.set(gamepadActiveAtom, true);
|
||||
defaultStore.set(gamepadActiveAtom, true);
|
||||
};
|
||||
|
||||
function gamepadLoop() {
|
||||
try {
|
||||
const now = Date.now();
|
||||
for (const gamepad of navigator.getGamepads()) {
|
||||
if (!gamepad) continue;
|
||||
try {
|
||||
const now = Date.now();
|
||||
for (const gamepad of navigator.getGamepads()) {
|
||||
if (!gamepad) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const btnLen = gamepad.buttons.length;
|
||||
const baseArr = -gamepad.axes.length * 2;
|
||||
for (let i = baseArr; i < btnLen; ++i) {
|
||||
let pressed: boolean;
|
||||
let btn_id: number;
|
||||
if (i >= 0) {
|
||||
btn_id = i;
|
||||
const btn = gamepad.buttons[i];
|
||||
if (!btn) continue;
|
||||
pressed = btn.pressed;
|
||||
} else {
|
||||
const idx = ((i + baseArr) / 2) | 0;
|
||||
btn_id = idx + 100;
|
||||
const axis = gamepad.axes[idx];
|
||||
if (axis === undefined) continue;
|
||||
pressed = i & 1 ? axis > deadZone : axis < -deadZone;
|
||||
}
|
||||
const wasPressed = buttonState[i] || false;
|
||||
buttonState[i] = pressed;
|
||||
const justPressed = pressed && !wasPressed;
|
||||
if (justPressed) {
|
||||
buttonRepeatTime[i] = now + 1600; // first repeat
|
||||
}
|
||||
const repeating = pressed && (buttonRepeatTime[i] || 0) > now;
|
||||
if (repeating) {
|
||||
buttonRepeatTime[i] = now + 200; // following repeats
|
||||
}
|
||||
if (pressed) {
|
||||
gamepadAcquire();
|
||||
}
|
||||
const e: GamepadButtonEvent = {
|
||||
button: btn_id,
|
||||
pressed,
|
||||
justPressed,
|
||||
repeating,
|
||||
};
|
||||
const btnLen = gamepad.buttons.length;
|
||||
const baseArr = -gamepad.axes.length * 2;
|
||||
for (let i = baseArr; i < btnLen; ++i) {
|
||||
let pressed: boolean;
|
||||
let btn_id: number;
|
||||
if (i >= 0) {
|
||||
btn_id = i;
|
||||
const btn = gamepad.buttons[i];
|
||||
if (!btn) {
|
||||
continue;
|
||||
}
|
||||
pressed = btn.pressed;
|
||||
} else {
|
||||
const idx = ((i + baseArr) / 2) | 0;
|
||||
btn_id = idx + 100;
|
||||
const axis = gamepad.axes[idx];
|
||||
if (axis === undefined) {
|
||||
continue;
|
||||
}
|
||||
pressed = i & 1 ? axis > deadZone : axis < -deadZone;
|
||||
}
|
||||
const wasPressed = buttonState[i] || false;
|
||||
buttonState[i] = pressed;
|
||||
const justPressed = pressed && !wasPressed;
|
||||
if (justPressed) {
|
||||
buttonRepeatTime[i] = now + 1600; // first repeat
|
||||
}
|
||||
const repeating = pressed && (buttonRepeatTime[i] || 0) > now;
|
||||
if (repeating) {
|
||||
buttonRepeatTime[i] = now + 200; // following repeats
|
||||
}
|
||||
if (pressed) {
|
||||
gamepadAcquire();
|
||||
}
|
||||
const e: GamepadButtonEvent = {
|
||||
button: btn_id,
|
||||
pressed,
|
||||
justPressed,
|
||||
repeating,
|
||||
};
|
||||
|
||||
callbackList.forEach((c) => c(e));
|
||||
}
|
||||
for (const c of callbackList) {
|
||||
c(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Gamepad read error", e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Gamepad read error", e);
|
||||
}
|
||||
requestAnimationFrame(gamepadLoop);
|
||||
requestAnimationFrame(gamepadLoop);
|
||||
}
|
||||
|
||||
export function startGamepadHandler() {
|
||||
requestAnimationFrame(gamepadLoop);
|
||||
window.addEventListener("mousemove", gamepadRelease);
|
||||
window.addEventListener("keydown", gamepadRelease);
|
||||
window.addEventListener("gamepadconnected", gamepadAcquire);
|
||||
window.addEventListener("gamepaddisconnected", gamepadRelease);
|
||||
requestAnimationFrame(gamepadLoop);
|
||||
window.addEventListener("mousemove", gamepadRelease);
|
||||
window.addEventListener("keydown", gamepadRelease);
|
||||
window.addEventListener("gamepadconnected", gamepadAcquire);
|
||||
window.addEventListener("gamepaddisconnected", gamepadRelease);
|
||||
}
|
||||
|
||||
export function addGamepadButtonListener(
|
||||
callback: (e: GamepadButtonEvent) => void,
|
||||
callback: (e: GamepadButtonEvent) => void,
|
||||
) {
|
||||
const e = callbackList.indexOf(callback);
|
||||
if (e !== -1) return;
|
||||
const e = callbackList.indexOf(callback);
|
||||
if (e !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
callbackList.push(callback);
|
||||
callbackList.push(callback);
|
||||
}
|
||||
|
||||
export function removeGamepadButtonListener(
|
||||
callback: (e: GamepadButtonEvent) => void,
|
||||
callback: (e: GamepadButtonEvent) => void,
|
||||
) {
|
||||
const e = callbackList.indexOf(callback);
|
||||
if (e === -1) return;
|
||||
const e = callbackList.indexOf(callback);
|
||||
if (e === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
callbackList.splice(e);
|
||||
callbackList.splice(e);
|
||||
}
|
||||
|
||||
40
src/handlers/run-emu.ts
Normal file
40
src/handlers/run-emu.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { appDataDir, join } from "@tauri-apps/api/path";
|
||||
import { exists, mkdir } from "@tauri-apps/plugin-fs";
|
||||
import { platform } from "@tauri-apps/plugin-os";
|
||||
import { toast } from "sonner";
|
||||
import { startGameProcess } from "@/lib/native-calls";
|
||||
import type { EmulatorVersion } from "@/store/version-manager";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
|
||||
export async function startGame(emu: EmulatorVersion, gameDir: string) {
|
||||
const gameBinary = await join(gameDir, "eboot.bin");
|
||||
if (!(await exists(gameBinary))) {
|
||||
const msg = "Game binary (eboot.bin) not found";
|
||||
toast.error(msg);
|
||||
console.warn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const suffix = platform() === "windows" ? ".exe" : "";
|
||||
|
||||
const emuBinary = await join(emu.path, `shadPS4${suffix}`);
|
||||
if (!(await exists(emuBinary))) {
|
||||
const msg = "Emulator binary not found";
|
||||
toast.error(msg);
|
||||
console.warn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const workDir = await join(await appDataDir(), "emu_data");
|
||||
if (!(await exists(workDir))) {
|
||||
await mkdir(workDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
await startGameProcess(emuBinary, workDir, gameBinary);
|
||||
} catch (e) {
|
||||
const msg = `Couldn't start the game: ${stringifyError(e)}`;
|
||||
console.error(msg);
|
||||
toast.error(msg);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { startGameProcess } from "@/lib/native-calls";
|
||||
import { type EmulatorVersion } from "@/store/version-manager";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
import { appDataDir, join } from "@tauri-apps/api/path";
|
||||
import { exists, mkdir } from "@tauri-apps/plugin-fs";
|
||||
import { platform } from "@tauri-apps/plugin-os";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export async function startGame(emu: EmulatorVersion, gameDir: string) {
|
||||
const gameBinary = await join(gameDir, "eboot.bin");
|
||||
if (!(await exists(gameBinary))) {
|
||||
const msg = "Game binary (eboot.bin) not found";
|
||||
toast.error(msg);
|
||||
console.warn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const suffix = platform() == "windows" ? ".exe" : "";
|
||||
|
||||
const emuBinary = await join(emu.path, "shadPS4" + suffix);
|
||||
if (!(await exists(emuBinary))) {
|
||||
const msg = "Emulator binary not found";
|
||||
toast.error(msg);
|
||||
console.warn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const workDir = await join(await appDataDir(), "emu_data");
|
||||
if (!(await exists(workDir))) {
|
||||
await mkdir(workDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
await startGameProcess(emuBinary, workDir, gameBinary);
|
||||
} catch (e) {
|
||||
const msg = "Couldn't start the game: " + stringifyError(e);
|
||||
console.error(msg);
|
||||
toast.error(msg);
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,90 @@
|
||||
import { extractZip } from "@/lib/native-calls";
|
||||
import { defaultStore } from "@/store";
|
||||
import { atomDownloadingOverlay } from "@/store/common";
|
||||
import {
|
||||
refreshInstalledVersion,
|
||||
type EmulatorVersion,
|
||||
type RemoteEmulatorVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
import { join, tempDir } from "@tauri-apps/api/path";
|
||||
import { exists, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
||||
import { download } from "@tauri-apps/plugin-upload";
|
||||
import { toast } from "sonner";
|
||||
import * as superjson from "superjson";
|
||||
import { extractZip } from "@/lib/native-calls";
|
||||
import { defaultStore } from "@/store";
|
||||
import { atomDownloadingOverlay } from "@/store/common";
|
||||
import {
|
||||
type EmulatorVersion,
|
||||
type RemoteEmulatorVersion,
|
||||
refreshInstalledVersion,
|
||||
} from "@/store/version-manager";
|
||||
import { stringifyError } from "@/utils/error";
|
||||
|
||||
export async function writeConfig({ path, ...config }: EmulatorVersion) {
|
||||
const data = superjson.stringify(config);
|
||||
const metaPath = await join(path, "meta.json");
|
||||
await writeTextFile(metaPath, data);
|
||||
const data = superjson.stringify(config);
|
||||
const metaPath = await join(path, "meta.json");
|
||||
await writeTextFile(metaPath, data);
|
||||
}
|
||||
|
||||
export async function readConfig(
|
||||
path: string,
|
||||
path: string,
|
||||
): Promise<EmulatorVersion | null> {
|
||||
const metaPath = await join(path, "meta.json");
|
||||
if (!(await exists(metaPath))) {
|
||||
return null;
|
||||
}
|
||||
const data = await readTextFile(metaPath);
|
||||
return {
|
||||
...superjson.parse<EmulatorVersion>(data),
|
||||
path,
|
||||
};
|
||||
const metaPath = await join(path, "meta.json");
|
||||
if (!(await exists(metaPath))) {
|
||||
return null;
|
||||
}
|
||||
const data = await readTextFile(metaPath);
|
||||
return {
|
||||
...superjson.parse<EmulatorVersion>(data),
|
||||
path,
|
||||
};
|
||||
}
|
||||
|
||||
export async function installNewVersion(
|
||||
version: RemoteEmulatorVersion,
|
||||
rootInstallPath: string,
|
||||
version: RemoteEmulatorVersion,
|
||||
rootInstallPath: string,
|
||||
) {
|
||||
try {
|
||||
defaultStore.set(atomDownloadingOverlay, {
|
||||
message: "Downloading",
|
||||
progress: "infinity",
|
||||
});
|
||||
const folderName = `${version.repo}-${version.version}`.replaceAll(
|
||||
/[^\w.]/g,
|
||||
"-",
|
||||
);
|
||||
let installPath;
|
||||
let i = 1;
|
||||
do {
|
||||
const name = i <= 1 ? folderName : `${folderName}-${i}`;
|
||||
i++;
|
||||
installPath = await join(rootInstallPath, name);
|
||||
} while (await exists(installPath));
|
||||
try {
|
||||
defaultStore.set(atomDownloadingOverlay, {
|
||||
message: "Downloading",
|
||||
progress: "infinity",
|
||||
});
|
||||
const folderName = `${version.repo}-${version.version}`.replaceAll(
|
||||
/[^\w.]/g,
|
||||
"-",
|
||||
);
|
||||
let installPath: string;
|
||||
let i = 1;
|
||||
do {
|
||||
const name = i <= 1 ? folderName : `${folderName}-${i}`;
|
||||
i++;
|
||||
installPath = await join(rootInstallPath, name);
|
||||
} while (await exists(installPath));
|
||||
|
||||
const tmpPath = await join(await tempDir(), "shardps4-artifact.zip");
|
||||
const tmpPath = await join(await tempDir(), "shardps4-artifact.zip");
|
||||
|
||||
await download(version.url, tmpPath, ({ progressTotal, total }) => {
|
||||
defaultStore.set(
|
||||
atomDownloadingOverlay,
|
||||
total > 0
|
||||
? {
|
||||
message: "Downloading",
|
||||
progress: progressTotal,
|
||||
total,
|
||||
format: "data",
|
||||
}
|
||||
: { message: "Downloading", progress: "infinity" },
|
||||
);
|
||||
});
|
||||
await download(version.url, tmpPath, ({ progressTotal, total }) => {
|
||||
defaultStore.set(
|
||||
atomDownloadingOverlay,
|
||||
total > 0
|
||||
? {
|
||||
message: "Downloading",
|
||||
progress: progressTotal,
|
||||
total,
|
||||
format: "data",
|
||||
}
|
||||
: { message: "Downloading", progress: "infinity" },
|
||||
);
|
||||
});
|
||||
|
||||
defaultStore.set(atomDownloadingOverlay, {
|
||||
message: "Extracting",
|
||||
progress: "infinity",
|
||||
});
|
||||
await extractZip(tmpPath, installPath);
|
||||
await writeConfig({ ...version, path: installPath });
|
||||
defaultStore.set(atomDownloadingOverlay, {
|
||||
message: "Extracting",
|
||||
progress: "infinity",
|
||||
});
|
||||
await extractZip(tmpPath, installPath);
|
||||
await writeConfig({ ...version, path: installPath });
|
||||
|
||||
defaultStore.set(atomDownloadingOverlay, null);
|
||||
defaultStore.set(atomDownloadingOverlay, null);
|
||||
|
||||
refreshInstalledVersion(defaultStore);
|
||||
toast.success("Installed");
|
||||
} catch (e: unknown) {
|
||||
toast.error(stringifyError(e));
|
||||
console.error(e);
|
||||
debugger;
|
||||
} finally {
|
||||
defaultStore.set(atomDownloadingOverlay, null);
|
||||
}
|
||||
refreshInstalledVersion(defaultStore);
|
||||
toast.success("Installed");
|
||||
} catch (e: unknown) {
|
||||
toast.error(stringifyError(e));
|
||||
console.error(e);
|
||||
} finally {
|
||||
defaultStore.set(atomDownloadingOverlay, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { createAbort } from "@/utils/events";
|
||||
import { useEffect, useState } from "react";
|
||||
import { createAbort } from "@/utils/events";
|
||||
|
||||
export function useAbort(): [signal: AbortSignal, abort: () => void] {
|
||||
const [{ signal, abort }] = useState(() => createAbort());
|
||||
const [{ signal, abort }] = useState(() => createAbort());
|
||||
|
||||
useEffect(() => {
|
||||
return () => abort();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
return () => abort();
|
||||
}, [abort]);
|
||||
|
||||
return [signal, abort];
|
||||
return [signal, abort];
|
||||
}
|
||||
|
||||
@@ -1,54 +1,56 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
export function useFocus(globalFilter?: (element: HTMLElement) => boolean) {
|
||||
const getElements = useCallback(
|
||||
(
|
||||
filter: ((element: HTMLElement) => boolean) | undefined = globalFilter,
|
||||
) => {
|
||||
const elements = Array.from<HTMLElement>(
|
||||
document.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
|
||||
),
|
||||
);
|
||||
const getElements = useCallback(
|
||||
(
|
||||
filter:
|
||||
| ((element: HTMLElement) => boolean)
|
||||
| undefined = globalFilter,
|
||||
) => {
|
||||
const elements = Array.from<HTMLElement>(
|
||||
document.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
|
||||
),
|
||||
);
|
||||
|
||||
if (filter) {
|
||||
return elements.filter(filter);
|
||||
}
|
||||
if (filter) {
|
||||
return elements.filter(filter);
|
||||
}
|
||||
|
||||
return elements;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const focusNext = useCallback(() => {
|
||||
const elements = getElements();
|
||||
if (!document.activeElement) {
|
||||
elements[0]!.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const currentIndex = elements.indexOf(
|
||||
document.activeElement as HTMLElement,
|
||||
return elements;
|
||||
},
|
||||
[globalFilter],
|
||||
);
|
||||
if (currentIndex !== -1 && currentIndex < elements.length - 1) {
|
||||
elements[currentIndex + 1]!.focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const focusPrevious = useCallback(() => {
|
||||
const elements = getElements();
|
||||
if (!document.activeElement) {
|
||||
elements[elements.length - 1]!.focus();
|
||||
return;
|
||||
}
|
||||
const focusNext = useCallback(() => {
|
||||
const elements = getElements();
|
||||
if (!document.activeElement) {
|
||||
elements[0]?.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const currentIndex = elements.indexOf(
|
||||
document.activeElement as HTMLElement,
|
||||
);
|
||||
if (currentIndex !== -1 && currentIndex > 0) {
|
||||
elements[currentIndex - 1]!.focus();
|
||||
}
|
||||
}, []);
|
||||
const currentIndex = elements.indexOf(
|
||||
document.activeElement as HTMLElement,
|
||||
);
|
||||
if (currentIndex !== -1 && currentIndex < elements.length - 1) {
|
||||
elements[currentIndex + 1]?.focus();
|
||||
}
|
||||
}, [getElements]);
|
||||
|
||||
return { getElements, next: focusNext, previous: focusPrevious };
|
||||
const focusPrevious = useCallback(() => {
|
||||
const elements = getElements();
|
||||
if (!document.activeElement) {
|
||||
elements[elements.length - 1]?.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const currentIndex = elements.indexOf(
|
||||
document.activeElement as HTMLElement,
|
||||
);
|
||||
if (currentIndex !== -1 && currentIndex > 0) {
|
||||
elements[currentIndex - 1]?.focus();
|
||||
}
|
||||
}, [getElements]);
|
||||
|
||||
return { getElements, next: focusNext, previous: focusPrevious };
|
||||
}
|
||||
|
||||
@@ -1,37 +1,41 @@
|
||||
import { type GamepadButtonEvent } from "@/handlers/gamepad";
|
||||
import { GamepadInputStackProvider } from "@/providers/gamepad-input-stack";
|
||||
import { useCallback, useContext, useEffect, useRef } from "react";
|
||||
import type { GamepadButtonEvent } from "@/handlers/gamepad";
|
||||
import { GamepadInputStackProvider } from "@/providers/gamepad-input-stack";
|
||||
|
||||
export function useGamepadInputStack(zIndex?: number) {
|
||||
const context = useContext(GamepadInputStackProvider.Context);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useGamepadInputStack must be used within a GamepadInputStackProvider",
|
||||
const context = useContext(GamepadInputStackProvider.Context);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useGamepadInputStack must be used within a GamepadInputStackProvider",
|
||||
);
|
||||
}
|
||||
|
||||
const symRef = useRef<symbol>(null);
|
||||
useEffect(() => {
|
||||
symRef.current = context.add(zIndex);
|
||||
|
||||
return () => {
|
||||
const sym = symRef.current;
|
||||
if (!sym) {
|
||||
throw new Error("this should not be null");
|
||||
}
|
||||
context.del(sym);
|
||||
};
|
||||
}, [context, zIndex]);
|
||||
|
||||
const listen = useCallback(
|
||||
(button: number, callback: (e: GamepadButtonEvent) => void) => {
|
||||
const sym = symRef.current;
|
||||
if (!sym) {
|
||||
throw new Error("this should not be null");
|
||||
}
|
||||
return context.listen(sym, button, callback);
|
||||
},
|
||||
[context],
|
||||
);
|
||||
}
|
||||
|
||||
const symRef = useRef<symbol>(null);
|
||||
useEffect(() => {
|
||||
symRef.current = context.add(zIndex);
|
||||
|
||||
return () => {
|
||||
const sym = symRef.current;
|
||||
if (!sym) throw new Error("this should not be null");
|
||||
context.del(sym);
|
||||
return {
|
||||
context: context,
|
||||
listen,
|
||||
};
|
||||
}, []);
|
||||
|
||||
const listen = useCallback(
|
||||
(button: number, callback: (e: GamepadButtonEvent) => void) => {
|
||||
const sym = symRef.current;
|
||||
if (!sym) throw new Error("this should not be null");
|
||||
context.listen(sym, button, callback);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
context: context,
|
||||
listen,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export interface SystemTime {
|
||||
secs_since_epoch: number;
|
||||
nanos_since_epoch: number;
|
||||
secs_since_epoch: number;
|
||||
nanos_since_epoch: number;
|
||||
}
|
||||
|
||||
export interface PSFEntry {
|
||||
Integer?: number;
|
||||
Text?: string;
|
||||
Binary?: Uint8Array;
|
||||
Integer?: number;
|
||||
Text?: string;
|
||||
Binary?: Uint8Array;
|
||||
}
|
||||
|
||||
export interface PSF {
|
||||
last_write: SystemTime;
|
||||
entries: Record<string, PSFEntry>;
|
||||
last_write: SystemTime;
|
||||
entries: Record<string, PSFEntry>;
|
||||
}
|
||||
|
||||
export async function readPsf(path: string): Promise<PSF> {
|
||||
return await invoke("read_psf", {
|
||||
path,
|
||||
});
|
||||
return await invoke("read_psf", {
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
export async function extractZip(zipPath: string, extractPath: string) {
|
||||
return await invoke("extract_zip", {
|
||||
zipPath,
|
||||
extractPath,
|
||||
});
|
||||
return await invoke("extract_zip", {
|
||||
zipPath,
|
||||
extractPath,
|
||||
});
|
||||
}
|
||||
|
||||
export async function startGameProcess(
|
||||
exe: string,
|
||||
workingDir: string,
|
||||
gameBinary: string,
|
||||
exe: string,
|
||||
workingDir: string,
|
||||
gameBinary: string,
|
||||
) {
|
||||
return await invoke("start_emu_process_cmd", {
|
||||
exe,
|
||||
wd: workingDir,
|
||||
gameBinary,
|
||||
});
|
||||
return await invoke("start_emu_process_cmd", {
|
||||
exe,
|
||||
wd: workingDir,
|
||||
gameBinary,
|
||||
});
|
||||
}
|
||||
|
||||
40
src/main.tsx
40
src/main.tsx
@@ -3,29 +3,35 @@ import * as Jotai from "jotai";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import { LoadingOverlay } from "./components/loading-overlay";
|
||||
import { Toaster } from "./components/ui/sonner";
|
||||
import { TooltipProvider } from "./components/ui/tooltip";
|
||||
import { startGamepadHandler } from "./handlers/gamepad";
|
||||
import { GamepadInputStackProvider } from "./providers/gamepad-input-stack";
|
||||
import { defaultStore } from "./store";
|
||||
import { Toaster } from "./components/ui/sonner";
|
||||
import { LoadingOverlay } from "./components/loading-overlay";
|
||||
import { TooltipProvider } from "./components/ui/tooltip";
|
||||
|
||||
startGamepadHandler();
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Jotai.Provider store={defaultStore}>
|
||||
<GamepadInputStackProvider>
|
||||
<TooltipProvider>
|
||||
<Toaster richColors />
|
||||
<LoadingOverlay />
|
||||
<App />
|
||||
</TooltipProvider>
|
||||
</GamepadInputStackProvider>
|
||||
</Jotai.Provider>
|
||||
</QueryClientProvider>
|
||||
</React.StrictMode>,
|
||||
const root = document.getElementById("root");
|
||||
|
||||
if (!root) {
|
||||
throw new Error("Root element not found");
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(root).render(
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Jotai.Provider store={defaultStore}>
|
||||
<GamepadInputStackProvider>
|
||||
<TooltipProvider>
|
||||
<Toaster richColors />
|
||||
<LoadingOverlay />
|
||||
<App />
|
||||
</TooltipProvider>
|
||||
</GamepadInputStackProvider>
|
||||
</Jotai.Provider>
|
||||
</QueryClientProvider>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
||||
@@ -1,94 +1,118 @@
|
||||
import {
|
||||
addGamepadButtonListener,
|
||||
removeGamepadButtonListener,
|
||||
type GamepadButtonEvent,
|
||||
} from "@/handlers/gamepad";
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
import {
|
||||
addGamepadButtonListener,
|
||||
type GamepadButtonEvent,
|
||||
removeGamepadButtonListener,
|
||||
} from "@/handlers/gamepad";
|
||||
|
||||
type Callback = (e: GamepadButtonEvent) => void;
|
||||
|
||||
export interface Target {
|
||||
zIndex: number;
|
||||
symbol: symbol;
|
||||
zIndex: number;
|
||||
symbol: symbol;
|
||||
|
||||
listener: Map<number, Callback>;
|
||||
listener: Map<number, Callback[]>;
|
||||
}
|
||||
|
||||
type Unlisten = () => void;
|
||||
|
||||
interface IGamepadInputStack {
|
||||
isOnTop(symbol: symbol): boolean;
|
||||
getNextZIndex(): number;
|
||||
isOnTop(symbol: symbol): boolean;
|
||||
getNextZIndex(): number;
|
||||
|
||||
add(zIndex?: number): symbol;
|
||||
del(symbol: symbol): void;
|
||||
add(zIndex?: number): symbol;
|
||||
del(symbol: symbol): void;
|
||||
|
||||
listen(symbol: symbol, button: number, callback: Callback): void;
|
||||
listen(symbol: symbol, button: number, callback: Callback): Unlisten;
|
||||
}
|
||||
|
||||
const context = createContext<IGamepadInputStack | null>(null);
|
||||
|
||||
function compare(a: Target, b: Target): number {
|
||||
return b.zIndex - a.zIndex;
|
||||
return b.zIndex - a.zIndex;
|
||||
}
|
||||
|
||||
export function GamepadInputStackProvider({ children }: PropsWithChildren) {
|
||||
const targets = useRef<Target[]>([]);
|
||||
const targets = useRef<Target[]>([]);
|
||||
|
||||
const getNextZIndex = useCallback(() => {
|
||||
return targets.current[0]?.zIndex || 1;
|
||||
}, []);
|
||||
const getNextZIndex = useCallback(() => {
|
||||
return (targets.current[0]?.zIndex || 0) + 1;
|
||||
}, []);
|
||||
|
||||
const isOnTop = useCallback((symbol: symbol) => {
|
||||
return targets.current[0]?.symbol == symbol;
|
||||
}, []);
|
||||
const isOnTop = useCallback((symbol: symbol) => {
|
||||
return targets.current[0]?.symbol === symbol;
|
||||
}, []);
|
||||
|
||||
const add = useCallback((zIndex?: number): symbol => {
|
||||
const symbol = Symbol();
|
||||
zIndex = zIndex || getNextZIndex();
|
||||
const newTarget = {
|
||||
zIndex,
|
||||
symbol,
|
||||
listener: new Map(),
|
||||
};
|
||||
targets.current.push(newTarget);
|
||||
targets.current.sort(compare);
|
||||
return symbol;
|
||||
}, []);
|
||||
const add = useCallback(
|
||||
(_zIndex?: number): symbol => {
|
||||
const symbol = Symbol();
|
||||
const zIndex = _zIndex || getNextZIndex();
|
||||
const newTarget = {
|
||||
zIndex,
|
||||
symbol,
|
||||
listener: new Map(),
|
||||
};
|
||||
targets.current.push(newTarget);
|
||||
targets.current.sort(compare);
|
||||
return symbol;
|
||||
},
|
||||
[getNextZIndex],
|
||||
);
|
||||
|
||||
const del = useCallback((symbol: symbol) => {
|
||||
targets.current = targets.current.filter((e) => e.symbol != symbol);
|
||||
}, []);
|
||||
const del = useCallback((symbol: symbol) => {
|
||||
targets.current = targets.current.filter((e) => e.symbol !== symbol);
|
||||
}, []);
|
||||
|
||||
const listen = useCallback(
|
||||
(symbol: symbol, button: number, callback: Callback) => {
|
||||
const target = targets.current.find((e) => e.symbol == symbol);
|
||||
if (!target) return;
|
||||
const listen = useCallback(
|
||||
(symbol: symbol, button: number, callback: Callback) => {
|
||||
const target = targets.current.find((e) => e.symbol === symbol);
|
||||
if (!target) {
|
||||
throw new Error("Target not found");
|
||||
}
|
||||
|
||||
target.listener.set(button, callback);
|
||||
},
|
||||
[],
|
||||
);
|
||||
let callbackList = target.listener.get(button);
|
||||
if (!callbackList) {
|
||||
callbackList = [];
|
||||
target.listener.set(button, callbackList);
|
||||
}
|
||||
callbackList.push(callback);
|
||||
return () => {
|
||||
const idx = callbackList.indexOf(callback);
|
||||
if (idx !== -1) {
|
||||
callbackList.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const onButtonEvent = useCallback((e: GamepadButtonEvent) => {
|
||||
targets.current[0]?.listener?.get(e.button)?.(e);
|
||||
}, []);
|
||||
const onButtonEvent = useCallback((e: GamepadButtonEvent) => {
|
||||
const callbackList = targets.current[0]?.listener?.get(e.button);
|
||||
if (!callbackList) {
|
||||
return;
|
||||
}
|
||||
for (const c of callbackList) {
|
||||
c(e);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
addGamepadButtonListener(onButtonEvent);
|
||||
useEffect(() => {
|
||||
addGamepadButtonListener(onButtonEvent);
|
||||
|
||||
return () => removeGamepadButtonListener(onButtonEvent);
|
||||
}, [onButtonEvent]);
|
||||
return () => removeGamepadButtonListener(onButtonEvent);
|
||||
}, [onButtonEvent]);
|
||||
|
||||
return (
|
||||
<context.Provider value={{ isOnTop, getNextZIndex, add, del, listen }}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
);
|
||||
return (
|
||||
<context.Provider value={{ isOnTop, getNextZIndex, add, del, listen }}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
GamepadInputStackProvider.Context = context;
|
||||
|
||||
@@ -5,12 +5,12 @@ export const oficialRepo = "shadps4-emu/shadPS4";
|
||||
export const atomModalConfigIsOpen = atom<boolean>(false);
|
||||
|
||||
export const atomDownloadingOverlay = atom<
|
||||
| ({
|
||||
message?: string;
|
||||
} & (
|
||||
| { percent: number }
|
||||
| { progress: number; total?: number; format?: "data" }
|
||||
| { progress: "infinity" }
|
||||
))
|
||||
| null
|
||||
| ({
|
||||
message?: string;
|
||||
} & (
|
||||
| { percent: number }
|
||||
| { progress: number; total?: number; format?: "data" }
|
||||
| { progress: "infinity" }
|
||||
))
|
||||
| null
|
||||
>(null);
|
||||
|
||||
@@ -1,128 +1,129 @@
|
||||
import { type PSF, readPsf } from "@/lib/native-calls";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { BaseDirectory, basename, join } from "@tauri-apps/api/path";
|
||||
import { exists, readDir, readTextFile, watch } from "@tauri-apps/plugin-fs";
|
||||
import { atom } from "jotai";
|
||||
import { type PSF, readPsf } from "@/lib/native-calls";
|
||||
import { defaultStore, type JotaiStore } from ".";
|
||||
import { atomGamesPath } from "./paths";
|
||||
|
||||
export interface GameEntry {
|
||||
path: string;
|
||||
id: string;
|
||||
title: string;
|
||||
cover: string | null;
|
||||
version: string;
|
||||
fw_version: string;
|
||||
sfo?: PSF;
|
||||
path: string;
|
||||
id: string;
|
||||
title: string;
|
||||
cover: string | null;
|
||||
version: string;
|
||||
fw_version: string;
|
||||
sfo?: PSF;
|
||||
}
|
||||
|
||||
const atomGameLibraryRefresh = atom(0);
|
||||
export const atomGameLibrary = atom(async (get) => {
|
||||
get(atomGameLibraryRefresh);
|
||||
if (import.meta.env.VITE_USE_MOCK) {
|
||||
await new Promise((resolve) => {
|
||||
// simulate some loading
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
const data = await readTextFile("mock/games.json", {
|
||||
baseDir: BaseDirectory.Resource,
|
||||
});
|
||||
get(atomGameLibraryRefresh);
|
||||
if (import.meta.env.VITE_USE_MOCK) {
|
||||
await new Promise((resolve) => {
|
||||
// simulate some loading
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
const data = await readTextFile("mock/games.json", {
|
||||
baseDir: BaseDirectory.Resource,
|
||||
});
|
||||
|
||||
return JSON.parse(data) as GameEntry[];
|
||||
}
|
||||
|
||||
const knownPaths: string[] = [];
|
||||
|
||||
async function isGame(path: string) {
|
||||
const paramSfoPath = await join(path, "sce_sys", "param.sfo");
|
||||
if (await exists(paramSfoPath)) {
|
||||
return true;
|
||||
return JSON.parse(data) as GameEntry[];
|
||||
}
|
||||
const eBootPath = await join(path, "eboot.bin");
|
||||
if (await exists(eBootPath)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function discoverGame(path: string) {
|
||||
try {
|
||||
if (await isGame(path)) {
|
||||
knownPaths.push(path);
|
||||
return;
|
||||
}
|
||||
void (await Promise.all(
|
||||
(await readDir(path)).map(async (child) => {
|
||||
if (child.isDirectory) {
|
||||
await discoverGame(await join(path, child.name));
|
||||
}
|
||||
}),
|
||||
));
|
||||
} catch (error) {
|
||||
console.error(`Error discovering game: ${path}. ${error}`);
|
||||
}
|
||||
}
|
||||
const knownPaths: string[] = [];
|
||||
|
||||
const v = get(atomGamesPath);
|
||||
if (!v || !(await exists(v))) {
|
||||
return [];
|
||||
}
|
||||
void (await discoverGame(v));
|
||||
|
||||
return await Promise.all(
|
||||
knownPaths.map(async (path): Promise<GameEntry> => {
|
||||
const b = await basename(path);
|
||||
|
||||
const paramSfo = await join(path, "sce_sys", "param.sfo");
|
||||
const sfo = await readPsf(paramSfo);
|
||||
const e = sfo.entries;
|
||||
|
||||
let cover: string | null = await join(path, "sce_sys", "icon0.png");
|
||||
if (!(await exists(cover))) {
|
||||
cover = null;
|
||||
} else {
|
||||
cover = convertFileSrc(cover);
|
||||
}
|
||||
|
||||
let fw_version = e.SYSTEM_VER?.Integer?.toString(16)
|
||||
.padStart(8, "0")
|
||||
.slice(0, 4);
|
||||
if (fw_version) {
|
||||
fw_version =
|
||||
fw_version.slice(0, 2).trimStart() + "." + fw_version.slice(2);
|
||||
if (fw_version.startsWith("0")) {
|
||||
fw_version = fw_version.slice(1);
|
||||
async function isGame(path: string) {
|
||||
const paramSfoPath = await join(path, "sce_sys", "param.sfo");
|
||||
if (await exists(paramSfoPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const eBootPath = await join(path, "eboot.bin");
|
||||
if (await exists(eBootPath)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
path,
|
||||
id: e.TITLE_ID?.Text || b,
|
||||
title: e.TITLE?.Text || "Unknown",
|
||||
cover,
|
||||
version: e.APP_VER?.Text || "UNK",
|
||||
fw_version: fw_version || "UNK",
|
||||
sfo,
|
||||
};
|
||||
}),
|
||||
);
|
||||
async function discoverGame(path: string) {
|
||||
try {
|
||||
if (await isGame(path)) {
|
||||
knownPaths.push(path);
|
||||
return;
|
||||
}
|
||||
void (await Promise.all(
|
||||
(
|
||||
await readDir(path)
|
||||
).map(async (child) => {
|
||||
if (child.isDirectory) {
|
||||
await discoverGame(await join(path, child.name));
|
||||
}
|
||||
}),
|
||||
));
|
||||
} catch (error) {
|
||||
console.error(`Error discovering game: ${path}. ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
const v = get(atomGamesPath);
|
||||
if (!v || !(await exists(v))) {
|
||||
return [];
|
||||
}
|
||||
void (await discoverGame(v));
|
||||
|
||||
return await Promise.all(
|
||||
knownPaths.map(async (path): Promise<GameEntry> => {
|
||||
const b = await basename(path);
|
||||
|
||||
const paramSfo = await join(path, "sce_sys", "param.sfo");
|
||||
const sfo = await readPsf(paramSfo);
|
||||
const e = sfo.entries;
|
||||
|
||||
let cover: string | null = await join(path, "sce_sys", "icon0.png");
|
||||
if (!(await exists(cover))) {
|
||||
cover = null;
|
||||
} else {
|
||||
cover = convertFileSrc(cover);
|
||||
}
|
||||
|
||||
let fw_version = e.SYSTEM_VER?.Integer?.toString(16)
|
||||
.padStart(8, "0")
|
||||
.slice(0, 4);
|
||||
if (fw_version) {
|
||||
fw_version = `${fw_version.slice(0, 2).trimStart()}.${fw_version.slice(2)}`;
|
||||
if (fw_version.startsWith("0")) {
|
||||
fw_version = fw_version.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
path,
|
||||
id: e.TITLE_ID?.Text || b,
|
||||
title: e.TITLE?.Text || "Unknown",
|
||||
cover,
|
||||
version: e.APP_VER?.Text || "UNK",
|
||||
fw_version: fw_version || "UNK",
|
||||
sfo,
|
||||
};
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
export function refreshGameLibrary(s: JotaiStore) {
|
||||
s.set(atomGameLibraryRefresh, (prev) => prev + 1);
|
||||
s.set(atomGameLibraryRefresh, (prev) => prev + 1);
|
||||
}
|
||||
|
||||
(() => {
|
||||
let unsub: Promise<() => void> | undefined;
|
||||
defaultStore.sub(atomGamesPath, () => {
|
||||
unsub?.then((e) => e());
|
||||
unsub = undefined;
|
||||
let unsub: Promise<() => void> | undefined;
|
||||
defaultStore.sub(atomGamesPath, () => {
|
||||
unsub?.then((e) => e());
|
||||
unsub = undefined;
|
||||
|
||||
const path = defaultStore.get(atomGamesPath);
|
||||
if (path) {
|
||||
unsub = watch(path, () => {
|
||||
refreshGameLibrary(defaultStore);
|
||||
});
|
||||
}
|
||||
});
|
||||
})()
|
||||
const path = defaultStore.get(atomGamesPath);
|
||||
if (path) {
|
||||
unsub = watch(path, () => {
|
||||
refreshGameLibrary(defaultStore);
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { atomWithTauriStore } from "@/utils/jotai/tauri-store";
|
||||
import { appDataDir, join } from "@tauri-apps/api/path";
|
||||
import { atomWithTauriStore } from "@/utils/jotai/tauri-store";
|
||||
|
||||
export const atomGamesPath = atomWithTauriStore("config.json", "games_path", {
|
||||
onMount: async () => join(await appDataDir(), "games"),
|
||||
onMount: async () => join(await appDataDir(), "games"),
|
||||
});
|
||||
|
||||
export const atomEmuInstallsPath = atomWithTauriStore(
|
||||
"config.json",
|
||||
"version_installs",
|
||||
{
|
||||
onMount: async () => join(await appDataDir(), "versions"),
|
||||
},
|
||||
"config.json",
|
||||
"version_installs",
|
||||
{
|
||||
onMount: async () => join(await appDataDir(), "versions"),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,36 +1,42 @@
|
||||
import { readConfig } from "@/handlers/version-manager";
|
||||
import { atomWithTauriStore } from "@/utils/jotai/tauri-store";
|
||||
import { join } from "@tauri-apps/api/path";
|
||||
import { exists, readDir, watch } from "@tauri-apps/plugin-fs";
|
||||
import { platform } from "@tauri-apps/plugin-os";
|
||||
import { atom } from "jotai";
|
||||
import { atomWithQuery } from "jotai-tanstack-query";
|
||||
import { unwrap } from "jotai/utils";
|
||||
import { atomWithQuery } from "jotai-tanstack-query";
|
||||
import { Octokit } from "octokit";
|
||||
import { readConfig } from "@/handlers/version-manager";
|
||||
import { atomWithTauriStore } from "@/utils/jotai/tauri-store";
|
||||
import { defaultStore, type JotaiStore } from ".";
|
||||
import { oficialRepo } from "./common";
|
||||
import { atomEmuInstallsPath } from "./paths";
|
||||
|
||||
const currentPlatform = (() => {
|
||||
const p = platform();
|
||||
if (p === "windows") return "win";
|
||||
if (p === "macos") return "macos";
|
||||
if (p === "linux") return "linux";
|
||||
return p;
|
||||
const p = platform();
|
||||
if (p === "windows") {
|
||||
return "win";
|
||||
}
|
||||
if (p === "macos") {
|
||||
return "macos";
|
||||
}
|
||||
if (p === "linux") {
|
||||
return "linux";
|
||||
}
|
||||
return p;
|
||||
})();
|
||||
|
||||
export interface EmulatorVersion {
|
||||
path: string; // local path directory
|
||||
repo: string; // repo source
|
||||
date: Date; // release date
|
||||
version: string; // release version
|
||||
name: string; // release name
|
||||
prerelease: boolean;
|
||||
path: string; // local path directory
|
||||
repo: string; // repo source
|
||||
date: Date; // release date
|
||||
version: string; // release version
|
||||
name: string; // release name
|
||||
prerelease: boolean;
|
||||
}
|
||||
|
||||
export type RemoteEmulatorVersion = Omit<EmulatorVersion, "path"> & {
|
||||
url: string; // download url
|
||||
notSupported?: boolean; // no available for the current platform
|
||||
url: string; // download url
|
||||
notSupported?: boolean; // no available for the current platform
|
||||
};
|
||||
|
||||
const octokit = new Octokit();
|
||||
@@ -38,141 +44,160 @@ const octokit = new Octokit();
|
||||
export const atomModalVersionManagerIsOpen = atom<boolean>(false);
|
||||
|
||||
const atomSelectedVersionRaw = atomWithTauriStore<string>(
|
||||
"config.json",
|
||||
"selected",
|
||||
{
|
||||
initialValue: "",
|
||||
},
|
||||
"config.json",
|
||||
"selected",
|
||||
{
|
||||
initialValue: "",
|
||||
},
|
||||
);
|
||||
|
||||
export const atomSelectedVersion = atom<
|
||||
EmulatorVersion | null,
|
||||
[EmulatorVersion | string],
|
||||
void
|
||||
EmulatorVersion | null,
|
||||
[EmulatorVersion | string],
|
||||
void
|
||||
>(
|
||||
(get) => {
|
||||
const raw = get(atomSelectedVersionRaw);
|
||||
const installedVersion = get(unwrap(atomInstalledVersions));
|
||||
if (!raw || !installedVersion) return null;
|
||||
(get) => {
|
||||
const raw = get(atomSelectedVersionRaw);
|
||||
const installedVersion = get(unwrap(atomInstalledVersions));
|
||||
if (!raw || !installedVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return installedVersion.find((e) => e.path === raw) ?? null;
|
||||
},
|
||||
(_get, set, value: EmulatorVersion | string) => {
|
||||
set(atomSelectedVersionRaw, typeof value === "string" ? value : value.path);
|
||||
},
|
||||
return installedVersion.find((e) => e.path === raw) ?? null;
|
||||
},
|
||||
(_get, set, value: EmulatorVersion | string) => {
|
||||
set(
|
||||
atomSelectedVersionRaw,
|
||||
typeof value === "string" ? value : value.path,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const atomRemoteList = atomWithTauriStore("config.json", "remote_list", {
|
||||
initialValue: [oficialRepo],
|
||||
mergeInitial: false,
|
||||
initialValue: [oficialRepo],
|
||||
mergeInitial: false,
|
||||
});
|
||||
|
||||
export const atomAvailableVersions = atomWithQuery((get) => ({
|
||||
queryKey: ["github", "available", get(atomRemoteList)] as [
|
||||
string,
|
||||
string,
|
||||
string[],
|
||||
],
|
||||
queryFn: async ({
|
||||
queryKey: [, , list],
|
||||
}: {
|
||||
queryKey: [string, string, string[]];
|
||||
}) => {
|
||||
return (
|
||||
await Promise.all(
|
||||
list.map(async (repoSource) => {
|
||||
const [owner, repo] = repoSource.split("/");
|
||||
if (!owner || !repo) return [];
|
||||
const releaseList = await octokit.rest.repos.listReleases({
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
if (releaseList.status !== 200)
|
||||
throw new Error("Failed to fetch releases " + repoSource);
|
||||
return releaseList.data
|
||||
.map((release) => {
|
||||
const asset = release.assets.find(
|
||||
(e) =>
|
||||
e.name.endsWith(".zip") &&
|
||||
(e.name.includes("sdl") || !e.name.includes("qt")) &&
|
||||
e.name.includes(currentPlatform),
|
||||
);
|
||||
queryKey: ["github", "available", get(atomRemoteList)] as [
|
||||
string,
|
||||
string,
|
||||
string[],
|
||||
],
|
||||
queryFn: async ({
|
||||
queryKey: [, , list],
|
||||
}: {
|
||||
queryKey: [string, string, string[]];
|
||||
}) => {
|
||||
return (
|
||||
await Promise.all(
|
||||
list.map(async (repoSource) => {
|
||||
const [owner, repo] = repoSource.split("/");
|
||||
if (!owner || !repo) {
|
||||
return [];
|
||||
}
|
||||
const releaseList = await octokit.rest.repos.listReleases({
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
if (releaseList.status !== 200) {
|
||||
throw new Error(
|
||||
`Failed to fetch releases ${repoSource}`,
|
||||
);
|
||||
}
|
||||
return releaseList.data
|
||||
.map((release) => {
|
||||
const asset = release.assets.find(
|
||||
(e) =>
|
||||
e.name.endsWith(".zip") &&
|
||||
(e.name.includes("sdl") ||
|
||||
!e.name.includes("qt")) &&
|
||||
e.name.includes(currentPlatform),
|
||||
);
|
||||
|
||||
let name = "";
|
||||
if (release.prerelease) {
|
||||
name = "Pre-release";
|
||||
} else {
|
||||
name = release.name || "Unknown";
|
||||
name = name.replaceAll(
|
||||
/-|(codename)|(shadps4)|(v\.?\d+\.\d+\.\d+)/g,
|
||||
"",
|
||||
);
|
||||
name = name.replaceAll(" ", "");
|
||||
name = name.trim();
|
||||
}
|
||||
let name = "";
|
||||
if (release.prerelease) {
|
||||
name = "Pre-release";
|
||||
} else {
|
||||
name = release.name || "Unknown";
|
||||
name = name.replaceAll(
|
||||
/-|(codename)|(shadps4)|(v\.?\d+\.\d+\.\d+)/g,
|
||||
"",
|
||||
);
|
||||
name = name.replaceAll(" ", "");
|
||||
name = name.trim();
|
||||
}
|
||||
|
||||
let version = "";
|
||||
if (release.prerelease) {
|
||||
version = release.tag_name.split("-").pop() || "Unknown";
|
||||
} else {
|
||||
version = release.tag_name;
|
||||
}
|
||||
let version = "";
|
||||
if (release.prerelease) {
|
||||
version =
|
||||
release.tag_name.split("-").pop() ||
|
||||
"Unknown";
|
||||
} else {
|
||||
version = release.tag_name;
|
||||
}
|
||||
|
||||
return {
|
||||
repo: repoSource,
|
||||
date: new Date(asset?.updated_at || release.created_at),
|
||||
version,
|
||||
name,
|
||||
prerelease: release.prerelease,
|
||||
url: asset?.browser_download_url || "",
|
||||
notSupported: asset == null,
|
||||
} satisfies RemoteEmulatorVersion;
|
||||
})
|
||||
.filter((e) => e != null);
|
||||
}),
|
||||
)
|
||||
).flat();
|
||||
},
|
||||
return {
|
||||
repo: repoSource,
|
||||
date: new Date(
|
||||
asset?.updated_at || release.created_at,
|
||||
),
|
||||
version,
|
||||
name,
|
||||
prerelease: release.prerelease,
|
||||
url: asset?.browser_download_url || "",
|
||||
notSupported: asset == null,
|
||||
} satisfies RemoteEmulatorVersion;
|
||||
})
|
||||
.filter((e) => e != null);
|
||||
}),
|
||||
)
|
||||
).flat();
|
||||
},
|
||||
}));
|
||||
|
||||
export const atomInstalledVersionsRefresh = atom(0);
|
||||
|
||||
export function refreshInstalledVersion(s: JotaiStore) {
|
||||
s.set(atomInstalledVersionsRefresh, (prev) => prev + 1);
|
||||
s.set(atomInstalledVersionsRefresh, (prev) => prev + 1);
|
||||
}
|
||||
|
||||
export const atomInstalledVersions = atom(async (get) => {
|
||||
get(atomInstalledVersionsRefresh);
|
||||
const installationPath = get(atomEmuInstallsPath);
|
||||
if (!installationPath) return [];
|
||||
get(atomInstalledVersionsRefresh);
|
||||
const installationPath = get(atomEmuInstallsPath);
|
||||
if (!installationPath) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!(await exists(installationPath))) return [];
|
||||
if (!(await exists(installationPath))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const dirList = (await readDir(installationPath)).filter(
|
||||
(e) => e.isDirectory,
|
||||
);
|
||||
const dirList = (await readDir(installationPath)).filter(
|
||||
(e) => e.isDirectory,
|
||||
);
|
||||
|
||||
return (
|
||||
await Promise.all(
|
||||
dirList.map(async (dir) => {
|
||||
const path = await join(installationPath, dir.name);
|
||||
return await readConfig(path);
|
||||
}),
|
||||
)
|
||||
).filter((e) => e != null);
|
||||
return (
|
||||
await Promise.all(
|
||||
dirList.map(async (dir) => {
|
||||
const path = await join(installationPath, dir.name);
|
||||
return await readConfig(path);
|
||||
}),
|
||||
)
|
||||
).filter((e) => e != null);
|
||||
});
|
||||
|
||||
(() => {
|
||||
let unsub: Promise<() => void> | undefined;
|
||||
defaultStore.sub(atomEmuInstallsPath, () => {
|
||||
unsub?.then((e) => e());
|
||||
unsub = undefined;
|
||||
let unsub: Promise<() => void> | undefined;
|
||||
defaultStore.sub(atomEmuInstallsPath, () => {
|
||||
unsub?.then((e) => e());
|
||||
unsub = undefined;
|
||||
|
||||
const path = defaultStore.get(atomEmuInstallsPath);
|
||||
if (path) {
|
||||
unsub = watch(path, () => {
|
||||
refreshInstalledVersion(defaultStore);
|
||||
});
|
||||
}
|
||||
});
|
||||
const path = defaultStore.get(atomEmuInstallsPath);
|
||||
if (path) {
|
||||
unsub = watch(path, () => {
|
||||
refreshInstalledVersion(defaultStore);
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
24
src/types.d.ts
vendored
24
src/types.d.ts
vendored
@@ -1,18 +1,18 @@
|
||||
type SelectableAnchor =
|
||||
| "TOP_LEFT"
|
||||
| "TOP_CENTER"
|
||||
| "TOP_RIGHT"
|
||||
| "CENTER_LEFT"
|
||||
| "CENTER"
|
||||
| "CENTER_RIGHT"
|
||||
| "BOTTOM_LEFT"
|
||||
| "BOTTOM_CENTER"
|
||||
| "BOTTOM_RIGHT";
|
||||
| "TOP_LEFT"
|
||||
| "TOP_CENTER"
|
||||
| "TOP_RIGHT"
|
||||
| "CENTER_LEFT"
|
||||
| "CENTER"
|
||||
| "CENTER_RIGHT"
|
||||
| "BOTTOM_LEFT"
|
||||
| "BOTTOM_CENTER"
|
||||
| "BOTTOM_RIGHT";
|
||||
|
||||
declare module "react" {
|
||||
export interface HTMLAttributes {
|
||||
["data-gamepad-selectable"]?: boolean | SelectableAnchor;
|
||||
}
|
||||
export interface HTMLAttributes {
|
||||
"data-gamepad-selectable"?: boolean | SelectableAnchor;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
export function stringifyError(e: unknown): string {
|
||||
if (typeof e === "string") {
|
||||
return e;
|
||||
}
|
||||
if (e !== null && typeof e === "object" && "message" in e) {
|
||||
const msg = e.message;
|
||||
if (typeof msg === "string") return msg;
|
||||
return String(msg);
|
||||
}
|
||||
if (typeof e === "string") {
|
||||
return e;
|
||||
}
|
||||
if (e !== null && typeof e === "object" && "message" in e) {
|
||||
const msg = e.message;
|
||||
if (typeof msg === "string") {
|
||||
return msg;
|
||||
}
|
||||
return String(msg);
|
||||
}
|
||||
|
||||
return JSON.stringify(e);
|
||||
return JSON.stringify(e);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const createAbort = () => {
|
||||
const controller = new AbortController();
|
||||
return {
|
||||
signal: controller.signal,
|
||||
abort: () => controller.abort(),
|
||||
};
|
||||
const controller = new AbortController();
|
||||
return {
|
||||
signal: controller.signal,
|
||||
abort: () => controller.abort(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { atomWithReducer } from "jotai/utils";
|
||||
import { dequal } from "dequal";
|
||||
import { atomWithReducer } from "jotai/utils";
|
||||
|
||||
export function atomDeepEqual<Value>(initialValue: Value) {
|
||||
return atomWithReducer(initialValue, (prev: Value, next: Value) => {
|
||||
if (dequal(prev, next)) {
|
||||
return prev;
|
||||
}
|
||||
return atomWithReducer(initialValue, (prev: Value, next: Value) => {
|
||||
if (dequal(prev, next)) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return next;
|
||||
});
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,78 +3,79 @@ import { atom, type SetStateAction } from "jotai";
|
||||
|
||||
const __store = new Map<string, Promise<Store>>();
|
||||
|
||||
async function getStore(path: string): Promise<Store> {
|
||||
let s = __store.get(path);
|
||||
if (s) {
|
||||
function getStore(path: string): Promise<Store> {
|
||||
let s = __store.get(path);
|
||||
if (s) {
|
||||
return s;
|
||||
}
|
||||
s = Store.load(path, { autoSave: true });
|
||||
__store.set(path, s);
|
||||
return s;
|
||||
}
|
||||
s = Store.load(path, { autoSave: true });
|
||||
__store.set(path, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
export function atomWithTauriStore<T>(
|
||||
path: string,
|
||||
key: string,
|
||||
{
|
||||
initialValue,
|
||||
onMount = initialValue,
|
||||
mergeInitial = true,
|
||||
}:
|
||||
| {
|
||||
initialValue: T;
|
||||
onMount?: T | (() => Promise<T> | T);
|
||||
mergeInitial?: boolean;
|
||||
}
|
||||
| {
|
||||
initialValue?: T;
|
||||
onMount: T | (() => Promise<T> | T);
|
||||
mergeInitial?: boolean;
|
||||
},
|
||||
path: string,
|
||||
key: string,
|
||||
{
|
||||
initialValue,
|
||||
onMount = initialValue,
|
||||
mergeInitial = true,
|
||||
}:
|
||||
| {
|
||||
initialValue: T;
|
||||
onMount?: T | (() => Promise<T> | T);
|
||||
mergeInitial?: boolean;
|
||||
}
|
||||
| {
|
||||
initialValue?: T;
|
||||
onMount: T | (() => Promise<T> | T);
|
||||
mergeInitial?: boolean;
|
||||
},
|
||||
) {
|
||||
const getInitialValue = async () => {
|
||||
const initialProm =
|
||||
typeof onMount === "function"
|
||||
? (onMount as () => Promise<T> | T)()
|
||||
: onMount;
|
||||
if (initialProm == null) {
|
||||
throw new Error("Initial value or onMount must be defined");
|
||||
}
|
||||
const initial: T = await Promise.resolve(initialProm);
|
||||
try {
|
||||
const store = await getStore(path);
|
||||
const value = await store.get<T>(key);
|
||||
if (mergeInitial) {
|
||||
if (Array.isArray(initial)) {
|
||||
return [...initial, ...((value as T[]) || [])] as T;
|
||||
} else if (typeof initial === "object") {
|
||||
return {
|
||||
...initial,
|
||||
...(value || {}),
|
||||
};
|
||||
const getInitialValue = async () => {
|
||||
const initialProm =
|
||||
typeof onMount === "function"
|
||||
? (onMount as () => Promise<T> | T)()
|
||||
: onMount;
|
||||
if (initialProm == null) {
|
||||
throw new Error("Initial value or onMount must be defined");
|
||||
}
|
||||
}
|
||||
return value || initial;
|
||||
} catch {
|
||||
return initial;
|
||||
}
|
||||
};
|
||||
const initial: T = await Promise.resolve(initialProm);
|
||||
try {
|
||||
const store = await getStore(path);
|
||||
const value = await store.get<T>(key);
|
||||
if (mergeInitial) {
|
||||
if (Array.isArray(initial)) {
|
||||
return [...initial, ...((value as T[]) || [])] as T;
|
||||
}
|
||||
if (typeof initial === "object") {
|
||||
return {
|
||||
...initial,
|
||||
...(value || {}),
|
||||
};
|
||||
}
|
||||
}
|
||||
return value || initial;
|
||||
} catch {
|
||||
return initial;
|
||||
}
|
||||
};
|
||||
|
||||
const baseAtom = atom<T | null>(initialValue ?? null);
|
||||
baseAtom.onMount = (setAtom) => {
|
||||
void Promise.resolve(getInitialValue()).then(setAtom);
|
||||
};
|
||||
const baseAtom = atom<T | null>(initialValue ?? null);
|
||||
baseAtom.onMount = (setAtom) => {
|
||||
void Promise.resolve(getInitialValue()).then(setAtom);
|
||||
};
|
||||
|
||||
return atom<T | null, [T], void>(
|
||||
(get) => get(baseAtom),
|
||||
(get, set, update: SetStateAction<T | null>) => {
|
||||
const newValue =
|
||||
typeof update === "function"
|
||||
? (update as (prev: T | null) => T)(get(baseAtom))
|
||||
: update;
|
||||
return atom<T | null, [T], void>(
|
||||
(get) => get(baseAtom),
|
||||
(get, set, update: SetStateAction<T | null>) => {
|
||||
const newValue =
|
||||
typeof update === "function"
|
||||
? (update as (prev: T | null) => T)(get(baseAtom))
|
||||
: update;
|
||||
|
||||
set(baseAtom, newValue);
|
||||
void getStore(path).then((store) => void store.set(key, newValue));
|
||||
},
|
||||
);
|
||||
set(baseAtom, newValue);
|
||||
void getStore(path).then((store) => void store.set(key, newValue));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
4
src/vite-env.d.ts
vendored
4
src/vite-env.d.ts
vendored
@@ -1,9 +1,9 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_USE_MOCK: boolean;
|
||||
readonly VITE_USE_MOCK: boolean;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
112
tsconfig.json
112
tsconfig.json
@@ -1,59 +1,59 @@
|
||||
{
|
||||
"include": ["eslint.config.mjs", "prettier.config.mjs", "src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"include": ["eslint.config.mjs", "prettier.config.mjs", "src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
|
||||
/* LANGUAGE COMPILATION OPTIONS */
|
||||
"target": "ES2022",
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2021"],
|
||||
"module": "ESNext",
|
||||
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
|
||||
/* EMIT RULES */
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true,
|
||||
"sourceMap": true,
|
||||
"removeComments": true,
|
||||
|
||||
/* TYPE CHECKING RULES */
|
||||
"strict": true,
|
||||
// "noImplicitAny": true, // Included in "Strict"
|
||||
// "noImplicitThis": true, // Included in "Strict"
|
||||
// "strictBindCallApply": true, // Included in "Strict"
|
||||
// "strictFunctionTypes": true, // Included in "Strict"
|
||||
// "strictNullChecks": true, // Included in "Strict"
|
||||
// "strictPropertyInitialization": true, // Included in "Strict"
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"useUnknownInCatchVariables": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
/* OTHER OPTIONS */
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
// "emitDecoratorMetadata": true,
|
||||
// "experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"useDefineForClassFields": true
|
||||
},
|
||||
|
||||
/* LANGUAGE COMPILATION OPTIONS */
|
||||
"target": "ES2022",
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2021"],
|
||||
"module": "ESNext",
|
||||
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
|
||||
/* EMIT RULES */
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true,
|
||||
"sourceMap": true,
|
||||
"removeComments": true,
|
||||
|
||||
/* TYPE CHECKING RULES */
|
||||
"strict": true,
|
||||
// "noImplicitAny": true, // Included in "Strict"
|
||||
// "noImplicitThis": true, // Included in "Strict"
|
||||
// "strictBindCallApply": true, // Included in "Strict"
|
||||
// "strictFunctionTypes": true, // Included in "Strict"
|
||||
// "strictNullChecks": true, // Included in "Strict"
|
||||
// "strictPropertyInitialization": true, // Included in "Strict"
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"useUnknownInCatchVariables": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
/* OTHER OPTIONS */
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
// "emitDecoratorMetadata": true,
|
||||
// "experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"useDefineForClassFields": true
|
||||
},
|
||||
"exclude": [
|
||||
"eslint.config.mjs",
|
||||
"postcss.config.js",
|
||||
"prettier.config.mjs",
|
||||
"tailwind.config.js",
|
||||
"vite.config.ts"
|
||||
]
|
||||
"exclude": [
|
||||
"eslint.config.mjs",
|
||||
"postcss.config.js",
|
||||
"prettier.config.mjs",
|
||||
"tailwind.config.js",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
import path from "path";
|
||||
import { defineConfig } from "vite";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import path from "path";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
// @ts-expect-error process is a nodejs global
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
//
|
||||
// 1. prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
host: host || false,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: "ws",
|
||||
host,
|
||||
port: 1421,
|
||||
}
|
||||
: undefined,
|
||||
watch: {
|
||||
// 3. tell vite to ignore watching `src-tauri`
|
||||
ignored: ["**/src-tauri/**"],
|
||||
},
|
||||
},
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
//
|
||||
// 1. prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
host: host || false,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: "ws",
|
||||
host,
|
||||
port: 1421,
|
||||
}
|
||||
: undefined,
|
||||
watch: {
|
||||
// 3. tell vite to ignore watching `src-tauri`
|
||||
ignored: ["**/src-tauri/**"],
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user