Compare commits

..
52 Commits
Author SHA1 Message Date
Lncvrt 3c7487f20f 1.5.7 2026-02-09 20:48:25 -07:00
Lncvrt 97231c6b38 Let the user approve revision updates before proceeding 2026-02-09 20:46:15 -07:00
Lncvrt a93e4ab521 Fix TS 2026-02-09 20:39:59 -07:00
Lncvrt e7c48b182f Downgrade eslint from 10.0.0 to 9.39.2 to fix issues 2026-02-09 20:38:52 -07:00
Lncvrt 16dd3fd613 Fixes here 2026-02-09 20:22:11 -07:00
Lncvrt c91303d194 Make reinstall button change popup to downloads popup stead 2026-02-09 20:13:55 -07:00
Lncvrt a76e81789b Make this show N/A if can't load 2026-02-09 19:28:22 -07:00
Lncvrt c909973aab Not sure why that was like that 2026-02-09 19:20:50 -07:00
Lncvrt 28f694e4e7 Update dependencies 2026-02-09 18:59:15 -07:00
Lncvrt 508e4d1640 1.5.6 2026-02-07 20:22:19 -07:00
Lncvrt 41a66eaf86 Make sure __MACOSX and .DS_Store don't get included 2026-02-07 20:19:20 -07:00
Lncvrt ac4b76fa46 Set permissions properly when unzipping 2026-02-07 20:18:55 -07:00
Lncvrt 2e02275c29 1.5.5 2026-02-04 19:22:03 -07:00
Lncvrt dbaac6a6a6 Remove green & mint theme 2026-02-04 19:22:01 -07:00
Lncvrt 68525f161e Add a reinstall button for manage menu 2026-02-04 18:28:03 -07:00
Lncvrt d386454e91 Fix versions config not being set right when downloading 2026-02-04 17:58:07 -07:00
Lncvrt 6e05aac871 Fix games that can't even be installed showing up 2026-02-04 16:56:25 -07:00
Lncvrt fbe3feec9d Fix some issues 2026-02-04 16:47:54 -07:00
Lncvrt 1c540ad35b Fix eslint 2026-02-04 15:55:08 -07:00
Lncvrt 4ec597967a 1.5.4 2026-02-03 18:51:40 -07:00
Lncvrt be4b8fc3ee 1.5.3 2026-02-03 17:33:46 -07:00
Lncvrt d9fa967ade Make it so you can copy text here 2026-02-03 17:27:02 -07:00
Lncvrt 0f4ee9f78c 1.5.2 + Update dependencies 2026-01-28 15:21:57 -07:00
Lncvrt cc5d814740 Make downloads popup close on finish, and add a revision check 2026-01-28 15:20:02 -07:00
Lncvrt 53ecbbd07f Fix 2026-01-27 20:01:39 -07:00
Lncvrt d0810ae80e 1.5.1 + Update dependencies 2026-01-27 18:52:20 -07:00
Lncvrt d688e5181f No point in this actually 2026-01-27 18:45:04 -07:00
Lncvrt 1d7f888563 Savefile is proper now 2026-01-27 18:43:15 -07:00
Lncvrt 482708038e Format date using the system formatter 2026-01-27 11:33:40 -07:00
Lncvrt ce3830ba2e Fixes 2026-01-27 10:21:44 -07:00
Lncvrt 0acf23b2f6 oops 2026-01-27 10:09:22 -07:00
Lncvrt 31adc14156 Add subcategory support 2026-01-27 10:08:41 -07:00
Lncvrt bd9209359e Update dependencies + Make window state presistent 2026-01-26 08:41:50 -07:00
Lncvrt 803cfb8742 Idk why I didn't do this before 2026-01-15 20:50:37 -07:00
Lncvrt f3fdf76817 Add wine support back for Linux 2026-01-08 11:28:25 -07:00
Lncvrt 2777e6dac0 1.5.0 2026-01-07 19:56:34 -07:00
Lncvrt a551d5fb52 Change the colors of popup close button 2026-01-07 19:39:15 -07:00
Lncvrt 08915ad2ae Remove this case, I want to eventually make it close the popup but I haven't gotten that to work for some reason 2026-01-07 19:36:36 -07:00
Lncvrt 1dd75f8ccf Improve download versions/games button size 2026-01-07 19:14:54 -07:00
Lncvrt 3dc24ab3d7 Use proper way of detecting when a user hovers for games/installs page 2026-01-07 19:01:58 -07:00
Lncvrt a3e9067ba0 Change rounding for popup close button 2026-01-07 19:01:39 -07:00
Lncvrt a0a763ae57 Remove the manage button and make it a right-click instead. And also change the button height/width. Along with more re-arranging in layout.tsx 2026-01-07 18:29:17 -07:00
Lncvrt c56a903d55 Moove stuff around to make more sense 2026-01-07 18:14:33 -07:00
Lncvrt c07828f244 Improve the logic for uninstalling a version, it was incredibly bad and stupid 2026-01-07 18:10:14 -07:00
Lncvrt cf4f1c15ea Launching works as intended now 2026-01-07 18:07:11 -07:00
Lncvrt 76797c6120 Bring back this, either works or doesn't on linux and windows. I will have to test 2026-01-07 17:45:07 -07:00
Lncvrt 36ed3e0095 Rename this to make more sense 2026-01-07 17:43:26 -07:00
Lncvrt e0ba25da77 Improve parts of launch/download logic 2026-01-07 17:29:14 -07:00
Lncvrt e89b0fac8a Fix a memory leak that doesn't fix until another version is downloaded (can take up to 400mb of ram) 2026-01-07 17:28:42 -07:00
Lncvrt fa256dd004 Update dependencies 2026-01-07 17:28:01 -07:00
Lncvrt b5c6598722 Well that's stupid but it's fixed now 2026-01-07 15:09:55 -07:00
Lncvrt db111aaa2e Fix stupidness here 2026-01-07 15:01:44 -07:00
28 changed files with 1144 additions and 642 deletions

No files matched your search

+89 -89
View File
@@ -8,32 +8,32 @@
"@fortawesome/fontawesome-svg-core": "7.1.0", "@fortawesome/fontawesome-svg-core": "7.1.0",
"@fortawesome/free-brands-svg-icons": "7.1.0", "@fortawesome/free-brands-svg-icons": "7.1.0",
"@fortawesome/free-solid-svg-icons": "7.1.0", "@fortawesome/free-solid-svg-icons": "7.1.0",
"@fortawesome/react-fontawesome": "3.1.1", "@fortawesome/react-fontawesome": "3.2.0",
"@tauri-apps/api": "2.9.1", "@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2", "@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-dialog": "2.4.2", "@tauri-apps/plugin-dialog": "2.6.0",
"@tauri-apps/plugin-fs": "2.4.4", "@tauri-apps/plugin-fs": "2.4.5",
"@tauri-apps/plugin-notification": "2.3.3", "@tauri-apps/plugin-notification": "2.3.3",
"@tauri-apps/plugin-opener": "2.5.2", "@tauri-apps/plugin-opener": "2.5.3",
"@tauri-apps/plugin-os": "2.3.2", "@tauri-apps/plugin-os": "2.3.2",
"axios": "1.13.2", "@tauri-apps/plugin-window-state": "2.4.1",
"date-fns": "4.1.0", "axios": "1.13.5",
"next": "16.1.1", "next": "16.1.6",
"pretty-bytes": "7.1.0", "pretty-bytes": "7.1.0",
"react": "19.2.3", "react": "19.2.4",
"react-dom": "19.2.3", "react-dom": "19.2.4",
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "3.3.3", "@eslint/eslintrc": "3.3.3",
"@tailwindcss/postcss": "4.1.18", "@tailwindcss/postcss": "4.1.18",
"@tauri-apps/cli": "2.9.6", "@tauri-apps/cli": "2.10.0",
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/node": "25.0.3", "@types/node": "25.2.2",
"@types/react": "19.2.7", "@types/react": "19.2.13",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"eslint": "9.39.2", "eslint": "9.39.2",
"eslint-config-next": "16.1.1", "eslint-config-next": "16.1.6",
"tailwindcss": "4.1.18", "tailwindcss": "4.1.18",
"typescript": "5.9.3", "typescript": "5.9.3",
}, },
@@ -42,21 +42,21 @@
"packages": { "packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
@@ -64,19 +64,19 @@
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
"@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -106,7 +106,7 @@
"@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA=="], "@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA=="],
"@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@3.1.1", "", { "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~6 || ~7", "react": "^18.0.0 || ^19.0.0" } }, "sha512-EDllr9hpodc21odmUywHS1alXNiCd4E8sp5GJ5s7wYINz8vSmMiNWpALTiuYODb865YyQ/NlyiN4mbXp7HCNqg=="], "@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@3.2.0", "", { "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~6 || ~7", "react": "^18.0.0 || ^19.0.0" } }, "sha512-E9Gu1hqd6JussVO26EC4WqRZssXMnQr2ol7ZNWkkFOH8jZUaxDJ9Z9WF9wIVkC+kJGXUdY3tlffpDwEKfgQrQw=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -178,25 +178,25 @@
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
"@next/env": ["@next/env@16.1.1", "", {}, "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA=="], "@next/env": ["@next/env@16.1.6", "", {}, "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ=="],
"@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.1.1", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-Ovb/6TuLKbE1UiPcg0p39Ke3puyTCIKN9hGbNItmpQsp+WX3qrjO3WaMVSi6JHr9X1NrmthqIguVHodMJbh/dw=="], "@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.1.6", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ=="],
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA=="], "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw=="],
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw=="], "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ=="],
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ=="], "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw=="],
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg=="], "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ=="],
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ=="], "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ=="],
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA=="], "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg=="],
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA=="], "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.1.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw=="],
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw=="], "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A=="],
"@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.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@@ -240,44 +240,46 @@
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="], "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="],
"@tauri-apps/api": ["@tauri-apps/api@2.9.1", "", {}, "sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw=="], "@tauri-apps/api": ["@tauri-apps/api@2.10.1", "", {}, "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw=="],
"@tauri-apps/cli": ["@tauri-apps/cli@2.9.6", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.9.6", "@tauri-apps/cli-darwin-x64": "2.9.6", "@tauri-apps/cli-linux-arm-gnueabihf": "2.9.6", "@tauri-apps/cli-linux-arm64-gnu": "2.9.6", "@tauri-apps/cli-linux-arm64-musl": "2.9.6", "@tauri-apps/cli-linux-riscv64-gnu": "2.9.6", "@tauri-apps/cli-linux-x64-gnu": "2.9.6", "@tauri-apps/cli-linux-x64-musl": "2.9.6", "@tauri-apps/cli-win32-arm64-msvc": "2.9.6", "@tauri-apps/cli-win32-ia32-msvc": "2.9.6", "@tauri-apps/cli-win32-x64-msvc": "2.9.6" }, "bin": { "tauri": "tauri.js" } }, "sha512-3xDdXL5omQ3sPfBfdC8fCtDKcnyV7OqyzQgfyT5P3+zY6lcPqIYKQBvUasNvppi21RSdfhy44ttvJmftb0PCDw=="], "@tauri-apps/cli": ["@tauri-apps/cli@2.10.0", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.0", "@tauri-apps/cli-darwin-x64": "2.10.0", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0", "@tauri-apps/cli-linux-arm64-gnu": "2.10.0", "@tauri-apps/cli-linux-arm64-musl": "2.10.0", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-musl": "2.10.0", "@tauri-apps/cli-win32-arm64-msvc": "2.10.0", "@tauri-apps/cli-win32-ia32-msvc": "2.10.0", "@tauri-apps/cli-win32-x64-msvc": "2.10.0" }, "bin": { "tauri": "tauri.js" } }, "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q=="],
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.9.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ=="], "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.9.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw=="], "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q=="],
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.9.6", "", { "os": "linux", "cpu": "arm" }, "sha512-/zde3bFroFsNXOHN204DC2qUxAcAanUjVXXSdEGmhwMUZeAQalNj5cz2Qli2elsRjKN/hVbZOJj0gQ5zaYUjSg=="], "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.0", "", { "os": "linux", "cpu": "arm" }, "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g=="],
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.9.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-pvbljdhp9VOo4RnID5ywSxgBs7qiylTPlK56cTk7InR3kYSTJKYMqv/4Q/4rGo/mG8cVppesKIeBMH42fw6wjg=="], "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA=="],
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.9.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-02TKUndpodXBCR0oP//6dZWGYcc22Upf2eP27NvC6z0DIqvkBBFziQUcvi2n6SrwTRL0yGgQjkm9K5NIn8s6jw=="], "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA=="],
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.9.6", "", { "os": "linux", "cpu": "none" }, "sha512-fmp1hnulbqzl1GkXl4aTX9fV+ubHw2LqlLH1PE3BxZ11EQk+l/TmiEongjnxF0ie4kV8DQfDNJ1KGiIdWe1GvQ=="], "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.0", "", { "os": "linux", "cpu": "none" }, "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw=="],
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.9.6", "", { "os": "linux", "cpu": "x64" }, "sha512-vY0le8ad2KaV1PJr+jCd8fUF9VOjwwQP/uBuTJvhvKTloEwxYA/kAjKK9OpIslGA9m/zcnSo74czI6bBrm2sYA=="], "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng=="],
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.9.6", "", { "os": "linux", "cpu": "x64" }, "sha512-TOEuB8YCFZTWVDzsO2yW0+zGcoMiPPwcUgdnW1ODnmgfwccpnihDRoks+ABT1e3fHb1ol8QQWsHSCovb3o2ENQ=="], "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q=="],
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.9.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-ujmDGMRc4qRLAnj8nNG26Rlz9klJ0I0jmZs2BPpmNNf0gM/rcVHhqbEkAaHPTBVIrtUdf7bGvQAD2pyIiUrBHQ=="], "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g=="],
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.9.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-S4pT0yAJgFX8QRCyKA1iKjZ9Q/oPjCZf66A/VlG5Yw54Nnr88J1uBpmenINbXxzyhduWrIXBaUbEY1K80ZbpMg=="], "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A=="],
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.9.6", "", { "os": "win32", "cpu": "x64" }, "sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw=="], "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ=="],
"@tauri-apps/plugin-clipboard-manager": ["@tauri-apps/plugin-clipboard-manager@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ=="], "@tauri-apps/plugin-clipboard-manager": ["@tauri-apps/plugin-clipboard-manager@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ=="],
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ=="], "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.6.0", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg=="],
"@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.4", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-MTorXxIRmOnOPT1jZ3w96vjSuScER38ryXY88vl5F0uiKdnvTKKTtaEjTEo8uPbl4e3gnUtfsDVwC7h77GQLvQ=="], "@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.5", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA=="],
"@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="], "@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="],
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew=="], "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="],
"@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="], "@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="],
"@tauri-apps/plugin-window-state": ["@tauri-apps/plugin-window-state@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/crypto-js": ["@types/crypto-js@4.2.2", "", {}, "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ=="], "@types/crypto-js": ["@types/crypto-js@4.2.2", "", {}, "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ=="],
@@ -288,31 +290,31 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="], "@types/node": ["@types/node@25.2.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ=="],
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="], "@types/react": ["@types/react@19.2.13", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.51.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/type-utils": "8.51.0", "@typescript-eslint/utils": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.51.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.55.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/type-utils": "8.55.0", "@typescript-eslint/utils": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.55.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.51.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.55.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.51.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.51.0", "@typescript-eslint/types": "^8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ=="], "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.55.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.55.0", "@typescript-eslint/types": "^8.55.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0" } }, "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.51.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw=="], "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.55.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0", "debug": "^4.3.4", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q=="], "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/utils": "8.55.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.55.0", "", {}, "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.51.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.51.0", "@typescript-eslint/tsconfig-utils": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.55.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.55.0", "@typescript-eslint/tsconfig-utils": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.51.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@8.55.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA=="],
"@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="],
@@ -388,15 +390,15 @@
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
"axe-core": ["axe-core@4.11.0", "", {}, "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ=="], "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="],
"axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.11", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
@@ -412,7 +414,7 @@
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001762", "", {}, "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw=="], "caniuse-lite": ["caniuse-lite@1.0.30001769", "", {}, "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
@@ -442,8 +444,6 @@
"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=="], "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.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
@@ -460,11 +460,11 @@
"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=="], "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=="],
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], "electron-to-chromium": ["electron-to-chromium@1.5.286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="],
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], "enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="],
"es-abstract": ["es-abstract@1.24.1", "", { "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.4", "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.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "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-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.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.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], "es-abstract": ["es-abstract@1.24.1", "", { "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.4", "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.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "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-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.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.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="],
@@ -488,7 +488,7 @@
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "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.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.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-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "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.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.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-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
"eslint-config-next": ["eslint-config-next@16.1.1", "", { "dependencies": { "@next/eslint-plugin-next": "16.1.1", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-55nTpVWm3qeuxoQKLOjQVciKZJUphKrNM0fCcQHAIOGl6VFXgaqeMfv0aKJhs7QtcnlAPhNVqsqRfRjeKBPIUA=="], "eslint-config-next": ["eslint-config-next@16.1.6", "", { "dependencies": { "@next/eslint-plugin-next": "16.1.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA=="],
"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-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=="],
@@ -562,7 +562,7 @@
"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=="], "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=="],
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
@@ -740,7 +740,7 @@
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"next": ["next@16.1.1", "", { "dependencies": { "@next/env": "16.1.1", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.1", "@next/swc-darwin-x64": "16.1.1", "@next/swc-linux-arm64-gnu": "16.1.1", "@next/swc-linux-arm64-musl": "16.1.1", "@next/swc-linux-x64-gnu": "16.1.1", "@next/swc-linux-x64-musl": "16.1.1", "@next/swc-win32-arm64-msvc": "16.1.1", "@next/swc-win32-x64-msvc": "16.1.1", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w=="], "next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="],
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
@@ -796,9 +796,9 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -882,7 +882,7 @@
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"ts-api-utils": ["ts-api-utils@2.3.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg=="], "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"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=="], "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=="],
@@ -900,7 +900,7 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.51.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.51.0", "@typescript-eslint/parser": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA=="], "typescript-eslint": ["typescript-eslint@8.55.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.55.0", "@typescript-eslint/parser": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/utils": "8.55.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw=="],
"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=="], "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=="],
@@ -920,7 +920,7 @@
"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-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.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
@@ -928,7 +928,7 @@
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zod": ["zod@4.3.4", "", {}, "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A=="], "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
@@ -936,9 +936,9 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -952,7 +952,7 @@
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"eslint-config-next/globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], "eslint-config-next/globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="],
@@ -966,13 +966,13 @@
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"is-bun-module/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "is-bun-module/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
} }
+2 -1
View File
@@ -11,7 +11,8 @@ const eslintConfig = defineConfig([
'.next/**', '.next/**',
'out/**', 'out/**',
'build/**', 'build/**',
'next-env.d.ts' 'next-env.d.ts',
'src-tauri/**'
]) ])
]) ])
+15 -15
View File
@@ -1,7 +1,7 @@
{ {
"name": "lncvrt-games-launcher", "name": "lncvrt-games-launcher",
"private": true, "private": true,
"version": "1.4.0", "version": "1.5.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@@ -14,32 +14,32 @@
"@fortawesome/fontawesome-svg-core": "7.1.0", "@fortawesome/fontawesome-svg-core": "7.1.0",
"@fortawesome/free-brands-svg-icons": "7.1.0", "@fortawesome/free-brands-svg-icons": "7.1.0",
"@fortawesome/free-solid-svg-icons": "7.1.0", "@fortawesome/free-solid-svg-icons": "7.1.0",
"@fortawesome/react-fontawesome": "3.1.1", "@fortawesome/react-fontawesome": "3.2.0",
"@tauri-apps/api": "2.9.1", "@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2", "@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-dialog": "2.4.2", "@tauri-apps/plugin-dialog": "2.6.0",
"@tauri-apps/plugin-fs": "2.4.4", "@tauri-apps/plugin-fs": "2.4.5",
"@tauri-apps/plugin-notification": "2.3.3", "@tauri-apps/plugin-notification": "2.3.3",
"@tauri-apps/plugin-opener": "2.5.2", "@tauri-apps/plugin-opener": "2.5.3",
"@tauri-apps/plugin-os": "2.3.2", "@tauri-apps/plugin-os": "2.3.2",
"axios": "1.13.2", "@tauri-apps/plugin-window-state": "2.4.1",
"date-fns": "4.1.0", "axios": "1.13.5",
"next": "16.1.1", "next": "16.1.6",
"pretty-bytes": "7.1.0", "pretty-bytes": "7.1.0",
"react": "19.2.3", "react": "19.2.4",
"react-dom": "19.2.3" "react-dom": "19.2.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "3.3.3", "@eslint/eslintrc": "3.3.3",
"@tailwindcss/postcss": "4.1.18", "@tailwindcss/postcss": "4.1.18",
"@tauri-apps/cli": "2.9.6", "@tauri-apps/cli": "2.10.0",
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/node": "25.0.3", "@types/node": "25.2.2",
"@types/react": "19.2.7", "@types/react": "19.2.13",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"eslint": "9.39.2", "eslint": "9.39.2",
"eslint-config-next": "16.1.1", "eslint-config-next": "16.1.6",
"tailwindcss": "4.1.18", "tailwindcss": "4.1.18",
"typescript": "5.9.3" "typescript": "5.9.3"
} }
+14 -13
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "lncvrt-games-launcher" name = "lncvrt-games-launcher"
version = "1.4.0" version = "1.5.7"
authors = ["Lncvrt"] authors = ["Lncvrt"]
edition = "2024" edition = "2024"
@@ -9,24 +9,24 @@ name = "lncvrt_games_launcher_lib"
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.5.3", features = [] } tauri-build = { version = "2.5.5", features = [] }
[dependencies] [dependencies]
tauri = { version = "2.9.5", features = ["macos-private-api"] } tauri = { version = "2.10.2", features = ["macos-private-api"] }
tauri-plugin-opener = "2.5.2" tauri-plugin-opener = "2.5.3"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.148" serde_json = "1.0.149"
tauri-plugin-os = "2.3.2" tauri-plugin-os = "2.3.2"
reqwest = { version = "0.13.1", default-features = false, features = ["stream", "rustls"] } reqwest = { version = "0.13.2", default-features = false, features = ["stream", "rustls"] }
tokio = "1.48.0" tokio = "1.49.0"
futures-util = { version = "0.3.31", features = ["io"] } futures-util = { version = "0.3.31", features = ["io"] }
tauri-plugin-decorum = "1.1.1" tauri-plugin-decorum = "1.1.1"
tauri-plugin-fs = "2.4.4" tauri-plugin-fs = "2.4.5"
zip = "7.0.0" zip = "7.4.0"
libc = "0.2.178" libc = "0.2.181"
tauri-plugin-dialog = "2.4.2" tauri-plugin-dialog = "2.6.0"
tauri-plugin-notification = "2.3.3" tauri-plugin-notification = "2.3.3"
sysinfo = "0.37.2" sysinfo = "0.38.1"
sha2 = "0.10.9" sha2 = "0.10.9"
tauri-plugin-clipboard-manager = "2.3.2" tauri-plugin-clipboard-manager = "2.3.2"
@@ -34,6 +34,7 @@ tauri-plugin-clipboard-manager = "2.3.2"
shlex = "1.3.0" shlex = "1.3.0"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.6" tauri-plugin-single-instance = "2.4.0"
tauri-plugin-window-state = "2.4.1"
+9 -3
View File
@@ -21,11 +21,17 @@
"core:window:allow-toggle-maximize", "core:window:allow-toggle-maximize",
"decorum:allow-show-snap-overlay", "decorum:allow-show-snap-overlay",
"fs:default", "fs:default",
"fs:allow-applocaldata-read",
"fs:allow-applocaldata-write",
"dialog:default", "dialog:default",
"notification:default", "notification:default",
"clipboard-manager:default", "clipboard-manager:default",
"clipboard-manager:allow-write-text" "clipboard-manager:allow-write-text",
"fs:allow-applocaldata-read",
"fs:allow-applocaldata-write",
{
"identifier": "fs:scope",
"allow": [
{ "path": "$APPLOCALDATA/game/**" }
]
}
] ]
} }
+14
View File
@@ -0,0 +1,14 @@
{
"identifier": "desktop-capability",
"platforms": [
"macOS",
"windows",
"linux"
],
"windows": [
"main"
],
"permissions": [
"window-state:default"
]
}
+102 -79
View File
@@ -15,42 +15,72 @@ use tauri::{AppHandle, Emitter, Manager};
use tauri_plugin_dialog::{DialogExt, MessageDialogKind}; use tauri_plugin_dialog::{DialogExt, MessageDialogKind};
use tauri_plugin_opener::OpenerExt; use tauri_plugin_opener::OpenerExt;
use tauri_plugin_os::platform; use tauri_plugin_os::platform;
use tokio::io::AsyncReadExt;
use tokio::{io::AsyncWriteExt, time::timeout}; use tokio::{io::AsyncWriteExt, time::timeout};
use zip::ZipArchive; use zip::ZipArchive;
#[cfg(target_os = "linux")]
use std::os::unix::fs::PermissionsExt;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use tauri_plugin_decorum::WebviewWindowExt; use tauri_plugin_decorum::WebviewWindowExt;
fn is_running_by_path(path: &PathBuf) -> bool { #[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[allow(unused)]
fn is_running_by_path(path: &Path) -> bool {
let sys = System::new_all(); let sys = System::new_all();
sys.processes().values().any(|proc| { let target = path.canonicalize().ok();
if let Some(exe) = proc.exe() { if target.is_none() {
exe == path return false;
} else {
false
} }
let target = target.unwrap();
sys.processes().values().any(|proc| {
proc.exe()
.and_then(|exe| exe.canonicalize().ok())
.map_or(false, |exe| exe == target)
}) })
} }
fn should_skip(name: &str) -> bool {
name.starts_with("__MACOSX/")
|| name == "__MACOSX"
|| name.ends_with("/.DS_Store")
|| name.ends_with(".DS_Store")
}
async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String { async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String {
let res = tauri::async_runtime::spawn_blocking(move || { let res = tauri::async_runtime::spawn_blocking(move || {
let file = File::open(zip_path)?; let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(BufReader::new(file))?; let mut archive = ZipArchive::new(BufReader::new(file))?;
for i in 0..archive.len() { for i in 0..archive.len() {
let mut file = archive.by_index(i)?; let mut entry = archive.by_index(i)?;
let outpath = out_dir.join(file.name()); let name = entry.name();
if file.is_dir() { if should_skip(name) {
continue;
}
let outpath = out_dir.join(name);
if entry.is_dir() {
create_dir_all(&outpath)?; create_dir_all(&outpath)?;
#[cfg(unix)]
if let Some(mode) = entry.unix_mode() {
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode))?;
}
} else { } else {
if let Some(parent) = outpath.parent() { if let Some(parent) = outpath.parent() {
create_dir_all(parent)?; create_dir_all(parent)?;
} }
let mut outfile = File::create(&outpath)?; let mut outfile = File::create(&outpath)?;
copy(&mut file, &mut outfile)?; copy(&mut entry, &mut outfile)?;
#[cfg(unix)]
if let Some(mode) = entry.unix_mode() {
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode))?;
}
} }
} }
@@ -182,9 +212,26 @@ async fn download(
app.emit("download-hash-checking", format!("{}", &name)) app.emit("download-hash-checking", format!("{}", &name))
.unwrap(); .unwrap();
let download_hash = {
let mut file = tokio::fs::File::open(download_part_path.clone())
.await
.unwrap();
let mut hasher = Sha512::new(); let mut hasher = Sha512::new();
hasher.update(&tokio::fs::read(download_part_path.clone()).await.unwrap()); {
let download_hash = format!("{:x}", hasher.finalize()); let mut buffer = [0; 8192];
loop {
let bytes_read = file.read(&mut buffer).await.unwrap();
if bytes_read == 0 {
break;
}
hasher.update(&buffer[..bytes_read]);
}
}
drop(file);
format!("{:x}", hasher.finalize())
};
if hash != download_hash { if hash != download_hash {
tokio::fs::remove_file(download_part_path.clone()) tokio::fs::remove_file(download_part_path.clone())
.await .await
@@ -205,102 +252,78 @@ async fn download(
return "-1".to_string(); return "-1".to_string();
} }
#[cfg(target_os = "linux")]
{
let executable_path = game_path.join(&name).join(&executable);
let mut perms = fs::metadata(&executable_path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(executable_path, perms).unwrap();
}
#[cfg(target_os = "macos")]
{
use std::fs;
use std::os::unix::fs::PermissionsExt;
let macos_app_path = game_path
.join(&name)
.join(&executable)
.join("Contents")
.join("MacOS")
.join(
&executable
.chars()
.take(executable.chars().count() - 4)
.collect::<String>(),
);
let mut perms = fs::metadata(&macos_app_path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&macos_app_path, perms).unwrap();
}
return "1".to_string(); return "1".to_string();
} }
#[allow(unused_variables)] #[allow(unused_variables)]
#[tauri::command] #[tauri::command]
fn launch_game(app: AppHandle, name: String, executable: String) { fn launch_game(
app: AppHandle,
name: String,
executable: String,
display_name: String,
use_wine: bool,
wine_command: String,
) {
let game_folder = app let game_folder = app
.path() .path()
.app_local_data_dir() .app_local_data_dir()
.unwrap() .unwrap()
.join("game") .join("game")
.join(&name); .join(&name);
let game_path = game_folder.join(&executable); if !game_folder.exists() {
if !game_path.exists() {
app.dialog()
.message(
format!(
"Executable \"{}\" not found.\n\nTry reinstalling the game or make a support request in the Community link on the sidebar.",
game_path.display().to_string()
)
)
.kind(MessageDialogKind::Error)
.title("Game not found")
.show(|_| {});
return; return;
} }
if is_running_by_path(&game_path) {
let exe_path = game_folder.join(&executable);
//if already running on macos, it'll auto take the user to that proccess
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
if !use_wine && is_running_by_path(&exe_path) {
app.dialog() app.dialog()
.message(format!("The version {} is already running.", name)) .message(format!(
"{} is already running, if this doesn't seem true, try to kill the proccess.",
display_name
))
.kind(MessageDialogKind::Error) .kind(MessageDialogKind::Error)
.title("Game already running") .title("Game already running")
.show(|_| {}); .show(|_| {});
return; return;
} }
}
#[cfg(target_os = "linux")]
{
if use_wine {
let quoted_path = format!("\"{}\"", exe_path.to_string_lossy());
let cmd = wine_command.replace("%path%", &quoted_path);
Command::new("bash")
.arg("-c")
.arg(cmd)
.current_dir(&game_folder)
.spawn()
.unwrap();
return;
}
}
if platform() == "macos" { if platform() == "macos" {
Command::new("open") Command::new("open")
.arg(&game_path) .arg(&executable)
.current_dir(&game_folder) .current_dir(&game_folder)
.spawn() .spawn()
.unwrap(); .unwrap();
} else { } else {
Command::new(&game_path) Command::new(&exe_path)
.current_dir(&game_folder) .current_dir(&game_folder)
.spawn() .spawn()
.unwrap(); .unwrap();
} }
} }
#[tauri::command]
async fn uninstall_version(app: AppHandle, name: String) {
let game_path = app
.path()
.app_local_data_dir()
.unwrap()
.join("game")
.join(&name);
if game_path.exists() {
if let Err(_) = tokio::fs::remove_dir_all(&game_path).await {
app.emit("version-failed", &name).unwrap();
} else {
app.emit("version-uninstalled", &name).unwrap();
}
} else {
app.emit("version-uninstalled", &name).unwrap();
}
}
#[tauri::command] #[tauri::command]
async fn open_folder(app: AppHandle, name: String) { async fn open_folder(app: AppHandle, name: String) {
let game_path = app let game_path = app
@@ -329,6 +352,7 @@ async fn open_folder(app: AppHandle, name: String) {
pub fn run() { pub fn run() {
#[allow(unused_variables)] #[allow(unused_variables)]
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_window_state::Builder::new().build())
.plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
@@ -345,7 +369,6 @@ pub fn run() {
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
download, download,
launch_game, launch_game,
uninstall_version,
open_folder, open_folder,
folder_size folder_size
]) ])
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.4.0", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.4.0", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.4.0", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.4.0", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+19 -12
View File
@@ -1,6 +1,12 @@
'use client' 'use client'
import { createContext, useContext, ReactNode } from 'react' import {
createContext,
useContext,
ReactNode,
Dispatch,
SetStateAction
} from 'react'
import { DownloadProgress } from './types/DownloadProgress' import { DownloadProgress } from './types/DownloadProgress'
import { VersionsConfig } from './types/VersionsConfig' import { VersionsConfig } from './types/VersionsConfig'
import { NormalConfig } from './types/NormalConfig' import { NormalConfig } from './types/NormalConfig'
@@ -11,31 +17,32 @@ import { Game } from './types/Game'
type GlobalCtxType = { type GlobalCtxType = {
serverVersionList: ServerVersionsResponse | null serverVersionList: ServerVersionsResponse | null
selectedVersionList: string[] selectedVersionList: string[]
setSelectedVersionList: (v: string[]) => void setSelectedVersionList: (value: SetStateAction<string[]>) => void
downloadProgress: DownloadProgress[] downloadProgress: DownloadProgress[]
setDownloadProgress: (v: DownloadProgress[]) => void setDownloadProgress: Dispatch<SetStateAction<DownloadProgress[]>>
showPopup: boolean showPopup: boolean
setShowPopup: (v: boolean) => void setShowPopup: Dispatch<SetStateAction<boolean>>
popupMode: number | null popupMode: number | null
setPopupMode: (v: number | null) => void setPopupMode: Dispatch<SetStateAction<number | null>>
fadeOut: boolean fadeOut: boolean
setFadeOut: (v: boolean) => void setFadeOut: Dispatch<SetStateAction<boolean>>
downloadedVersionsConfig: VersionsConfig | null downloadedVersionsConfig: VersionsConfig | null
setDownloadedVersionsConfig: (v: VersionsConfig | null) => void setDownloadedVersionsConfig: Dispatch<SetStateAction<VersionsConfig | null>>
normalConfig: NormalConfig | null normalConfig: NormalConfig | null
setNormalConfig: (v: NormalConfig | null) => void setNormalConfig: Dispatch<SetStateAction<NormalConfig | null>>
managingVersion: string | null managingVersion: string | null
setManagingVersion: (v: string | null) => void setManagingVersion: Dispatch<SetStateAction<string | null>>
setSelectedGame: (v: number | null) => void setSelectedGame: Dispatch<SetStateAction<number | null>>
getVersionInfo: (id: string | undefined) => GameVersion | undefined getVersionInfo: (id: string | undefined) => GameVersion | undefined
getVersionGame: (id: number | undefined) => Game | undefined getGameInfo: (game: number | undefined) => Game | undefined
getListOfGames: () => Game[] getListOfGames(): Game[]
getVersionsAmountData: (gameId: number) => { getVersionsAmountData: (gameId: number) => {
installed: number installed: number
total: number total: number
} | null } | null
viewingInfoFromDownloads: boolean viewingInfoFromDownloads: boolean
version: string | null version: string | null
downloadVersions: (list: string[]) => Promise<void>
} }
const GlobalCtx = createContext<GlobalCtxType | null>(null) const GlobalCtx = createContext<GlobalCtxType | null>(null)
+9 -29
View File
@@ -28,18 +28,6 @@ body {
--col8: rgb(152, 128, 128); --col8: rgb(152, 128, 128);
} }
.green-theme {
--col0: rgb(8, 32, 8);
--col1: rgb(16, 40, 16);
--col2: rgb(32, 56, 32);
--col3: rgb(48, 72, 48);
--col4: rgb(64, 88, 64);
--col5: rgb(80, 104, 80);
--col6: rgb(96, 120, 96);
--col7: rgb(112, 136, 112);
--col8: rgb(128, 152, 128);
}
.blue-theme { .blue-theme {
--col0: rgb(8, 8, 32); --col0: rgb(8, 8, 32);
--col1: rgb(16, 16, 40); --col1: rgb(16, 16, 40);
@@ -64,31 +52,23 @@ body {
--col8: rgb(140, 128, 152); --col8: rgb(140, 128, 152);
} }
.mint-theme {
--col0: rgb(8, 32, 16);
--col1: rgb(16, 48, 32);
--col2: rgb(32, 56, 40);
--col3: rgb(48, 72, 48);
--col4: rgb(64, 88, 66);
--col5: rgb(80, 104, 65);
--col6: rgb(96, 120, 80);
--col7: rgb(112, 136, 85);
--col8: rgb(128, 152, 95);
}
.button { .button {
@apply rounded-md cursor-pointer text-[16px] py-1.5 px-3 transition-colors border; @apply rounded-md cursor-pointer text-[16px] py-1 px-2 transition-colors border;
} }
.btntheme1 { .btntheme1 {
@apply bg-(--col2) border-(--col4) hover:bg-(--col4) hover:border-(--col6) disabled:text-gray-300 disabled:bg-(--col1) disabled:border-(--col5) disabled:hover:text-gray-100 disabled:hover:bg-(--col2) disabled:hover:border-(--col6); @apply bg-(--col2) border-(--col4) hover:bg-(--col4) hover:border-(--col6) disabled:text-gray-300 disabled:bg-(--col1) disabled:border-(--col5) disabled:hover:text-gray-100 disabled:hover:bg-(--col2) disabled:hover:border-(--col6);
} }
.btntheme2 { .btntheme2,
.downloads-entry .entry-info-item,
.downloads-entry .button {
@apply bg-(--col3) border-(--col5) hover:bg-(--col5) hover:border-(--col7) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col6) disabled:hover:text-gray-100 disabled:hover:bg-(--col3) disabled:hover:border-(--col7); @apply bg-(--col3) border-(--col5) hover:bg-(--col5) hover:border-(--col7) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col6) disabled:hover:text-gray-100 disabled:hover:bg-(--col3) disabled:hover:border-(--col7);
} }
.btntheme3 { .btntheme3,
.downloads-entry:hover .entry-info-item,
.downloads-entry:hover .button {
@apply bg-(--col4) border-(--col6) hover:bg-(--col6) hover:border-(--col8) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col7) disabled:hover:text-gray-100 disabled:hover:bg-(--col4) disabled:hover:border-(--col8); @apply bg-(--col4) border-(--col6) hover:bg-(--col6) hover:border-(--col8) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col7) disabled:hover:text-gray-100 disabled:hover:bg-(--col4) disabled:hover:border-(--col8);
} }
@@ -147,7 +127,7 @@ body {
} }
.close-button { .close-button {
@apply flex justify-center items-center absolute bg-(--col3) hover:bg-(--col4) text-2xl cursor-pointer text-gray-300 hover:text-white h-12 w-12 p-3 rounded-xl left-2 top-2 transition-colors border border-(--col4) hover:border-(--col5); @apply flex justify-center items-center absolute text-2xl text-gray-200 hover:text-white cursor-pointer h-12 w-12 p-3 rounded-lg left-2 top-2 transition-colors border;
} }
*:focus { *:focus {
@@ -155,7 +135,7 @@ body {
} }
.input-field { .input-field {
@apply border-2 border-(--col4) rounded-md bg-(--col2) p-2 px-4 focus:border-blue-600 transition-colors; @apply border-2 border-(--col4) rounded-md bg-(--col2) py-1 px-2 focus:bg-(--col3) focus:border-(--col6) transition-colors w-full;
} }
.entry-info-item { .entry-info-item {
-48
View File
@@ -1,48 +0,0 @@
import { useEffect, useRef } from 'react'
import BerryNoColor from '../assets/berries/BerryNoColor.png'
export default function RandomBerry () {
const canvasRef = useRef<HTMLCanvasElement>(null)
const imgRef = useRef<HTMLImageElement>(document.createElement('img'))
useEffect(() => {
imgRef.current.src = BerryNoColor.src
const canvas = canvasRef.current
const ctx = canvas?.getContext('2d')
if (!canvas || !ctx) return
canvas.width = 24
canvas.height = 24
let frame: number
const frequency = 5
const update = () => {
const t = (performance.now() / 1000) * frequency
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(imgRef.current, 0, 0, canvas.width, canvas.height)
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
const data = imageData.data
for (let i = 0; i < data.length; i += 4) {
const gray = data[i]
const r = (Math.sin(t) * 0.5 + 0.5) * 255 * (gray / 255)
const g = (Math.sin(t + 2) * 0.5 + 0.5) * 255 * (gray / 255)
const b = (Math.sin(t + 4) * 0.5 + 0.5) * 255 * (gray / 255)
data[i] = r
data[i + 1] = g
data[i + 2] = b
}
ctx.putImageData(imageData, 0, 0)
frame = requestAnimationFrame(update)
}
imgRef.current.onload = () => update()
return () => cancelAnimationFrame(frame)
}, [])
return <canvas ref={canvasRef} style={{ width: 24, height: 24 }} />
}
+10 -6
View File
@@ -43,9 +43,11 @@ export default function Sidebar () {
hidden={platform() != 'macos'} hidden={platform() != 'macos'}
onMouseDown={e => { onMouseDown={e => {
if (e.buttons === 1) { if (e.buttons === 1) {
e.detail === 2 if (e.detail === 2) {
? getCurrentWindow().toggleMaximize() getCurrentWindow().toggleMaximize()
: getCurrentWindow().startDragging() } else {
getCurrentWindow().startDragging()
}
} }
}} }}
></div> ></div>
@@ -62,9 +64,11 @@ export default function Sidebar () {
onMouseDown={e => { onMouseDown={e => {
if (platform() != 'macos') return if (platform() != 'macos') return
if (e.buttons === 1) { if (e.buttons === 1) {
e.detail === 2 if (e.detail === 2) {
? getCurrentWindow().toggleMaximize() getCurrentWindow().toggleMaximize()
: getCurrentWindow().startDragging() } else {
getCurrentWindow().startDragging()
}
} }
}} }}
> >
+4 -9
View File
@@ -3,25 +3,20 @@
import { useGlobal } from '../GlobalProvider' import { useGlobal } from '../GlobalProvider'
export default function VersionChangelog () { export default function VersionChangelog () {
const { const { getVersionInfo, managingVersion, downloadedVersionsConfig } =
getVersionGame, useGlobal()
getVersionInfo,
managingVersion,
downloadedVersionsConfig
} = useGlobal()
if (!managingVersion || !downloadedVersionsConfig) return <></> if (!managingVersion || !downloadedVersionsConfig) return <></>
const versionInfo = getVersionInfo(managingVersion) const versionInfo = getVersionInfo(managingVersion)
const gameInfo = getVersionGame(versionInfo?.game)
return ( return (
<> <>
<p className='text-xl text-center'> <p className='text-xl text-center'>
Viewing changelog for {gameInfo?.name} v{versionInfo?.versionName} Viewing changelog for {versionInfo?.displayName}
</p> </p>
<div className='popup-content text-center p-2'> <div className='popup-content text-center p-2'>
<span <span
className='whitespace-pre-wrap' className='whitespace-pre-wrap select-text'
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: versionInfo?.changelog ? atob(versionInfo.changelog) : '' __html: versionInfo?.changelog ? atob(versionInfo.changelog) : ''
}} }}
+14 -20
View File
@@ -9,7 +9,6 @@ import {
faWarning faWarning
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { format } from 'date-fns'
import { useGlobal } from '../GlobalProvider' import { useGlobal } from '../GlobalProvider'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -17,31 +16,32 @@ import prettyBytes from 'pretty-bytes'
export default function VersionInfo () { export default function VersionInfo () {
const { const {
getVersionGame, getGameInfo,
getVersionInfo, getVersionInfo,
managingVersion, managingVersion,
downloadedVersionsConfig, downloadedVersionsConfig,
viewingInfoFromDownloads, viewingInfoFromDownloads,
setPopupMode setPopupMode
} = useGlobal() } = useGlobal()
if (!managingVersion || !downloadedVersionsConfig) return <></> const [versionSize, setVersionSize] = useState<number>(0)
const versionInfo = getVersionInfo(managingVersion)
const gameInfo = getVersionGame(versionInfo?.game)
const [versionSize, setVersionSize] = useState<number | null>(null)
useEffect(() => { useEffect(() => {
invoke<string>('folder_size', { invoke<string>('folder_size', {
version: managingVersion version: managingVersion
}).then(size => { }).then(size => {
setVersionSize(parseInt(size, 10)) setVersionSize(Number(size))
}) })
}, [managingVersion, setVersionSize]) }, [managingVersion, setVersionSize])
if (!managingVersion || !downloadedVersionsConfig) return <></>
const versionInfo = getVersionInfo(managingVersion)
const gameInfo = getGameInfo(versionInfo?.game)
return ( return (
<> <>
<p className='text-xl text-center'> <p className='text-xl text-center'>
Viewing info for {gameInfo?.name} v{versionInfo?.versionName} Viewing info for {versionInfo?.displayName}
</p> </p>
<div className='popup-content flex flex-col items-center justify-center gap-2 h-full'> <div className='popup-content flex flex-col items-center justify-center gap-2 h-full'>
<div <div
@@ -50,11 +50,8 @@ export default function VersionInfo () {
> >
<p> <p>
Installed{' '} Installed{' '}
{format( {new Intl.DateTimeFormat(undefined).format(
new Date( downloadedVersionsConfig.list[managingVersion] ?? 0
downloadedVersionsConfig.timestamps[managingVersion] ?? 0
),
'MM/dd/yyyy'
)} )}
</p> </p>
</div> </div>
@@ -64,11 +61,8 @@ export default function VersionInfo () {
> >
<p> <p>
Released{' '} Released{' '}
{format( {new Intl.DateTimeFormat(undefined).format(
new Date(
versionInfo?.releaseDate ? versionInfo.releaseDate * 1000 : 0 versionInfo?.releaseDate ? versionInfo.releaseDate * 1000 : 0
),
'MM/dd/yyyy'
)} )}
</p> </p>
</div> </div>
@@ -97,12 +91,12 @@ export default function VersionInfo () {
<FontAwesomeIcon icon={faHardDrive} color='lightgray' /> <FontAwesomeIcon icon={faHardDrive} color='lightgray' />
<p> <p>
Size on disk:{' '} Size on disk:{' '}
{versionSize !== null {versionSize > 0
? prettyBytes(versionSize, { ? prettyBytes(versionSize, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2 maximumFractionDigits: 2
}) })
: 'Loading...'} : 'N/A'}
</p> </p>
</div> </div>
<div className='entry-info-item btntheme2' hidden={!versionInfo}> <div className='entry-info-item btntheme2' hidden={!versionInfo}>
+105
View File
@@ -0,0 +1,105 @@
'use client'
import { invoke } from '@tauri-apps/api/core'
import { useGlobal } from '../GlobalProvider'
import { BaseDirectory, exists, remove } from '@tauri-apps/plugin-fs'
import { writeVersionsConfig } from '../util/BazookaManager'
import { useState } from 'react'
export default function VersionUpdateWarning () {
const [confirmed, setConfirmed] = useState<-1 | 0>(-1)
const {
managingVersion,
setDownloadedVersionsConfig,
setManagingVersion,
setPopupMode,
setSelectedVersionList,
downloadVersions
} = useGlobal()
if (!managingVersion) return <p>Error</p>
return (
<>
<p className='text-xl text-center'>Warning!</p>
<div className='popup-content text-center p-2 relative'>
<p className='mb-2'>
Before proceeding, please note that any modifications to the
installation directory <b>(NOT THE SAVE DATA)</b> will be completely
wiped/reset.
</p>
<p>
If you do not want your installation directory wiped just yet, please
backup the files to another directory. When you click update, it will
be wiped.
</p>
<p className='my-2'>
Updating will have the same effect as clicking the uninstall button
then installing again.
</p>
<p>Revisions are not a frequent thing and rarely ever happen.</p>
<div className='flex flex-row gap-2 absolute bottom-2 left-1/2 -translate-x-1/2 w-max'>
<button
className='button btntheme2'
onClick={async () =>
invoke('open_folder', {
name: managingVersion
})
}
title="Click to browse the game's files."
>
Open Folder / Installation directory
</button>
<button
className='button btntheme2'
onClick={async () => {
if (confirmed == -1) {
setConfirmed(0)
return
}
//change popup to downloads
setManagingVersion(null)
setPopupMode(1)
//uninstall
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = Object.fromEntries(
Object.entries(prev.list).filter(
([k]) => k !== managingVersion
)
)
const updatedConfig = {
...prev,
list: updatedList
}
writeVersionsConfig(updatedConfig)
return updatedConfig
})
if (
await exists('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
//reinstall
setSelectedVersionList([managingVersion])
downloadVersions([managingVersion])
}}
title='Click to update the game'
>
<span className='text-red-500 font-bold underline'>
{confirmed == -1 ? 'Update' : 'Are you sure?'}
</span>
</button>
</div>
</div>
</>
)
}
+287 -43
View File
@@ -2,11 +2,12 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import '../Installs.css' import '../Installs.css'
import { format } from 'date-fns'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { useGlobal } from '../GlobalProvider' import { useGlobal } from '../GlobalProvider'
import { useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import { platform } from '@tauri-apps/plugin-os' import { platform } from '@tauri-apps/plugin-os'
import { faWarning } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
export default function Installs () { export default function Installs () {
const { const {
@@ -19,26 +20,65 @@ export default function Installs () {
normalConfig, normalConfig,
setManagingVersion, setManagingVersion,
getVersionInfo, getVersionInfo,
getVersionGame, getGameInfo,
setSelectedGame setSelectedGame,
serverVersionList
} = useGlobal() } = useGlobal()
const params = useSearchParams() const params = useSearchParams()
const [hoveredIds, setHoveredIds] = useState<string[]>([])
const id = Number(params.get('id') || 0)
const game = serverVersionList?.games.find(g => g.id === id)
const [category, setCategory] = useState<number>(-1)
const [lastId, setLastId] = useState(id)
useEffect(() => { useEffect(() => {
if (!showPopup) return if (!showPopup) return
setSelectedVersionList([]) setSelectedVersionList([])
}, [normalConfig, setSelectedVersionList, showPopup]) }, [normalConfig, setSelectedVersionList, showPopup])
if (!id || !game) return <p>Invalid game</p>
if (lastId !== id) {
setLastId(id)
setCategory(-1)
}
const needsRevisionUpdate = (
lastRevision: number | undefined,
version: string
) => {
if (!lastRevision) return false
return (
lastRevision > 0 &&
(downloadedVersionsConfig == undefined
? 0
: downloadedVersionsConfig?.list[version]) /
1000 <=
lastRevision
)
}
return ( return (
<div className='mx-4 mt-4'> <div className='mx-4 mt-4'>
<div className='flex justify-between items-center mb-4'> <div className='flex justify-between items-center mb-4'>
<p className='text-3xl'>Installs</p> <p className='text-3xl'>Installs</p>
<div className='flex gap-2'>
<button <button
className='button btntheme1 text-3xl' className='button btntheme1'
onClick={() => { onClick={() => {
setSelectedGame(Number(params.get('id') || 0)) setCategory(-1)
}}
title='Click to go up a level.'
hidden={category == -1}
>
Back
</button>
<button
className='button btntheme1'
onClick={() => {
setSelectedGame(id)
setPopupMode(0) setPopupMode(0)
setShowPopup(true) setShowPopup(true)
setFadeOut(false) setFadeOut(false)
@@ -48,6 +88,7 @@ export default function Installs () {
Download versions Download versions
</button> </button>
</div> </div>
</div>
<div className='downloads-container'> <div className='downloads-container'>
<div <div
className={`downloads-scroll ${ className={`downloads-scroll ${
@@ -56,13 +97,101 @@ export default function Installs () {
: 'h-[calc(100vh-84px)]' : 'h-[calc(100vh-84px)]'
}`} }`}
> >
{downloadedVersionsConfig && {category == -1 &&
downloadedVersionsConfig.list.filter(v => { Object.entries(game.categoryNames)
.sort(([a], [b]) => Number(b) - Number(a))
.filter(([key]) => {
const count = Object.keys(
downloadedVersionsConfig?.list ?? {}
).filter(v => {
const info = getVersionInfo(v) const info = getVersionInfo(v)
if (!info) return false if (!info) return false
return info.game === Number(params.get('id') || 0)
if (
platform() === 'linux' &&
info.wine &&
!normalConfig?.settings.useWineOnUnixWhenNeeded
)
return false
return info.game === id && info.category === Number(key)
}).length
return count >= 1
})
.map(([key, value]) => {
return (
<div
key={key}
className={`downloads-entry ${
normalConfig?.settings.useLegacyInteractButtons
? ''
: 'cursor-pointer'
}`}
title={
normalConfig?.settings.useLegacyInteractButtons
? ''
: 'Click to view category'
}
onClick={() => {
if (normalConfig?.settings.useLegacyInteractButtons)
return
setCategory(Number(key))
}}
>
<div className='h-18 w-screen relative'>
<p className='text-2xl'>{value}</p>
<div
className='entry-info-item flex absolute left-0 bottom-0'
title='The amount of versions installed of this game in installed/installable format.'
onClick={e => e.stopPropagation()}
>
<p>
{(() => {
const count =
Object.keys(
downloadedVersionsConfig?.list ?? []
).filter(v => {
const info = getVersionInfo(v)
if (!info) return false
if (
platform() === 'linux' &&
info.wine &&
!normalConfig?.settings
.useWineOnUnixWhenNeeded
)
return false
return (
info.game === id &&
info.category == Number(key)
)
}).length ?? 0
return `${count} install${count === 1 ? '' : 's'}`
})()}
</p>
</div>
<button
className='button absolute right-0 bottom-0'
hidden={
!normalConfig?.settings.useLegacyInteractButtons
}
title='Click to view category'
onClick={() => setCategory(Number(key))}
>
Installs
</button>
</div>
</div>
)
})}
{Object.keys(downloadedVersionsConfig?.list ?? []).filter(v => {
const info = getVersionInfo(v)
if (!info) return false
return info.game === id
}).length != 0 ? ( }).length != 0 ? (
downloadedVersionsConfig.list Object.keys(downloadedVersionsConfig?.list ?? [])
.sort((a, b) => { .sort((a, b) => {
const infoA = getVersionInfo(a) const infoA = getVersionInfo(a)
const infoB = getVersionInfo(b) const infoB = getVersionInfo(b)
@@ -72,60 +201,132 @@ export default function Installs () {
.filter(v => { .filter(v => {
const info = getVersionInfo(v) const info = getVersionInfo(v)
if (!info) return false if (!info) return false
return info.game === Number(params.get('id') || 0) if (
platform() === 'linux' &&
info.wine &&
!normalConfig?.settings.useWineOnUnixWhenNeeded
)
return false
return (
info.game === id &&
(category == -1
? info.category == -1
: info.category == category)
)
}) })
.map((entry, i) => ( .map(entry => (
<div <div
key={entry} key={entry}
className={`downloads-entry ${ className={`downloads-entry ${
normalConfig?.settings.useLegacyInteractButtons normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
? '' ? ''
: 'cursor-pointer' : 'cursor-pointer'
}`} }`}
title={ title={
normalConfig?.settings.useLegacyInteractButtons normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
? '' ? ''
: 'Click to launch game' : 'Click to launch game. Right-click to manage this version install'
} }
onClick={async () => { onClick={async () => {
if (normalConfig?.settings.useLegacyInteractButtons) return if (
normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
)
return
const verInfo = getVersionInfo(entry) const verInfo = getVersionInfo(entry)
if (verInfo == undefined) return if (verInfo == undefined) return
const gameInfo = getGameInfo(verInfo.game)
if (gameInfo == undefined) return
invoke('launch_game', { invoke('launch_game', {
name: verInfo.id, name: verInfo.id,
executable: verInfo.executable executable: verInfo.executable,
displayName: verInfo.displayName,
useWine: !!(
platform() === 'linux' &&
verInfo.wine &&
normalConfig?.settings.useWineOnUnixWhenNeeded
),
wineCommand: normalConfig?.settings.wineOnUnixCommand
}) })
}} }}
onMouseEnter={() => setHoveredIds(prev => [...prev, entry])} onContextMenu={e => {
onMouseLeave={() => e.preventDefault()
setHoveredIds(prev => prev.filter(i => i !== i)) if (
} normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
)
return
setManagingVersion(entry)
setPopupMode(2)
setShowPopup(true)
setFadeOut(false)
}}
> >
<div className='flex flex-col'> <div className='h-18 w-screen relative'>
<p className='text-2xl'> <p className='text-2xl'>
{getVersionGame(getVersionInfo(entry)?.game)?.name} v {getVersionInfo(entry)?.displayName}{' '}
{getVersionInfo(entry)?.versionName}
</p> </p>
<div className='flex gap-2 absolute left-0 bottom-0'>
<div <div
className={`entry-info-item mt-2 ${ className='entry-info-item'
hoveredIds.includes(entry) ? 'btntheme3' : 'btntheme2' title='The date the game was installed.'
}`} onClick={e => e.stopPropagation()}
title='The date the game was installed in MM/dd/yyyy format'
> >
<p> <p>
Installed{' '} Installed{' '}
{format( {new Intl.DateTimeFormat(undefined).format(
new Date(downloadedVersionsConfig.timestamps[entry]), downloadedVersionsConfig?.list[entry]
'MM/dd/yyyy'
)} )}
</p> </p>
</div> </div>
<div
className='entry-info-item'
title='This version is using wine. It cannot be guarenteed to work fully and might not work at all.'
hidden={
!(
platform() === 'linux' &&
getVersionInfo(entry)?.wine
)
}
onClick={e => e.stopPropagation()}
>
<FontAwesomeIcon icon={faWarning} color='#ffc800' />
<p>Uses wine</p>
</div> </div>
<div className='flex flex-row items-center gap-2 mt-auto'> <div
className='entry-info-item'
onClick={e => e.stopPropagation()}
hidden={
!needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
>
<FontAwesomeIcon icon={faWarning} color='#ffc800' />
<p>Needs revision update!</p>
</div>
</div>
<div className='flex gap-2 absolute right-0 bottom-0'>
<button <button
className={`button ${ className='button'
hoveredIds.includes(entry) ? 'btntheme3' : 'btntheme2'
}`}
onClick={e => { onClick={e => {
e.stopPropagation() e.stopPropagation()
setManagingVersion(entry) setManagingVersion(entry)
@@ -133,14 +334,23 @@ export default function Installs () {
setShowPopup(true) setShowPopup(true)
setFadeOut(false) setFadeOut(false)
}} }}
hidden={needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)}
title='Click to view version info' title='Click to view version info'
> >
View Info View Info
</button> </button>
<button <button
className={`button ${ className='button'
hoveredIds.includes(entry) ? 'btntheme3' : 'btntheme2' hidden={
}`} !normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
onClick={e => { onClick={e => {
e.stopPropagation() e.stopPropagation()
setManagingVersion(entry) setManagingVersion(entry)
@@ -153,23 +363,57 @@ export default function Installs () {
Manage Manage
</button> </button>
<button <button
className={`button ${ className='button'
hoveredIds.includes(entry) ? 'btntheme3' : 'btntheme2'
}`}
onClick={e => { onClick={e => {
e.stopPropagation() e.stopPropagation()
const verInfo = getVersionInfo(entry) const verInfo = getVersionInfo(entry)
if (verInfo == undefined) return if (verInfo == undefined) return
const gameInfo = getGameInfo(verInfo.game)
if (gameInfo == undefined) return
invoke('launch_game', { invoke('launch_game', {
name: verInfo.id, name: verInfo.id,
executable: verInfo.executable executable: verInfo.executable,
displayName: verInfo.displayName,
useWine: !!(
platform() === 'linux' &&
verInfo.wine &&
normalConfig?.settings.useWineOnUnixWhenNeeded
),
wineCommand:
normalConfig?.settings.wineOnUnixCommand
}) })
}} }}
hidden={!normalConfig?.settings.useLegacyInteractButtons} hidden={
!normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
title='Click to launch game' title='Click to launch game'
> >
Launch Launch
</button> </button>
<button
className='button'
onClick={e => {
e.stopPropagation()
setManagingVersion(entry)
setPopupMode(5)
setShowPopup(true)
setFadeOut(false)
}}
hidden={
!needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
title='Click to update the game'
>
Update
</button>
</div>
</div> </div>
</div> </div>
)) ))
+307 -210
View File
@@ -1,6 +1,6 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import Sidebar from './componets/Sidebar' import Sidebar from './componets/Sidebar'
import './Globals.css' import './Globals.css'
import { DownloadProgress } from './types/DownloadProgress' import { DownloadProgress } from './types/DownloadProgress'
@@ -45,6 +45,8 @@ import {
requestPermission requestPermission
} from '@tauri-apps/plugin-notification' } from '@tauri-apps/plugin-notification'
import VersionChangelog from './componets/VersionChangelog' import VersionChangelog from './componets/VersionChangelog'
import { BaseDirectory, exists, remove } from '@tauri-apps/plugin-fs'
import VersionUpdateWarning from './componets/VersionUpdateWarning'
const roboto = Roboto({ const roboto = Roboto({
subsets: ['latin'] subsets: ['latin']
@@ -80,34 +82,134 @@ export default function RootLayout ({
useState<boolean>(false) useState<boolean>(false)
const [selectedGame, setSelectedGame] = useState<number | null>(null) const [selectedGame, setSelectedGame] = useState<number | null>(null)
function handleOverlayClick (e: React.MouseEvent<HTMLDivElement>) { const pathname = usePathname()
if (e.target === e.currentTarget) { const revisionCheck = useRef(false)
if (viewingInfoFromDownloads) {
setPopupMode(0) function getSpecialVersionsList (game?: number): GameVersion[] {
setViewingInfoFromDownloads(false) if (!normalConfig || !serverVersionList) return []
setManagingVersion(null)
setSelectedGame(null) return serverVersionList.versions
.filter(
v => !Object.keys(downloadedVersionsConfig?.list ?? []).includes(v.id)
)
.filter(v => {
if (
platform() === 'linux' &&
v.wine &&
!normalConfig.settings.useWineOnUnixWhenNeeded
)
return false
if (game && v.game != game) return false
if (downloadProgress.length != 0) {
return !downloadProgress.some(d => d.version === v.id)
} }
return true
})
.sort((a, b) => {
if (b.game !== a.game) return a.game - b.game
return 0
})
}
const getVersionInfo = useCallback(
(id: string | undefined): GameVersion | undefined => {
if (!id) return undefined
return serverVersionList?.versions.find(v => v.id === id)
},
[serverVersionList]
)
const getGameInfo = useCallback(
(game: number | undefined): Game | undefined => {
if (!game) return undefined
return serverVersionList?.games.find(g => g.id === game)
},
[serverVersionList]
)
function getListOfGames (): Game[] {
if (!downloadedVersionsConfig?.list) return []
const gamesMap = new Map<number, Game>()
Object.keys(downloadedVersionsConfig.list).forEach(i => {
const version = getVersionInfo(i)
if (!version) return
const game = getGameInfo(version.game)
if (!game) return
gamesMap.set(game.id, game)
})
return Array.from(gamesMap.values())
}
function getVersionsAmountData (gameId: number): {
installed: number
total: number
} | null {
if (!downloadedVersionsConfig || !serverVersionList) return null
const allowWine =
platform() !== 'linux' || normalConfig?.settings.useWineOnUnixWhenNeeded
const installed = Object.keys(downloadedVersionsConfig.list).filter(v => {
const info = getVersionInfo(v)
if (!info) return false
if (info.wine && !allowWine) return false
return getGameInfo(info.game)?.id === gameId
}).length
const total = serverVersionList.versions.filter(v => {
if (!v) return false
if (v.wine && !allowWine) return false
return getGameInfo(v.game)?.id === gameId
}).length
return { installed, total }
}
function formatEtaSmart (seconds: number) {
if (seconds < 60) return `${Math.floor(seconds)}s`
if (seconds < 3600)
return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`
if (seconds < 86400) {
const h = Math.floor(seconds / 3600)
const m = Math.floor((seconds % 3600) / 60)
return `${h}h ${m}m`
}
const d = Math.floor(seconds / 86400)
const h = Math.floor((seconds % 86400) / 3600)
return `${d}d ${h}h`
}
function closePopup () {
if (popupMode == 0 && selectedGame && pathname === '/') {
setSelectedGame(null)
setSelectedVersionList([])
} else if (viewingInfoFromDownloads) {
setViewingInfoFromDownloads(false)
setPopupMode(0)
} else if (popupMode == 4) {
setPopupMode(3)
} else {
setFadeOut(true) setFadeOut(true)
setTimeout(() => setShowPopup(false), 200) setTimeout(() => setShowPopup(false), 200)
} }
} }
const pathname = usePathname()
useEffect(() => { useEffect(() => {
let unlistenProgress: (() => void) | null = null let unlistenProgress: (() => void) | null = null
let unlistenUninstalled: (() => void) | null = null
listen<string>('download-progress', event => { listen<string>('download-progress', event => {
const [versionName, progStr, totalSizeStr, speedStr, etaSecsStr] = const [displayName, progStr, totalSizeStr, speedStr, etaSecsStr] =
event.payload.split(':') event.payload.split(':')
const prog = Number(progStr) const prog = Number(progStr)
const progBytes = Number(totalSizeStr) const progBytes = Number(totalSizeStr)
const speed = Number(speedStr) const speed = Number(speedStr)
const etaSecs = Number(etaSecsStr) const etaSecs = Number(etaSecsStr)
setDownloadProgress(prev => { setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName) const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev if (i === -1) return prev
const copy = [...prev] const copy = [...prev]
copy[i] = { copy[i] = {
@@ -122,9 +224,9 @@ export default function RootLayout ({
}).then(f => (unlistenProgress = f)) }).then(f => (unlistenProgress = f))
listen<string>('download-hash-checking', event => { listen<string>('download-hash-checking', event => {
const versionName = event.payload const displayName = event.payload
setDownloadProgress(prev => { setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName) const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev if (i === -1) return prev
const copy = [...prev] const copy = [...prev]
copy[i] = { ...copy[i], hash_checking: true } copy[i] = { ...copy[i], hash_checking: true }
@@ -133,9 +235,9 @@ export default function RootLayout ({
}).then(f => (unlistenProgress = f)) }).then(f => (unlistenProgress = f))
listen<string>('download-finishing', event => { listen<string>('download-finishing', event => {
const versionName = event.payload const displayName = event.payload
setDownloadProgress(prev => { setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName) const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev if (i === -1) return prev
const copy = [...prev] const copy = [...prev]
copy[i] = { ...copy[i], hash_checking: false, finishing: true } copy[i] = { ...copy[i], hash_checking: false, finishing: true }
@@ -143,30 +245,8 @@ export default function RootLayout ({
}) })
}).then(f => (unlistenProgress = f)) }).then(f => (unlistenProgress = f))
listen<string>('version-uninstalled', event => {
const versionName = event.payload
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = prev.list.filter(v => v !== versionName)
const updatedTimestamps = Object.fromEntries(
Object.entries(prev.timestamps).filter(([k]) => k !== versionName)
)
const updatedConfig = {
...prev,
list: updatedList,
timestamps: updatedTimestamps
}
writeVersionsConfig(updatedConfig)
setManagingVersion(null)
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
return updatedConfig
})
}).then(f => (unlistenUninstalled = f))
return () => { return () => {
unlistenProgress?.() unlistenProgress?.()
unlistenUninstalled?.()
} }
}, []) }, [])
@@ -219,52 +299,9 @@ export default function RootLayout ({
return () => document.removeEventListener('contextmenu', handler) return () => document.removeEventListener('contextmenu', handler)
}, []) }, [])
function getSpecialVersionsList (game?: number): GameVersion[] { const downloadVersions = useCallback(
if (!normalConfig || !serverVersionList) return [] async (list: string[]): Promise<void> => {
if (list.length === 0) return
return serverVersionList.versions
.filter(v => !downloadedVersionsConfig?.list.includes(v.id))
.filter(v => {
if (game && v.game != game) return false
if (downloadProgress.length != 0) {
return !downloadProgress.some(d => d.version === v.id)
}
return true
})
.sort((a, b) => {
if (b.game !== a.game) return a.game - b.game
return 0
})
}
function getVersionInfo (id: string | undefined): GameVersion | undefined {
if (!id) return undefined
return serverVersionList?.versions.find(v => v.id === id)
}
function getVersionGame (game: number | undefined): Game | undefined {
if (!game) return undefined
return serverVersionList?.games.find(g => g.id === game)
}
function getListOfGames (): Game[] {
if (!downloadedVersionsConfig?.list) return []
const gamesMap = new Map<number, Game>()
downloadedVersionsConfig.list.forEach(i => {
const version = getVersionInfo(i)
if (!version) return
const game = getVersionGame(version.game)
if (!game) return
gamesMap.set(game.id, game)
})
return Array.from(gamesMap.values())
}
async function downloadVersions (): Promise<void> {
const list = selectedVersionList
setSelectedVersionList([]) setSelectedVersionList([])
const newDownloads = list.map( const newDownloads = list.map(
@@ -280,42 +317,54 @@ export default function RootLayout ({
setDownloadProgress(prev => setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version) prev.filter(d => d.version !== download.version)
) )
return continue
} }
const gameInfo = getVersionGame(info.game)
const gameInfo = getGameInfo(info.game)
if (!gameInfo) { if (!gameInfo) {
setDownloadProgress(prev => setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version) prev.filter(d => d.version !== download.version)
) )
return continue
} }
setDownloadProgress(prev => setDownloadProgress(prev =>
prev.map(d => prev.map(d =>
d.version === download.version ? { ...d, queued: false } : d d.version === download.version ? { ...d, queued: false } : d
) )
) )
try {
await axios.get(
'https://games.lncvrt.xyz/api/launcher/download?id=' + info.id
)
} catch {}
const res = await invoke<string>('download', { const res = await invoke<string>('download', {
url: info.downloadUrl, url: info.downloadUrl,
name: info.id, name: info.id,
executable: info.executable, executable: info.executable,
hash: info.sha512sum hash: info.sha512sum
}) })
if (res == '1') {
if (res === '1') {
setDownloadProgress(prev => setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version) prev.filter(d => d.version !== download.version)
) )
let data = downloadedVersionsConfig setDownloadedVersionsConfig(prev => {
if (!data) { if (!prev) return prev
setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version) const updated = {
) ...prev,
return list: {
...prev.list,
[download.version]: Date.now()
} }
const date = Date.now() }
data.list = [...data.list, download.version]
data.timestamps = { ...data.timestamps, [download.version]: date } writeVersionsConfig(updated)
setDownloadedVersionsConfig(data) return updated
writeVersionsConfig(data) })
} else { } else {
setDownloadProgress(prev => setDownloadProgress(prev =>
prev.map(d => prev.map(d =>
@@ -327,45 +376,47 @@ export default function RootLayout ({
if (normalConfig?.settings.allowNotifications) if (normalConfig?.settings.allowNotifications)
await notifyUser( await notifyUser(
'Download Failed', 'Download Failed',
`The download for version ${gameInfo.name} v${info.versionName} has failed.` `The download for version ${info.displayName} has failed.`
) )
} }
} }
if (normalConfig?.settings.allowNotifications) if (normalConfig?.settings.allowNotifications)
await notifyUser('Downloads Finished', 'All downloads have finished.') await notifyUser('Downloads Finished', 'All downloads have finished.')
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
},
[getGameInfo, getVersionInfo, normalConfig]
)
useEffect(() => {
if (revisionCheck.current) return
if (!serverVersionList || !downloadedVersionsConfig) return
revisionCheck.current = true
;(async () => {
for (const [key, value] of Object.entries(
downloadedVersionsConfig.list
)) {
const verInfo = serverVersionList.versions.find(item => item.id === key)
if (
!verInfo ||
(verInfo.lastRevision > 0 && value / 1000 <= verInfo.lastRevision)
) {
if (
await exists('game/' + key + '/' + verInfo?.executable, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + key + '/' + verInfo?.executable, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
} }
function getVersionsAmountData (gameId: number): {
installed: number
total: number
} | null {
if (!downloadedVersionsConfig || !serverVersionList) return null
const installed = downloadedVersionsConfig.list.filter(
v => getVersionGame(getVersionInfo(v)?.game)?.id === gameId
).length
const total = serverVersionList.versions.filter(
v => getVersionGame(v?.game)?.id === gameId
).length
return { installed, total }
}
function formatEtaSmart (seconds: number) {
if (seconds < 60) return `${Math.floor(seconds)}s`
if (seconds < 3600)
return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`
if (seconds < 86400) {
const h = Math.floor(seconds / 3600)
const m = Math.floor((seconds % 3600) / 60)
return `${h}h ${m}m`
}
const d = Math.floor(seconds / 86400)
const h = Math.floor((seconds % 86400) / 3600)
return `${d}d ${h}h`
} }
})()
}, [serverVersionList, downloadedVersionsConfig, downloadVersions])
return ( return (
<> <>
@@ -375,13 +426,9 @@ export default function RootLayout ({
normalConfig?.settings.theme === 1 normalConfig?.settings.theme === 1
? 'red-theme' ? 'red-theme'
: normalConfig?.settings.theme === 2 : normalConfig?.settings.theme === 2
? 'green-theme'
: normalConfig?.settings.theme === 3
? 'blue-theme' ? 'blue-theme'
: normalConfig?.settings.theme === 4 : normalConfig?.settings.theme === 3
? 'purple-theme' ? 'purple-theme'
: normalConfig?.settings.theme === 5
? 'mint-theme'
: 'dark-theme' : 'dark-theme'
} }
> >
@@ -427,31 +474,19 @@ export default function RootLayout ({
managingVersion, managingVersion,
setManagingVersion, setManagingVersion,
getVersionInfo, getVersionInfo,
getVersionGame, getGameInfo,
getListOfGames, getListOfGames,
setSelectedGame, setSelectedGame,
getVersionsAmountData, getVersionsAmountData,
viewingInfoFromDownloads, viewingInfoFromDownloads,
version version,
downloadVersions
}} }}
> >
<div <div
tabIndex={0} tabIndex={0}
onKeyDown={e => { onKeyDown={e => {
if (showPopup && e.key === 'Escape') { if (showPopup && e.key === 'Escape') closePopup()
if (popupMode == 0 && selectedGame && pathname === '/') {
setSelectedGame(null)
setSelectedVersionList([])
} else if (viewingInfoFromDownloads) {
setViewingInfoFromDownloads(false)
setPopupMode(0)
} else if (popupMode == 4) {
setPopupMode(3)
} else {
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
}
}
}} }}
> >
<Sidebar /> <Sidebar />
@@ -467,29 +502,23 @@ export default function RootLayout ({
{showPopup && ( {showPopup && (
<div <div
className={`popup-overlay ${fadeOut ? 'fade-out' : ''}`} className={`popup-overlay ${fadeOut ? 'fade-out' : ''}`}
onClick={handleOverlayClick} onClick={(e: React.MouseEvent<HTMLDivElement>) => {
> if (e.target === e.currentTarget) {
<div className='popup-box'> if (viewingInfoFromDownloads) {
<button
className='close-button'
onClick={() => {
if (
popupMode == 0 &&
selectedGame &&
pathname === '/'
) {
setSelectedGame(null)
setSelectedVersionList([])
} else if (viewingInfoFromDownloads) {
setViewingInfoFromDownloads(false)
setPopupMode(0) setPopupMode(0)
} else if (popupMode == 4) { setViewingInfoFromDownloads(false)
setPopupMode(3) setManagingVersion(null)
} else { setSelectedGame(null)
}
setFadeOut(true) setFadeOut(true)
setTimeout(() => setShowPopup(false), 200) setTimeout(() => setShowPopup(false), 200)
} }
}} }}
>
<div className='popup-box'>
<button
className='close-button btntheme1'
onClick={() => closePopup()}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={ icon={
@@ -516,16 +545,15 @@ export default function RootLayout ({
<p <p
className={`text-2xl truncate ${ className={`text-2xl truncate ${
selectedVersionList.includes(v.id) selectedVersionList.includes(v.id)
? 'max-w-80.5' ? 'max-w-84.5'
: 'max-w-87.5' : 'max-w-91.5'
}`} }`}
> >
{getVersionGame(v.game)?.name} v {v.displayName}
{v.versionName}
</p> </p>
</div> </div>
<button <button
className='button btntheme3 right-21.5 bottom-1.25' className='button btntheme3 right-20.75 bottom-1.75'
onClick={() => { onClick={() => {
setSelectedVersionList(prev => setSelectedVersionList(prev =>
prev.includes(v.id) prev.includes(v.id)
@@ -551,7 +579,7 @@ export default function RootLayout ({
)} )}
</button> </button>
<button <button
className='button btntheme3 right-1 bottom-1.25' className='button btntheme3 right-1.5 bottom-1.75'
onClick={() => { onClick={() => {
setManagingVersion(v.id) setManagingVersion(v.id)
setViewingInfoFromDownloads(true) setViewingInfoFromDownloads(true)
@@ -572,7 +600,13 @@ export default function RootLayout ({
Select a game to download Select a game to download
</p> </p>
<div className='popup-content'> <div className='popup-content'>
{serverVersionList?.games.map((v, i) => ( {serverVersionList?.games
.filter(v => {
const data = getVersionsAmountData(v.id)
if (!data) return false
if (data.total > 0) return true
})
.map((v, i) => (
<div key={i} className='popup-entry'> <div key={i} className='popup-entry'>
<p className='text-2xl'>{v.name}</p> <p className='text-2xl'>{v.name}</p>
<div className='flex gap-2'> <div className='flex gap-2'>
@@ -582,7 +616,9 @@ export default function RootLayout ({
> >
<p> <p>
{(() => { {(() => {
const data = getVersionsAmountData(v.id) const data = getVersionsAmountData(
v.id
)
if (!data) return 'N/A' if (!data) return 'N/A'
return `${data.installed}/${data.total}` return `${data.installed}/${data.total}`
})()}{' '} })()}{' '}
@@ -611,9 +647,13 @@ export default function RootLayout ({
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={ icon={
v.verified ? faShieldHalved : faWarning v.verified
? faShieldHalved
: faWarning
}
color={
v.verified ? '#19c84b' : '#ffc800'
} }
color={v.verified ? '#19c84b' : '#ffc800'}
/> />
<p> <p>
{v.verified ? 'Verified' : 'Unverified'} {v.verified ? 'Verified' : 'Unverified'}
@@ -653,23 +693,13 @@ export default function RootLayout ({
<> <>
<p className='text-xl text-center'>Downloads</p> <p className='text-xl text-center'>Downloads</p>
<div className='popup-content'> <div className='popup-content'>
{downloadProgress.length === 0 ? ( {downloadProgress.map((v, i) => (
<p className='text-center mt-6'>
No more downloads!
</p>
) : (
downloadProgress.map((v, i) => (
<div <div
key={i} key={i}
className='popup-entry flex flex-col justify-between' className='popup-entry flex flex-col justify-between'
> >
<p className='text-2xl text-center'> <p className='text-2xl text-center'>
{ {getVersionInfo(v.version)?.displayName}
getVersionGame(
getVersionInfo(v.version)?.game
)?.name
}{' '}
v{getVersionInfo(v.version)?.versionName}
</p> </p>
<div className='mt-6.25 flex items-center justify-between'> <div className='mt-6.25 flex items-center justify-between'>
{v.failed ? ( {v.failed ? (
@@ -719,15 +749,14 @@ export default function RootLayout ({
})}{' '} })}{' '}
of{' '} of{' '}
{prettyBytes( {prettyBytes(
getVersionInfo(v.version)?.size ?? getVersionInfo(v.version)?.size ?? 0,
0,
{ {
minimumFractionDigits: 1, minimumFractionDigits: 1,
maximumFractionDigits: 1 maximumFractionDigits: 1
} }
)}{' '} )}{' '}
(ETA: {formatEtaSmart(v.etaSecs)}{' '} (ETA: {formatEtaSmart(v.etaSecs)} &bull;
&bull; Speed:{' '} Speed:{' '}
{prettyBytes(v.speed, { {prettyBytes(v.speed, {
minimumFractionDigits: 1, minimumFractionDigits: 1,
maximumFractionDigits: 1 maximumFractionDigits: 1
@@ -742,8 +771,7 @@ export default function RootLayout ({
)} )}
</div> </div>
</div> </div>
)) ))}
)}
</div> </div>
</> </>
) : popupMode === 2 ? ( ) : popupMode === 2 ? (
@@ -751,26 +779,86 @@ export default function RootLayout ({
<> <>
<p className='text-xl text-center'> <p className='text-xl text-center'>
Manage{' '} Manage{' '}
{ {getVersionInfo(managingVersion)?.displayName}
getVersionGame(
getVersionInfo(managingVersion)?.game
)?.name
}{' '}
v{getVersionInfo(managingVersion)?.versionName}
</p> </p>
<div className='popup-content flex flex-col items-center justify-center gap-2 h-full'> <div className='popup-content flex flex-col items-center justify-center gap-2 h-full'>
<button <button
className='button btntheme2' className='button btntheme2'
disabled={downloadProgress.length != 0} disabled={downloadProgress.length != 0}
onClick={() => onClick={async () => {
invoke('uninstall_version', { closePopup()
name: managingVersion
}) setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = Object.fromEntries(
Object.entries(prev.list).filter(
([k]) => k !== managingVersion
)
)
const updatedConfig = {
...prev,
list: updatedList
} }
writeVersionsConfig(updatedConfig)
return updatedConfig
})
if (
await exists('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
}}
title='Click to uninstall this game. This will NOT remove any progress or any save files.' title='Click to uninstall this game. This will NOT remove any progress or any save files.'
> >
Uninstall Uninstall
</button> </button>
<button
className='button btntheme2'
disabled={downloadProgress.length != 0}
onClick={async () => {
//change popup to downloads
setManagingVersion(null)
setPopupMode(1)
//uninstall
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = Object.fromEntries(
Object.entries(prev.list).filter(
([k]) => k !== managingVersion
)
)
const updatedConfig = {
...prev,
list: updatedList
}
writeVersionsConfig(updatedConfig)
return updatedConfig
})
if (
await exists('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
//reinstall
setSelectedVersionList([managingVersion])
downloadVersions([managingVersion])
}}
title="Click to reinstall this game. This will NOT remove any progress or any save files. This WILL uninstall any modifications to the game's executable files."
>
Reinstall
</button>
<button <button
className='button btntheme2' className='button btntheme2'
onClick={async () => onClick={async () =>
@@ -805,6 +893,14 @@ export default function RootLayout ({
No version selected No version selected
</p> </p>
) )
) : popupMode === 5 ? (
managingVersion && downloadedVersionsConfig ? (
<VersionUpdateWarning />
) : (
<p className='text-xl text-center'>
No version selected
</p>
)
) : null} ) : null}
{popupMode == 0 && {popupMode == 0 &&
selectedGame && selectedGame &&
@@ -815,7 +911,8 @@ export default function RootLayout ({
onClick={() => { onClick={() => {
setFadeOut(true) setFadeOut(true)
setTimeout(() => setShowPopup(false), 200) setTimeout(() => setShowPopup(false), 200)
downloadVersions() if (downloadedVersionsConfig)
downloadVersions(selectedVersionList)
}} }}
disabled={downloadProgress.length != 0} disabled={downloadProgress.length != 0}
title={ title={
@@ -825,7 +922,7 @@ export default function RootLayout ({
selectedVersionList.length selectedVersionList.length
} version${ } version${
selectedVersionList.length == 1 ? '' : 's' selectedVersionList.length == 1 ? '' : 's'
} of ${getVersionGame(selectedGame)?.name}` } of ${getGameInfo(selectedGame)?.name}`
} }
> >
Download {selectedVersionList.length} version Download {selectedVersionList.length} version
+17 -28
View File
@@ -1,6 +1,6 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useEffect } from 'react'
import './Installs.css' import './Installs.css'
import { useGlobal } from './GlobalProvider' import { useGlobal } from './GlobalProvider'
import Link from 'next/link' import Link from 'next/link'
@@ -28,7 +28,6 @@ export default function Installs () {
} = useGlobal() } = useGlobal()
const router = useRouter() const router = useRouter()
const [hoveredIds, setHoveredIds] = useState<number[]>([])
useEffect(() => { useEffect(() => {
if (!showPopup) return if (!showPopup) return
@@ -40,7 +39,7 @@ export default function Installs () {
<div className='flex justify-between items-center mb-4'> <div className='flex justify-between items-center mb-4'>
<p className='text-3xl'>Games</p> <p className='text-3xl'>Games</p>
<button <button
className='button btntheme1 text-3xl' className='button btntheme1'
onClick={() => { onClick={() => {
setSelectedGame(null) setSelectedGame(null)
setPopupMode(0) setPopupMode(0)
@@ -60,7 +59,8 @@ export default function Installs () {
: 'h-[calc(100vh-84px)]' : 'h-[calc(100vh-84px)]'
}`} }`}
> >
{downloadedVersionsConfig && downloadedVersionsConfig.list.length ? ( {downloadedVersionsConfig &&
Object.keys(downloadedVersionsConfig.list).length ? (
getListOfGames() getListOfGames()
.sort((a, b) => { .sort((a, b) => {
return a.id - b.id return a.id - b.id
@@ -82,19 +82,15 @@ export default function Installs () {
if (normalConfig?.settings.useLegacyInteractButtons) return if (normalConfig?.settings.useLegacyInteractButtons) return
router.push('/game?id=' + i.id) router.push('/game?id=' + i.id)
}} }}
onMouseEnter={() => setHoveredIds(prev => [...prev, i.id])}
onMouseLeave={() =>
setHoveredIds(prev => prev.filter(e => e !== i.id))
}
> >
<div className='flex flex-col'> <div className='h-18 w-screen relative'>
<p className='text-2xl'>{i.name}</p> <p className='text-2xl'>{i.name}</p>
<div className='flex gap-2 mt-2'>
<div className='flex gap-2 absolute left-0 bottom-0'>
<div <div
className={`entry-info-item ${ className='entry-info-item'
hoveredIds.includes(i.id) ? 'btntheme3' : 'btntheme2'
}`}
title='The amount of versions installed of this game in installed/installable format.' title='The amount of versions installed of this game in installed/installable format.'
onClick={e => e.stopPropagation()}
> >
<p> <p>
{(() => { {(() => {
@@ -106,25 +102,23 @@ export default function Installs () {
</p> </p>
</div> </div>
<div <div
className={`entry-info-item ${ className='entry-info-item'
hoveredIds.includes(i.id) ? 'btntheme3' : 'btntheme2'
}`}
hidden={!i.official} hidden={!i.official}
title='This game is official.' title='This game is official.'
onClick={e => e.stopPropagation()}
> >
<FontAwesomeIcon icon={faCheck} color='#19c84b' /> <FontAwesomeIcon icon={faCheck} color='#19c84b' />
<p>Official</p> <p>Official</p>
</div> </div>
<div <div
className={`entry-info-item ${ className='entry-info-item'
hoveredIds.includes(i.id) ? 'btntheme3' : 'btntheme2'
}`}
hidden={i.official} hidden={i.official}
title={ title={
i.verified i.verified
? 'This game is verified to be safe' ? 'This game is verified to be safe'
: 'This game is not verified to be save. Proceed with caution.' : 'This game is not verified to be save. Proceed with caution.'
} }
onClick={e => e.stopPropagation()}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={i.verified ? faShieldHalved : faWarning} icon={i.verified ? faShieldHalved : faWarning}
@@ -133,17 +127,12 @@ export default function Installs () {
<p>{i.verified ? 'Verified' : 'Unverified'}</p> <p>{i.verified ? 'Verified' : 'Unverified'}</p>
</div> </div>
</div> </div>
</div>
<div <Link
className='flex flex-row items-center gap-2 mt-auto' className='button absolute right-0 bottom-0'
href={'/game?id=' + i.id}
hidden={!normalConfig?.settings.useLegacyInteractButtons} hidden={!normalConfig?.settings.useLegacyInteractButtons}
title='Click to view game installs' title='Click to view game installs'
>
<Link
className={`button ${
hoveredIds.includes(i.id) ? 'btntheme3' : 'btntheme2'
}`}
href={'/game?id=' + i.id}
> >
Installs Installs
</Link> </Link>
+70 -22
View File
@@ -5,6 +5,7 @@ import { Setting } from '../componets/Setting'
import { writeNormalConfig } from '../util/BazookaManager' import { writeNormalConfig } from '../util/BazookaManager'
import { useGlobal } from '../GlobalProvider' import { useGlobal } from '../GlobalProvider'
import { copyToClipboard } from '../util/Clipboard' import { copyToClipboard } from '../util/Clipboard'
import { platform } from '@tauri-apps/plugin-os'
export default function Settings () { export default function Settings () {
const [allowNotifications, setAllowNotifications] = useState(false) const [allowNotifications, setAllowNotifications] = useState(false)
@@ -12,6 +13,8 @@ export default function Settings () {
useState(false) useState(false)
const [useLegacyInteractButtons, setUseLegacyInteractButtons] = const [useLegacyInteractButtons, setUseLegacyInteractButtons] =
useState(false) useState(false)
const [useWineOnUnixWhenNeeded, setUseWineOnUnixWhenNeeded] = useState(false)
const [wineOnUnixCommand, setWineOnUnixCommand] = useState('wine %path%')
const [theme, setTheme] = useState(0) const [theme, setTheme] = useState(0)
const [loaded, setLoaded] = useState(false) const [loaded, setLoaded] = useState(false)
@@ -27,6 +30,10 @@ export default function Settings () {
setUseLegacyInteractButtons( setUseLegacyInteractButtons(
normalConfig.settings.useLegacyInteractButtons normalConfig.settings.useLegacyInteractButtons
) )
setUseWineOnUnixWhenNeeded(
normalConfig.settings.useWineOnUnixWhenNeeded
)
setWineOnUnixCommand(normalConfig.settings.wineOnUnixCommand)
setTheme(normalConfig.settings.theme) setTheme(normalConfig.settings.theme)
setLoaded(true) setLoaded(true)
break break
@@ -43,7 +50,7 @@ export default function Settings () {
label='Allow sending notifications' label='Allow sending notifications'
value={allowNotifications} value={allowNotifications}
onChange={async () => { onChange={async () => {
while (normalConfig != null) { if (!normalConfig) return
setAllowNotifications(!allowNotifications) setAllowNotifications(!allowNotifications)
setNormalConfig({ setNormalConfig({
...normalConfig, ...normalConfig,
@@ -52,15 +59,13 @@ export default function Settings () {
allowNotifications: !allowNotifications allowNotifications: !allowNotifications
} }
}) })
writeNormalConfig({ await writeNormalConfig({
...normalConfig, ...normalConfig,
settings: { settings: {
...normalConfig.settings, ...normalConfig.settings,
allowNotifications: !allowNotifications allowNotifications: !allowNotifications
} }
}) })
break
}
}} }}
title='This setting does as you expect, allow the launcher to send notifications for when stuff like downloading is done.' title='This setting does as you expect, allow the launcher to send notifications for when stuff like downloading is done.'
/> />
@@ -68,7 +73,7 @@ export default function Settings () {
label='Always show games in sidebar' label='Always show games in sidebar'
value={alwaysShowGamesInSidebar} value={alwaysShowGamesInSidebar}
onChange={async () => { onChange={async () => {
while (normalConfig != null) { if (!normalConfig) return
setAlwaysShowGamesInSidebar(!alwaysShowGamesInSidebar) setAlwaysShowGamesInSidebar(!alwaysShowGamesInSidebar)
setNormalConfig({ setNormalConfig({
...normalConfig, ...normalConfig,
@@ -77,23 +82,21 @@ export default function Settings () {
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
} }
}) })
writeNormalConfig({ await writeNormalConfig({
...normalConfig, ...normalConfig,
settings: { settings: {
...normalConfig.settings, ...normalConfig.settings,
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
} }
}) })
break
}
}} }}
title="This setting will make it so when you are on a page like this, the games won't disappear." title="This setting will make it so when you are on a page like this, the games won't disappear."
/> />
<Setting <Setting
label='Show Installs/Launch Buttons' label='Show Installs/Launch/Manage Buttons'
value={useLegacyInteractButtons} value={useLegacyInteractButtons}
onChange={async () => { onChange={async () => {
while (normalConfig != null) { if (!normalConfig) return
setUseLegacyInteractButtons(!useLegacyInteractButtons) setUseLegacyInteractButtons(!useLegacyInteractButtons)
setNormalConfig({ setNormalConfig({
...normalConfig, ...normalConfig,
@@ -102,26 +105,75 @@ export default function Settings () {
useLegacyInteractButtons: !useLegacyInteractButtons useLegacyInteractButtons: !useLegacyInteractButtons
} }
}) })
writeNormalConfig({ await writeNormalConfig({
...normalConfig, ...normalConfig,
settings: { settings: {
...normalConfig.settings, ...normalConfig.settings,
useLegacyInteractButtons: !useLegacyInteractButtons useLegacyInteractButtons: !useLegacyInteractButtons
} }
}) })
break
}
}} }}
title='Enable the legacy method of using the installs/launch buttons. In the future this setting may be removed so try and get used to the new method.' title='Enable the legacy method of using the installs/launch/manage buttons. In the future this setting may be removed so try and get used to the new method.'
/> />
<Setting
label='Use wine when needed to launch games'
value={useWineOnUnixWhenNeeded}
onChange={async () => {
if (!normalConfig) return
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
setNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
useWineOnUnixWhenNeeded: !useWineOnUnixWhenNeeded
}
})
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
useWineOnUnixWhenNeeded: !useWineOnUnixWhenNeeded
}
})
}}
className={platform() == 'linux' ? '' : 'hidden'}
/>
<p hidden={!(platform() == 'linux' && useWineOnUnixWhenNeeded)}>
Wine Command:
</p>
<input
type='text'
value={wineOnUnixCommand}
onChange={async e => {
if (!normalConfig) return
setWineOnUnixCommand(e.target.value)
setNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
wineOnUnixCommand: e.target.value
}
})
await writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
wineOnUnixCommand: e.target.value
}
})
}}
className={`input-field my-1 ${
platform() == 'linux' && useWineOnUnixWhenNeeded ? '' : 'hidden'
}`}
></input>
<div title='The theme you want the launcher to use.'> <div title='The theme you want the launcher to use.'>
<label className='text-lg'>Theme:</label> <label className='text-lg'>Theme:</label>
<select <select
className='ml-2 bg-(--col2) border border-(--col4) rounded-md' className='ml-2 bg-(--col2) border border-(--col4) rounded-md'
value={theme} value={theme}
onChange={async e => { onChange={async e => {
if (!normalConfig) return
const newTheme = parseInt(e.target.value) const newTheme = parseInt(e.target.value)
while (normalConfig != null) {
setTheme(newTheme) setTheme(newTheme)
setNormalConfig({ setNormalConfig({
...normalConfig, ...normalConfig,
@@ -130,23 +182,19 @@ export default function Settings () {
theme: newTheme theme: newTheme
} }
}) })
writeNormalConfig({ await writeNormalConfig({
...normalConfig, ...normalConfig,
settings: { settings: {
...normalConfig.settings, ...normalConfig.settings,
theme: newTheme theme: newTheme
} }
}) })
break
}
}} }}
> >
<option value={0}>Dark (default)</option> <option value={0}>Dark (default)</option>
<option value={1}>Red</option> <option value={1}>Red</option>
<option value={2}>Green</option> <option value={2}>Blue</option>
<option value={3}>Blue</option> <option value={3}>Purple</option>
<option value={4}>Purple</option>
<option value={5}>Mint</option>
</select> </select>
</div> </div>
</div> </div>
+1
View File
@@ -4,4 +4,5 @@ export interface Game {
official: boolean official: boolean
verified: boolean verified: boolean
developer: string | null developer: string | null
categoryNames: Record<string, string>
} }
+4 -1
View File
@@ -1,6 +1,6 @@
export interface GameVersion { export interface GameVersion {
id: string id: string
versionName: string displayName: string
releaseDate: number releaseDate: number
game: number game: number
downloadUrl: string downloadUrl: string
@@ -9,4 +9,7 @@ export interface GameVersion {
size: number size: number
place: number place: number
changelog: string changelog: string
wine: number | undefined
category: number
lastRevision: number
} }
+2
View File
@@ -3,6 +3,8 @@ export class SettingsType {
public allowNotifications: boolean = true, public allowNotifications: boolean = true,
public alwaysShowGamesInSidebar: boolean = true, public alwaysShowGamesInSidebar: boolean = true,
public useLegacyInteractButtons: boolean = false, public useLegacyInteractButtons: boolean = false,
public useWineOnUnixWhenNeeded: boolean = false,
public wineOnUnixCommand: string = 'wine %path%',
public theme: number = 0 public theme: number = 0
) {} ) {}
} }
+4 -7
View File
@@ -1,20 +1,17 @@
type VersionsConfigData = { export type VersionsConfigData = {
version: string version: string
list: string[] list: Record<string, number>
timestamps: Record<string, number>
} }
export class VersionsConfig { export class VersionsConfig {
constructor ( constructor (
public version: string, public version: string,
public list: string[] = [], public list: Record<string, number> = {}
public timestamps: Record<string, number> = {}
) {} ) {}
static import (data: VersionsConfigData) { static import (data: VersionsConfigData) {
const cfg = new VersionsConfig(data.version) const cfg = new VersionsConfig(data.version)
cfg.list = [...data.list] cfg.list = { ...data.list }
cfg.timestamps = { ...data.timestamps }
return cfg return cfg
} }
} }
+39 -2
View File
@@ -32,7 +32,31 @@ export async function readNormalConfig (): Promise<NormalConfig> {
return new NormalConfig(version) return new NormalConfig(version)
} }
const config = await readTextFile('config.json', options) const config = await readTextFile('config.json', options)
return NormalConfig.import(JSON.parse(config)) const raw = JSON.parse(config)
if (
raw.settings &&
raw.settings.theme &&
(raw.version == '1.0.0' ||
raw.version == '1.1.0' ||
raw.version == '1.1.1' ||
raw.version == '1.2.0' ||
raw.version == '1.3.0' ||
raw.version == '1.3.1' ||
raw.version == '1.4.0' ||
raw.version == '1.5.0' ||
raw.version == '1.5.1' ||
raw.version == '1.5.2' ||
raw.version == '1.5.3' ||
raw.version == '1.5.4')
) {
const parsed = Number(raw.settings.theme)
if (parsed == 3) raw.settings.theme = 2
if (parsed == 4) raw.settings.theme = 3
else if (parsed != 0 && parsed != 1) raw.settings.theme = 0
}
raw.version = version
writeNormalConfig(raw)
return NormalConfig.import(raw)
} catch { } catch {
return new NormalConfig(version) return new NormalConfig(version)
} }
@@ -82,7 +106,20 @@ export async function readVersionsConfig (): Promise<VersionsConfig> {
return new VersionsConfig(version) return new VersionsConfig(version)
} }
const config = await readTextFile('versions.json', options) const config = await readTextFile('versions.json', options)
return VersionsConfig.import(JSON.parse(config)) const raw = JSON.parse(config)
if (raw.list && raw.timestamps) {
raw.list = raw.timestamps
delete raw.timestamps
await writeFile(
'versions.json',
new TextEncoder().encode(JSON.stringify(raw, null, 2)),
options
)
}
raw.version = version
writeVersionsConfig(raw)
return VersionsConfig.import(raw)
} catch { } catch {
return new VersionsConfig(version) return new VersionsConfig(version)
} }
+3 -1
View File
@@ -28,7 +28,9 @@
"**/*.tsx", "**/*.tsx",
".next/types/**/*.ts", ".next/types/**/*.ts",
".next/dev/types/**/*.ts", ".next/dev/types/**/*.ts",
"**/*.mts" "**/*.mts",
"next.config.ts",
"eslint.config.ts"
], ],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }