Compare commits

...

56 Commits

Author SHA1 Message Date
HorizonCode cbfe5ec868 fix: Setup Wizard not working 2026-02-19 15:41:29 +01:00
HorizonCode c5b18dacbb chore: update lucide-svelte 2026-02-19 15:41:10 +01:00
HorizonCode ef01984875 fix: osu installation detection 2026-02-19 15:40:56 +01:00
HorizonCode 46ee36ce81 fix: disable all buttons and dropdowns on launch 2026-02-17 20:34:57 +01:00
HorizonCode c4658ae4cc fix: sort streaks by depth 2026-02-17 20:13:43 +01:00
HorizonCode ca15ff566f chore: bump version 2026-02-17 19:20:19 +01:00
HorizonCode a6fdda4487 fix: also use color-primary for pp stat 2026-02-17 19:19:09 +01:00
HorizonCode a30946eb60 chore: update animatedbg gradient background colors 2026-02-17 19:18:10 +01:00
HorizonCode 9106ad89b3 chore: replace all bg-pink and border-pink with bg-primary and border-primary 2026-02-17 19:15:38 +01:00
HorizonCode 194709df0c style: adjust primary color 2026-02-17 19:13:23 +01:00
HorizonCode 20f625be60 chore: improve line spreading alogrythm 2026-02-17 19:04:04 +01:00
HorizonCode 66a5fd84ae chore: set AnimatedBg globally 2026-02-17 19:02:37 +01:00
HorizonCode 44d7401947 chore: set AnimatedBg globally 2026-02-17 19:02:28 +01:00
HorizonCode f973e48561 chore: add border to view buttons 2026-02-17 18:58:16 +01:00
HorizonCode de186b7ff9 fix: change beatmapSets count icon 2026-02-17 18:55:45 +01:00
HorizonCode 244d526933 chore: make page switch transitions smoother 2026-02-17 18:52:41 +01:00
HorizonCode c7a990e3fe fix: show login result after redirect to home view 2026-02-17 18:46:12 +01:00
HorizonCode ed1f741a9e chore: remove all console.log 2026-02-17 17:43:05 +01:00
HorizonCode b6616a37f4 fix: isNet8Installed condition 2026-02-17 17:41:04 +01:00
HorizonCode 63433ac626 chore: update sileo 2026-02-17 17:40:46 +01:00
HorizonCode 149b4715d7 fix: updateUrl 2026-02-17 17:40:35 +01:00
HorizonCode ae3443d0b9 fix: osu running check 2026-02-16 21:53:53 +01:00
HorizonCode abc7b9d9d9 chore: replace sonner with sileo 2026-02-16 21:53:07 +01:00
HorizonCode d9dd21d3be chore: cleanup commands, fix osu folder check 2026-02-16 20:46:58 +01:00
HorizonCode 0df31178f4 fix: make count functions async to prevent frontend lock 2026-02-16 20:20:29 +01:00
HorizonCode 6825f9e99b fix: login box width, update releasestream and version 2026-02-15 19:08:04 +01:00
HorizonCode 08a8e34781 chore: add launch button states 2026-02-15 19:02:07 +01:00
HorizonCode 1aa973f6bb chore: bump version 2026-02-15 18:57:38 +01:00
HorizonCode 0999832985 fix: titlebar margin 2026-02-15 18:57:30 +01:00
HorizonCode 11798318f4 chore: only display user stats when logged in 2026-02-15 18:57:17 +01:00
HorizonCode f1b909e248 chore: make pp value better visible 2026-02-15 18:43:51 +01:00
HorizonCode 1f845f1282 chore: rework launcher design 2026-02-15 18:42:01 +01:00
HorizonCode f9b38ec9eb fix: improve error handling for network connection launch failures 2026-01-04 20:20:19 +01:00
HorizonCode 623559cf8e chore: update syn and other dependencies to latest versions 2026-01-04 20:08:26 +01:00
HorizonCode 80bd096834 chore: bump version 2026-01-04 19:36:57 +01:00
HorizonCode e1c6e35f95 chore: refactor version syncing logic in sync-version.ts 2026-01-04 19:36:39 +01:00
HorizonCode 57158bab15 chore: force dark theme to toast component 2026-01-04 19:27:01 +01:00
HorizonCode 58837053c7 chore: update button text color to improve visibility 2026-01-04 19:26:42 +01:00
HorizonCode 458a2cca36 chore: update @lucide/svelte dependency 2026-01-04 17:16:39 +01:00
HorizonCode cb66df6082 chore: update text color for user name display 2026-01-04 17:16:23 +01:00
HorizonCode 1d1904e995 chore: update interactive role checks in OsuCursor component 2026-01-04 17:16:09 +01:00
HorizonCode c07e390b65 chore: redesign user display, remove tabs switch from main view 2026-01-04 17:03:22 +01:00
HorizonCode bae0fad19b chore: update rust and bun dependencies to latest versions 2026-01-02 22:02:40 +01:00
HorizonCode 993eb167fc chore: bump version for tauri too .-. 2025-12-22 22:31:18 +01:00
HorizonCode ea2e348ccc chore: bump version for tauri backend too 2025-12-22 22:28:41 +01:00
HorizonCode 2855880c18 chore: bump version 2025-12-22 22:27:46 +01:00
HorizonCode dcb57c5452 chore: add seasonal assets 2025-12-22 22:25:18 +01:00
HorizonCode c9def2c46b chore: bump version to 3.0.8 2025-12-07 16:22:29 +01:00
HorizonCode b8ebcf5509 feat: conditionally track app launch, exit, and failure events based on trackingEnabled state 2025-12-07 16:21:21 +01:00
HorizonCode a338df6a36 chore: bump version to 3.0.7 in package.json, Cargo.toml, Cargo.lock, and tauri.conf.json; update +page.svelte to include trackingEnabled 2025-12-07 00:50:21 +01:00
HorizonCode d67d58824b feat: implement app tracking consent dialog and update tracking state management 2025-12-07 00:46:33 +01:00
HorizonCode ad090ce38c feat: add umami tracking for app launch and exit events; update dependencies in package.json and bun.lock 2025-12-07 00:11:49 +01:00
HorizonCode 3d57524a16 fix: update build script to include vite build step 2025-12-06 13:04:07 +01:00
HorizonCode d6bf3ccb3c chore: bump version to 3.0.6 in package.json, Cargo.toml, Cargo.lock, and tauri.conf.json; remove unused styles in Launch.svelte 2025-12-06 13:01:59 +01:00
HorizonCode a548dc875e chore: update .net8 desktop url 2025-12-06 12:46:31 +01:00
HorizonCode 3029cc66fb chore: update launch button to be more present 2025-12-06 12:40:37 +01:00
32 changed files with 2346 additions and 2025 deletions
+1
View File
@@ -43,6 +43,7 @@ It enhances the osu! experience with quality-of-life features and integration sp
- **Rust** (installed via [rustup](https://rustup.rs/) – recommended for Windows)
- **Cargo** (comes with rustup)
- **[CMake](https://cmake.org/download/)**
- **[Bun](https://bun.sh/)** (JavaScript runtime)
### Steps
+74 -40
View File
@@ -10,37 +10,43 @@
"@number-flow/svelte": "^0.3.9",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.1.11",
"@tauri-apps/api": "^2.8.0",
"@tauri-apps/plugin-dialog": "^2.4.0",
"@tauri-apps/plugin-fs": "^2.4.2",
"@tauri-apps/plugin-shell": "^2.3.1",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-dialog": "^2.4.2",
"@tauri-apps/plugin-fs": "^2.4.4",
"@tauri-apps/plugin-shell": "^2.3.3",
"@types/umami": "^2.10.1",
"animejs": "^4.1.3",
"buffer": "^6.0.3",
"crypto-js": "^4.2.0",
"lucide-svelte": "^0.542.0",
"lucide-svelte": "^0.562.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-to-webcomponent": "^2.0.1",
"semver": "^7.7.2",
"sileo": "^0.1.3",
"svelte-confetti": "^2.3.2",
"tw-animate-css": "^1.3.8",
},
"devDependencies": {
"@eslint/compat": "^1.3.2",
"@eslint/compat": "^2.0.0",
"@eslint/js": "^9.35.0",
"@iarna/toml": "2.2.5",
"@lucide/svelte": "^0.542.0",
"@lucide/svelte": "^0.562.0",
"@sveltejs/adapter-static": "^3.0.9",
"@sveltejs/kit": "^2.37.1",
"@sveltejs/vite-plugin-svelte": "^6.1.4",
"@tauri-apps/cli": "^2.8.4",
"@tauri-apps/cli": "^2.9.6",
"@types/bun": "^1.2.21",
"@types/crypto-js": "^4.2.2",
"@types/react-dom": "^19.2.3",
"@types/semver": "^7.7.1",
"autoprefixer": "10.4.21",
"bits-ui": "^2.9.6",
"bits-ui": "^1.4.7",
"clsx": "^2.1.1",
"eslint": "^9.35.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.12.2",
"globals": "^16.3.0",
"globals": "^17.0.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
@@ -56,7 +62,7 @@
"typescript": "^5.9.2",
"typescript-eslint": "^8.42.0",
"vite": "^7.1.5",
"vite-plugin-devtools-json": "^0.4.1",
"vite-plugin-devtools-json": "^1.0.0",
},
},
},
@@ -121,13 +127,13 @@
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/compat": ["@eslint/compat@1.3.2", "", { "peerDependencies": { "eslint": "^8.40 || 9" }, "optionalPeers": ["eslint"] }, "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA=="],
"@eslint/compat": ["@eslint/compat@2.0.0", "", { "dependencies": { "@eslint/core": "^1.0.0" }, "peerDependencies": { "eslint": "^8.40 || 9" }, "optionalPeers": ["eslint"] }, "sha512-T9AfE1G1uv4wwq94ozgTGio5EUQBqAVe1X9qsQtSNVEYW6j3hvtZVm8Smr4qL1qDPFg+lOB2cL5RxTRMzq4CTA=="],
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"@eslint/core": ["@eslint/core@1.0.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-PRfWP+8FOldvbApr6xL7mNCw4cJcSTq4GA7tYbgq15mRb0kWKO/wEB2jr+uwjFH3sZvEZneZyCUGTxsv4Sahyw=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
@@ -173,7 +179,7 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@lucide/svelte": ["@lucide/svelte@0.542.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-NuWttxTVfMSURpOxcKiKvoCtma3JtEpcJWzF/0cO69saZfXlv6G8NYAvEEGLmk75YPl+I+ROe+F97WhddM8r2A=="],
"@lucide/svelte": ["@lucide/svelte@0.562.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-wDMULwtTFN2Sc/TFBm6gfuVCNb4Y5P9LDrwxNnUbV52+IEU7NXZmvxwXoz+vrrpad6Xupq+Hw5eUlqIHEGhouw=="],
"@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=="],
@@ -213,6 +219,8 @@
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
"@r2wc/core": ["@r2wc/core@1.3.0", "", {}, "sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.44.1", "", { "os": "android", "cpu": "arm" }, "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.44.1", "", { "os": "android", "cpu": "arm64" }, "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ=="],
@@ -299,37 +307,37 @@
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="],
"@tauri-apps/api": ["@tauri-apps/api@2.8.0", "", {}, "sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw=="],
"@tauri-apps/api": ["@tauri-apps/api@2.9.1", "", {}, "sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw=="],
"@tauri-apps/cli": ["@tauri-apps/cli@2.8.4", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.8.4", "@tauri-apps/cli-darwin-x64": "2.8.4", "@tauri-apps/cli-linux-arm-gnueabihf": "2.8.4", "@tauri-apps/cli-linux-arm64-gnu": "2.8.4", "@tauri-apps/cli-linux-arm64-musl": "2.8.4", "@tauri-apps/cli-linux-riscv64-gnu": "2.8.4", "@tauri-apps/cli-linux-x64-gnu": "2.8.4", "@tauri-apps/cli-linux-x64-musl": "2.8.4", "@tauri-apps/cli-win32-arm64-msvc": "2.8.4", "@tauri-apps/cli-win32-ia32-msvc": "2.8.4", "@tauri-apps/cli-win32-x64-msvc": "2.8.4" }, "bin": { "tauri": "tauri.js" } }, "sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g=="],
"@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-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.8.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA=="],
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.9.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.8.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.9.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw=="],
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.8.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw=="],
"@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-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.8.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw=="],
"@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-musl": ["@tauri-apps/cli-linux-arm64-musl@2.8.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw=="],
"@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-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.8.4", "", { "os": "linux", "cpu": "none" }, "sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ=="],
"@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-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.8.4", "", { "os": "linux", "cpu": "x64" }, "sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw=="],
"@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-musl": ["@tauri-apps/cli-linux-x64-musl@2.8.4", "", { "os": "linux", "cpu": "x64" }, "sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA=="],
"@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-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.8.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w=="],
"@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-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.8.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA=="],
"@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-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.8.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA=="],
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.9.6", "", { "os": "win32", "cpu": "x64" }, "sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw=="],
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.4.0", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OvXkrEBfWwtd8tzVCEXIvRfNEX87qs2jv6SqmVPiHcJjBhSF/GUvjqUNIDmKByb5N8nvDqVUM7+g1sXwdC/S9w=="],
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ=="],
"@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-YGhmYuTgXGsi6AjoV+5mh2NvicgWBfVJHHheuck6oHD+HC9bVWPaHvCP0/Aw4pHDejwrvT8hE3+zZAaWf+hrig=="],
"@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.4", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-MTorXxIRmOnOPT1jZ3w96vjSuScER38ryXY88vl5F0uiKdnvTKKTtaEjTEo8uPbl4e3gnUtfsDVwC7h77GQLvQ=="],
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-jjs2WGDO/9z2pjNlydY/F5yYhNsscv99K5lCmU5uKjsVvQ3dRlDhhtVYoa4OLDmktLtQvgvbQjCFibMl6tgGfw=="],
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ=="],
"@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="],
@@ -345,8 +353,12 @@
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="],
"@types/umami": ["@types/umami@2.10.1", "", {}, "sha512-CvOEMq+BFOUXj8yciq4hPsdOt0o9KBg5jQXnF1FrdOMKZMxJiwryyZNLa9Ud2NVO6nXSwU22YMKR3E+Xhbo+DA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.42.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/type-utils": "8.42.0", "@typescript-eslint/utils": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.42.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.42.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg=="],
@@ -389,7 +401,7 @@
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"bits-ui": ["bits-ui@2.9.6", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.29.1", "svelte-toolbelt": "^0.9.3", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-OzHktsQRsIz/hIMk5VwHo96Wpp/KY68q/ebUPUzTbvuFBrALB/X+QvO4KLgdczj5dfb3xHs9zpWq8yMH8ZbZlA=="],
"bits-ui": ["bits-ui@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.6.4", "@floating-ui/dom": "^1.6.7", "@internationalized/date": "^3.5.6", "css.escape": "^1.5.1", "esm-env": "^1.1.2", "runed": "^0.23.2", "svelte-toolbelt": "^0.7.1", "tabbable": "^6.2.0" }, "peerDependencies": { "svelte": "^5.11.0" } }, "sha512-CXD6Orp7l8QevNDcRPLXc/b8iMVgxDWT2LyTwsdLzJKh9CxesOmPuNePSPqAxKoT59FIdU4aFPS1k7eBdbaCxg=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
@@ -429,6 +441,8 @@
"crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="],
"css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="],
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
@@ -501,11 +515,13 @@
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
"framer-motion": ["framer-motion@12.34.1", "", { "dependencies": { "motion-dom": "^12.34.1", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-kcZyNaYQfvE2LlH6+AyOaJAQV4rGp5XbzfhsZpiSZcwDMfZUHhuxLWeyRzf5I7jip3qKRpuimPA9pXXfr111kQ=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"globals": ["globals@17.0.0", "", {}, "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
@@ -587,7 +603,7 @@
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"lucide-svelte": ["lucide-svelte@0.542.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-KxqJycY4EWaGy1zk/7sqEcf48j4YaP9zEujYczzrsw5j9b9b5pjAJ1qGFKZvD7T6xz9reSYAfUAd6Bz62TdqGw=="],
"lucide-svelte": ["lucide-svelte@0.562.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-kSJDH/55lf0mun/o4nqWBXOcq0fWYzPeIjbTD97ywoeumAB9kWxtM06gC7oynqjtK3XhAljWSz5RafIzPEYIQA=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
@@ -605,6 +621,12 @@
"mode-watcher": ["mode-watcher@1.1.0", "", { "dependencies": { "runed": "^0.25.0", "svelte-toolbelt": "^0.7.1" }, "peerDependencies": { "svelte": "^5.27.0" } }, "sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g=="],
"motion": ["motion@12.34.1", "", { "dependencies": { "framer-motion": "^12.34.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-N9RVNGn/NSo85OgHX1wGaUWHvReuQ7dZUwuQRhHyzY2wfVOvY3cEgn0Mw4NXOsXMHL/y7EYuzA+b59PYI6EejA=="],
"motion-dom": ["motion-dom@12.34.1", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-SC7ZC5dRcGwku2g7EsPvI4q/EzHumUbqsDNumBmZTLFg+goBO5LTJvDu9MAxx+0mtX4IA78B2be/A3aRjY0jnw=="],
"motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
@@ -661,6 +683,12 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-to-webcomponent": ["react-to-webcomponent@2.0.1", "", { "dependencies": { "@r2wc/core": "^1.0.0" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-jpVztcA0SbV6TnBRV6EFuU+hmuuSIxgEww3wRcbneT0ytqn57y9ygeRfUmhzz8+bYg53u1h4COKk8iAextHE+Q=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
@@ -671,7 +699,7 @@
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"runed": ["runed@0.29.2", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA=="],
"runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
@@ -717,6 +745,8 @@
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.92.1", "", { "os": "win32", "cpu": "x64" }, "sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
@@ -725,6 +755,8 @@
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"sileo": ["sileo@0.1.3", "", { "dependencies": { "motion": "^12.34.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-kmGjM2ts2TpuPzOaD7llxcMpU37Pyj5dO8s4wGXvDlR143zV2sB6sJ76PCVP4kY2+hfkrLJhiSm/wXGdUHDFjQ=="],
"sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
@@ -745,7 +777,7 @@
"svelte-sonner": ["svelte-sonner@1.0.5", "", { "dependencies": { "runed": "^0.28.0" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-9dpGPFqKb/QWudYqGnEz93vuY+NgCEvyNvxoCLMVGw6sDN/3oVeKV1xiEirW2E1N3vJEyj5imSBNOGltQHA7mg=="],
"svelte-toolbelt": ["svelte-toolbelt@0.9.3", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.29.0", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw=="],
"svelte-toolbelt": ["svelte-toolbelt@0.7.1", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.23.2", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ=="],
"sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="],
@@ -797,7 +829,7 @@
"vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="],
"vite-plugin-devtools-json": ["vite-plugin-devtools-json@0.4.1", "", { "dependencies": { "uuid": "^11.1.0" }, "peerDependencies": { "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-pN+QJL+NwZUV+Via8w/Sh6X2pDrVClIMDAXdl7+EteXKB6mcHhsFGGclmxrPx6ZPGKSK5ez5ns64oRpjE5wFCg=="],
"vite-plugin-devtools-json": ["vite-plugin-devtools-json@1.0.0", "", { "dependencies": { "uuid": "^11.1.0" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-MobvwqX76Vqt/O4AbnNMNWoXWGrKUqZbphCUle/J2KXH82yKQiunOeKnz/nqEPosPsoWWPP9FtNuPBSYpiiwkw=="],
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
@@ -817,6 +849,8 @@
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
@@ -839,16 +873,18 @@
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"eslint/@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"eslint-plugin-svelte/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"eslint-plugin-svelte/globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"mode-watcher/runed": ["runed@0.25.0", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg=="],
"mode-watcher/svelte-toolbelt": ["svelte-toolbelt@0.7.1", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.23.2", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ=="],
"svelte-eslint-parser/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
"svelte-sonner/runed": ["runed@0.28.0", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ=="],
@@ -860,7 +896,5 @@
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"eslint-plugin-svelte/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"mode-watcher/svelte-toolbelt/runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
}
}
+21 -15
View File
@@ -1,11 +1,11 @@
{
"name": "ezpplauncher",
"version": "3.0.5",
"version": "3.1.1",
"description": "",
"type": "module",
"scripts": {
"debug": "bun run tauri dev",
"build": "bun ./scripts/sync-version.ts && bun run tauri:build",
"build": "bun ./scripts/sync-version.ts && bun run vite:build && bun run tauri:build",
"vite:dev": "vite dev",
"vite:build": "vite build",
"tauri:build": "tauri build",
@@ -24,37 +24,43 @@
"@number-flow/svelte": "^0.3.9",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.1.11",
"@tauri-apps/api": "^2.8.0",
"@tauri-apps/plugin-dialog": "^2.4.0",
"@tauri-apps/plugin-fs": "^2.4.2",
"@tauri-apps/plugin-shell": "^2.3.1",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-dialog": "^2.4.2",
"@tauri-apps/plugin-fs": "^2.4.4",
"@tauri-apps/plugin-shell": "^2.3.3",
"@types/umami": "^2.10.1",
"animejs": "^4.1.3",
"buffer": "^6.0.3",
"crypto-js": "^4.2.0",
"lucide-svelte": "^0.542.0",
"lucide-svelte": "^0.575.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-to-webcomponent": "^2.0.1",
"semver": "^7.7.2",
"tw-animate-css": "^1.3.8",
"svelte-confetti": "^2.3.2"
"sileo": "^0.1.3",
"svelte-confetti": "^2.3.2",
"tw-animate-css": "^1.3.8"
},
"devDependencies": {
"@eslint/compat": "^1.3.2",
"@eslint/compat": "^2.0.0",
"@eslint/js": "^9.35.0",
"@iarna/toml": "2.2.5",
"@lucide/svelte": "^0.542.0",
"@lucide/svelte": "^0.575.0",
"@sveltejs/adapter-static": "^3.0.9",
"@sveltejs/kit": "^2.37.1",
"@sveltejs/vite-plugin-svelte": "^6.1.4",
"@tauri-apps/cli": "^2.8.4",
"@tauri-apps/cli": "^2.9.6",
"@types/bun": "^1.2.21",
"@types/crypto-js": "^4.2.2",
"@types/react-dom": "^19.2.3",
"@types/semver": "^7.7.1",
"autoprefixer": "10.4.21",
"bits-ui": "^2.9.6",
"bits-ui": "^1.4.7",
"clsx": "^2.1.1",
"eslint": "^9.35.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.12.2",
"globals": "^16.3.0",
"globals": "^17.0.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
@@ -70,6 +76,6 @@
"typescript": "^5.9.2",
"typescript-eslint": "^8.42.0",
"vite": "^7.1.5",
"vite-plugin-devtools-json": "^0.4.1"
"vite-plugin-devtools-json": "^1.0.0"
}
}
+12 -5
View File
@@ -3,19 +3,26 @@ import path from 'path';
import * as toml from '@iarna/toml';
import { cwd } from 'process';
const packageJsonPath = path.join(cwd(), 'package.json');
const cargoTomlPath = path.join(cwd(), 'src-tauri', 'Cargo.toml');
const tauriConfPath = path.join(cwd(), 'src-tauri', 'tauri.conf.json');
const cargoToml = fs.readFileSync(cargoTomlPath, 'utf8');
const cargo = toml.parse(cargoToml) as Record<string, string>;
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const version = packageJson.version;
if (!version) throw new Error('Could not find version in package.json');
const version = cargo.package['version'];
if (!version) throw new Error('Could not find version in Cargo.toml');
let cargoTomlContent = fs.readFileSync(cargoTomlPath, 'utf8');
const cargo = toml.parse(cargoTomlContent) as { package: { version: string } };
if (cargo.package.version !== version) {
cargoTomlContent = cargoTomlContent.replace(/version = ".*?"/, `version = "${version}"`);
fs.writeFileSync(cargoTomlPath, cargoTomlContent);
console.log(`✅ Synced Cargo.toml version to ${version}`);
}
const tauriConf = JSON.parse(fs.readFileSync(tauriConfPath, 'utf8'));
if (tauriConf.version !== version) {
tauriConf.version = version;
fs.writeFileSync(tauriConfPath, JSON.stringify(tauriConf, null, 2));
console.log(`✅ Synced tauri.conf.json version to ${version}`);
}
+967 -1016
View File
File diff suppressed because it is too large Load Diff
+15 -15
View File
@@ -1,6 +1,6 @@
[package]
name = "ezpplauncher"
version = "3.0.5"
version = "3.1.1"
description = "EZPPLauncher redefined."
authors = ["HorizonCode"]
edition = "2024"
@@ -15,24 +15,24 @@ name = "ezpplauncher_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.4.1", features = [] }
tauri-build = { version = "2.5.3", features = [] }
[dependencies]
tauri = { version = "2.8.5", features = [] }
tauri-plugin-shell = "2.3.1"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.143"
tauri = { version = "2.9.5", features = [] }
tauri-plugin-shell = "2.3.3"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.148"
serde_repr = "0.1.20"
tauri-plugin-dialog = "2.4.0"
tauri-plugin-fs = "2.4.2"
tauri-plugin-dialog = "2.4.2"
tauri-plugin-fs = "2.4.4"
hardware-id = "0.3.0"
tauri-plugin-cors-fetch = "4.1.0"
sysinfo = "0.37.0"
reqwest = { version = "0.12.23", features = ["json", "stream"] }
sysinfo = "0.37.2"
reqwest = { version = "0.13.1", features = ["json", "stream", "query"] }
md5 = "0.8.0"
tokio = { version = "1.47.1", features = ["full"] }
open = "5.3.2"
windows-sys = "0.61.0"
tokio = { version = "1.48.0", features = ["full"] }
open = "5.3.3"
windows-sys = "0.61.2"
discord-rich-presence = "1.0.0"
once_cell = "1.21.3"
@@ -40,8 +40,8 @@ once_cell = "1.21.3"
winreg = "0.55.0"
winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
base64 = "0.22.1"
widestring = "1.0"
widestring = "1.2.1"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.4"
tauri-plugin-single-instance = "2.3.6"
+48 -62
View File
@@ -56,17 +56,11 @@ pub fn valid_osu_folder(folder: String) -> bool {
"scores.db",
];
let folder_files: Vec<&str> = osu_folder_files.iter().map(|&s| s).collect();
if folder_files.iter().any(|&file| file == "osu!.exe") == false {
return false;
}
let path = PathBuf::from(folder);
let match_percentage = check_folder_completeness(path, &osu_folder_files) >= 70.0;
if match_percentage {
return true;
}
if !path.join("osu!.exe").exists() {
return false;
}
check_folder_completeness(path, &osu_folder_files) >= 70.0
}
#[cfg(not(windows))]
@@ -83,10 +77,10 @@ pub fn find_osu_installation() -> Option<String> {
let hklm_registry_paths = ["SOFTWARE\\Classes\\osu\\DefaultIcon"];
let hkcr_registry_paths = [
"osustable.File.osk\\DefaultIcon",
"osustable.File.osr\\DefaultIcon",
"osustable.File.osz\\DefaultIcon",
let hkcu_registry_paths = [
"Software\\Classes\\osustable.File.osk\\DefaultIcon",
"Software\\Classes\\osustable.File.osr\\DefaultIcon",
"Software\\Classes\\osustable.File.osz\\DefaultIcon",
];
let osu_folder_files = [
@@ -135,10 +129,10 @@ pub fn find_osu_installation() -> Option<String> {
}
}
let hkcr = RegKey::predef(HKEY_CLASSES_ROOT);
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
for reg_path in &hkcr_registry_paths {
if let Ok(subkey) = hkcr.open_subkey_with_flags(reg_path, KEY_READ | KEY_WOW64_32KEY) {
for reg_path in &hkcu_registry_paths {
if let Ok(subkey) = hkcu.open_subkey_with_flags(reg_path, KEY_READ | KEY_WOW64_32KEY) {
let value_names = [""];
for value_name in &value_names {
if let Ok(value) = subkey.get_value::<String, _>(value_name) {
@@ -160,7 +154,7 @@ pub fn find_osu_installation() -> Option<String> {
}
#[tauri::command]
pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
pub async fn get_beatmapsets_count(folder: String) -> Option<u64> {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
let songs_path = osu_user_config
@@ -173,12 +167,12 @@ pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
}
let mut count = 0;
if let Ok(entries) = std::fs::read_dir(songs_folder) {
for entry in entries.flatten() {
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
if let Ok(mut entries) = fs::read_dir(songs_folder).await {
while let Ok(Some(entry)) = entries.next_entry().await {
if entry.file_type().await.map_or(false, |ft| ft.is_dir()) {
let dir_path = entry.path();
if let Ok(files) = std::fs::read_dir(&dir_path) {
for file in files.flatten() {
if let Ok(mut files) = fs::read_dir(&dir_path).await {
while let Ok(Some(file)) = files.next_entry().await {
if file.path().extension().map_or(false, |ext| ext == "osu") {
count += 1;
break;
@@ -192,7 +186,7 @@ pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
}
#[tauri::command]
pub fn get_skins_count(folder: String) -> Option<u64> {
pub async fn get_skins_count(folder: String) -> Option<u64> {
let path = PathBuf::from(folder);
let skins_folder = path.join("Skins");
@@ -201,12 +195,12 @@ pub fn get_skins_count(folder: String) -> Option<u64> {
}
let mut count = 0;
if let Ok(entries) = std::fs::read_dir(skins_folder) {
for entry in entries.flatten() {
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
if let Ok(mut entries) = fs::read_dir(skins_folder).await {
while let Ok(Some(entry)) = entries.next_entry().await {
if entry.file_type().await.map_or(false, |ft| ft.is_dir()) {
let dir_path = entry.path();
if let Ok(files) = std::fs::read_dir(&dir_path) {
for file in files.flatten() {
if let Ok(mut files) = fs::read_dir(&dir_path).await {
while let Ok(Some(file)) = files.next_entry().await {
if file.path().extension().map_or(false, |ext| ext == "ini") {
count += 1;
break;
@@ -222,28 +216,28 @@ pub fn get_skins_count(folder: String) -> Option<u64> {
#[tauri::command]
pub fn get_osu_skin(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
return osu_user_config
let osu_user_config = get_osu_user_config(path);
osu_user_config
.and_then(|config| config.get("Skin").cloned())
.unwrap_or_else(|| "Default".to_string());
.unwrap_or_else(|| "Default".to_string())
}
#[tauri::command]
pub fn get_osu_version(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
return osu_user_config
let osu_user_config = get_osu_user_config(path);
osu_user_config
.and_then(|config| config.get("LastVersion").cloned())
.unwrap_or_else(|| "failed".to_string());
.unwrap_or_else(|| "failed".to_string())
}
#[tauri::command]
pub fn get_osu_release_stream(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_config = get_osu_config(path.clone());
return osu_config
let osu_config = get_osu_config(path);
osu_config
.and_then(|config| config.get("_ReleaseStream").cloned())
.unwrap_or_else(|| "Stable40".to_string());
.unwrap_or_else(|| "Stable40".to_string())
}
#[derive(serde::Deserialize)]
@@ -261,10 +255,7 @@ pub fn set_osu_user_config_values(
.iter()
.map(|entry| (entry.key.as_str(), Some(entry.value.as_str())))
.collect();
match set_osu_user_config_vals(&osu_folder_path, &converted) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
Ok(set_osu_user_config_vals(&osu_folder_path, &converted).is_ok())
}
#[tauri::command]
@@ -276,22 +267,16 @@ pub fn set_osu_config_values(
.iter()
.map(|entry| (entry.key.as_str(), Some(entry.value.as_str())))
.collect();
match set_osu_config_vals(&osu_folder_path, &converted) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
Ok(set_osu_config_vals(&osu_folder_path, &converted).is_ok())
}
#[tauri::command]
pub async fn run_osu_updater(folder: String) -> Result<(), String> {
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x00000008;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
let mut updater_process = {
#[cfg(windows)]
{
const DETACHED_PROCESS: u32 = 0x00000008;
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
let osu_exe_path = PathBuf::from(&folder).join("osu!.exe");
Command::new(&osu_exe_path)
.arg("-repair")
@@ -368,9 +353,6 @@ pub async fn run_osu_updater(folder: String) -> Result<(), String> {
#[tauri::command]
pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
/* #[cfg(windows)]
use std::os::windows::process::CommandExt; */
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x00000008;
#[cfg(windows)]
@@ -385,7 +367,7 @@ pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
.arg("ez-pp.farm")
.creation_flags(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)
.spawn()
.map_err(|e| format!("Failed to spawn updater: {}", e))?
.map_err(|e| format!("Failed to spawn osu: {}", e))?
}
#[cfg(not(windows))]
@@ -394,7 +376,7 @@ pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
.arg("--devserver")
.arg("ez-pp.farm")
.spawn()
.map_err(|e| format!("Failed to spawn updater: {}", e))?
.map_err(|e| format!("Failed to spawn osu: {}", e))?
}
};
@@ -566,10 +548,13 @@ pub fn replace_ui_files(folder: String, revert: bool) -> Result<(), ReplaceUIErr
let osu_path = PathBuf::from(folder);
let ezpp_ui = osu_path.join("EZPPLauncher").join("ezpp!ui.dll");
let osu_ui = osu_path.join("osu!ui.dll");
let ezpp_seasonal = osu_path.join("EZPPLauncher").join("ezpp!seasonal.dll");
let osu_seasonal = osu_path.join("osu!seasonal.dll");
let ezpp_gameplay = osu_path.join("EZPPLauncher").join("ezpp!gameplay.dll");
let osu_gameplay = osu_path.join("osu!gameplay.dll");
let osu_ui_bak = osu_path.join("osu!ui.dll.bak");
let osu_seasonal_bak = osu_path.join("osu!seasonal.dll.bak");
let osu_gameplay_bak = osu_path.join("osu!gameplay.dll.bak");
let try_rename = |from: &PathBuf, to: &PathBuf| -> Result<(), ReplaceUIError> {
@@ -591,12 +576,18 @@ pub fn replace_ui_files(folder: String, revert: bool) -> Result<(), ReplaceUIErr
try_rename(&osu_ui, &osu_ui_bak)?;
try_rename(&ezpp_ui, &osu_ui)?;
try_rename(&osu_seasonal, &osu_seasonal_bak)?;
try_rename(&ezpp_seasonal, &osu_seasonal)?;
try_rename(&osu_gameplay, &osu_gameplay_bak)?;
try_rename(&ezpp_gameplay, &osu_gameplay)?;
} else {
try_rename(&osu_ui, &ezpp_ui)?;
try_rename(&osu_ui_bak, &osu_ui)?;
try_rename(&osu_seasonal, &ezpp_seasonal)?;
try_rename(&osu_seasonal_bak, &osu_seasonal)?;
try_rename(&osu_gameplay, &ezpp_gameplay)?;
try_rename(&osu_gameplay_bak, &osu_gameplay)?;
}
@@ -723,12 +714,7 @@ pub async fn has_net8() -> bool {
#[tauri::command]
pub fn encrypt_string(string: String, entropy: String) -> String {
let encrypted = encrypt_password(&string, &entropy);
match encrypted {
Ok(encrypted_vec) => encrypted_vec,
Err(_) => string,
}
encrypt_password(&string, &entropy).unwrap_or(string)
}
#[tauri::command]
@@ -764,7 +750,7 @@ pub async fn download_ezpp_launcher_update(app: AppHandle, url: String) -> Resul
UpdateStatus {
file_name: "Update".to_string(),
downloaded,
size: size,
size,
progress: ((downloaded as f64 / size as f64 * 100.0) * 100.0).trunc() / 100.0,
},
)
+2 -2
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "EZPPLauncher",
"version": "3.0.5",
"version": "3.1.1",
"identifier": "farm.EZPPFarm.Launcher",
"mainBinaryName": "ezpplauncher",
"build": {
@@ -15,7 +15,7 @@
{
"title": "EZPPLauncher",
"width": 1000,
"height": 700,
"height": 650,
"decorations": false,
"resizable": false,
"maximizable": false
+16 -18
View File
@@ -55,7 +55,7 @@
--card-foreground: oklch(89.24% 0.079 263.24);
--popover: oklch(20.3% 0.05 282.86);
--popover-foreground: oklch(89.24% 0.079 263.24);
--primary: oklch(81.45% 0.159 300.53);
--primary: oklch(72.08% 0.196 356.34);
--primary-foreground: oklch(20.22% 0.048 282.86);
--secondary: oklch(42.99% 0.031 270.49);
--secondary-foreground: oklch(89.24% 0.079 263.24);
@@ -67,8 +67,8 @@
--destructive-foreground: oklch(20.22% 0.048 282.86);
--border: oklch(27.7% 0.041 276.87);
--input: oklch(27.7% 0.041 276.87);
--ring: oklch(81.45% 0.159 300.53);
--chart-1: oklch(81.45% 0.159 300.53);
--ring: oklch(72.08% 0.196 356.34);
--chart-1: oklch(72.08% 0.196 356.34);
--chart-2: oklch(77.19% 0.121 223.01);
--chart-3: oklch(79.1% 0.119 150.21);
--chart-4: oklch(79.74% 0.167 57.97);
@@ -76,12 +76,12 @@
--sidebar: oklch(13.29% 0.036 282.86);
--sidebar-background: oklch(13.29% 0.036 282.86);
--sidebar-foreground: oklch(89.24% 0.079 263.24);
--sidebar-primary: oklch(81.45% 0.159 300.53);
--sidebar-primary: oklch(72.08% 0.196 356.34);
--sidebar-primary-foreground: oklch(20.22% 0.048 282.86);
--sidebar-accent: oklch(75.21% 0.121 293.01);
--sidebar-accent-foreground: oklch(20.22% 0.048 282.86);
--sidebar-border: oklch(35.13% 0.03 273.31);
--sidebar-ring: oklch(81.45% 0.159 300.53);
--sidebar-ring: oklch(72.08% 0.196 356.34);
}
@theme inline {
@@ -108,20 +108,18 @@
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-50: #fefdff;
--color-primary-100: #faf6fe;
--color-primary-200: #f2e9fc;
--color-primary-300: #e9dbfa;
--color-primary-400: #e1cef9;
--color-primary-500: #d9c0f7;
--color-primary-600: #c6a0f3;
--color-primary-700: #b381ef;
--color-primary-800: #a061eb;
--color-primary-900: #8d41e7;
--color-primary-950: #8331e5;
--color-primary-50: #ffe5f1;
--color-primary-100: #ffcce2;
--color-primary-200: #ff99c5;
--color-primary-300: #ff66a8;
--color-primary-400: #ff338b;
--color-primary-500: #ff006e;
--color-primary-600: #cc0058;
--color-primary-700: #990042;
--color-primary-800: #66002c;
--color-primary-900: #330016;
--color-primary-950: #24000f;
--color-primary-foreground: var(--primary-foreground);
--color-primary-50: #fefdff;
--color-primary-100: #faf6fe;
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
@@ -0,0 +1,86 @@
<script lang="ts">
import Logo from '$assets/logo.png';
//TODO: maybe dynamic background images fetched from ezpp?
const COUNT = 60;
function rand(min: number, max: number) {
return Math.random() * (max - min) + min;
}
const streaks = Array.from({ length: COUNT })
.map((_, i) => {
const depth = rand(0, 2);
const scale = 0.6 + depth * 0.8;
const speed = 0.4 + depth * 1.35;
const distance = 150;
const duration = distance / speed;
return {
width: rand(300, 320) * scale,
height: 32 * scale,
x: (i / COUNT) * 200 - 50,
y: ((i * 137.5) % 100) - 20,
opacity: 0.25 + depth * 0.65,
duration,
delay: rand(0, duration),
scale,
};
})
.sort((a, b) => a.scale - b.scale);
</script>
<div class="absolute bg blur-[2px]">
<div
class="relative h-full w-full from-0% to-90% bg-gradient-to-b from-transparent to-black z-50"
></div>
{#each streaks as s}
<div
class="streak drop-shadow-lg"
style="
width:{s.width}px;
height:{s.height}px;
left:{s.x}%;
top:{s.y}%;
opacity:{s.opacity};
animation-duration:{s.duration}s;
animation-delay:-{s.delay}s;
"
></div>
{/each}
</div>
<style>
.bg {
position: fixed;
inset: 0;
overflow: hidden;
background: linear-gradient(
180deg,
var(--color-primary-300) 0%,
var(--color-primary-600) 40%,
var(--color-primary-900) 100%
);
}
.streak {
position: absolute;
background: #d6f3ff;
border-radius: 999px;
transform: rotate(-35deg);
animation: move linear infinite;
will-change: transform;
}
@keyframes move {
from {
transform: translate(-150vw, 150vh) rotate(-35deg);
}
to {
transform: translate(150vw, -150vh) rotate(-35deg);
}
}
</style>
@@ -0,0 +1,91 @@
<script lang="ts">
import Ellipsis from 'lucide-svelte/icons/ellipsis';
import Play from 'lucide-svelte/icons/play';
const prop: {
downloading: boolean;
progress: number;
text: string;
subtext?: string;
disabled?: boolean;
onClick?: () => void;
} = $props();
const radius = 16;
const circumference = 2 * Math.PI * radius;
const strokeDashoffset = $derived(circumference - (prop.progress / 100) * circumference);
</script>
<button
class="group flex items-center h-12 rounded-full bg-primary-300 disabled:bg-primary-300/70 shadow-lg shadow-primary/25 transition-all not-disabled:hover:shadow-primary/40 not-disabled:hover:brightness-110 not-disabled:active:scale-[0.98] cursor-pointer w-fit"
disabled={prop.disabled}
onclick={prop.onClick}
>
<div class="relative size-12 shrink-0 flex items-center justify-center">
{#if prop.downloading}
{#if prop.progress === -1}
<svg class="absolute inset-0 animate-spin" viewBox="0 0 48 48">
<circle class="stroke-black/10" cx="24" cy="24" r={radius} fill="none" stroke-width="3" />
<circle
class="stroke-pink-950"
cx="24"
cy="24"
r={radius}
fill="none"
stroke-width="3"
stroke-linecap="round"
stroke-dasharray={circumference}
stroke-dashoffset={circumference * 0.7}
/>
</svg>
{:else}
<svg class="absolute inset-0 -rotate-90" viewBox="0 0 48 48">
<circle
cx="24"
cy="24"
r={radius}
fill="none"
stroke="rgba(0,0,0,0.2)"
stroke-width="3"
/>
<circle
cx="24"
cy="24"
r={radius}
fill="none"
stroke="rgba(0,0,0,0.7)"
stroke-width="3"
stroke-linecap="round"
stroke-dasharray={circumference}
stroke-dashoffset={strokeDashoffset}
class="transition-[stroke-dashoffset] duration-100"
/>
</svg>
{/if}
{/if}
<div class="size-9 rounded-full bg-black/30 flex items-center justify-center relative z-10">
{#if prop.downloading}
{#if prop.progress === -1}
<Ellipsis class="size-4 text-primary-foreground fill-current animate-pulse" />
{:else}
<span class="text-[10px] font-bold text-primary-foreground">
{prop.progress.toFixed()}
</span>
{/if}
{:else}
<Play class="size-4 text-primary-foreground fill-current ml-0.5" />
{/if}
</div>
</div>
<div class="pr-6 pl-1 text-center w-52">
<p class="text-sm font-bold text-primary-foreground leading-tight">
{prop.text}
</p>
{#if prop.subtext}
<p class="text-[10px] text-primary-foreground/70 leading-tight">
{prop.subtext}
</p>
{/if}
</div>
</button>
@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
import Check from 'lucide-svelte/icons/check';
import Minus from 'lucide-svelte/icons/minus';
import Check from '@lucide/svelte/icons/check';
import Minus from '@lucide/svelte/icons/minus';
import { cn } from '$lib/utils.js';
import type { Snippet } from 'svelte';
@@ -15,7 +15,7 @@
<DropdownMenuPrimitive.Item
bind:ref
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
'data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
inset && 'pl-8',
className
)}
@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChild } from 'bits-ui';
import Circle from 'lucide-svelte/icons/circle';
import Circle from '@lucide/svelte/icons/circle';
import { cn } from '$lib/utils.js';
let {
@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import ChevronRight from 'lucide-svelte/icons/chevron-right';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { cn } from '$lib/utils.js';
let {
@@ -25,7 +25,7 @@
const computed = getComputedStyle(el);
if (
['button', 'a', 'input', 'select', 'textarea', 'label', 'option'].includes(tag) ||
(role && ['button', 'link', 'checkbox', 'combobox'].includes(role)) ||
(role && ['button', 'link', 'checkbox', 'combobox', 'menuitem', 'option'].includes(role)) ||
computed.cursor === 'pointer'
) {
return true;
@@ -85,7 +85,7 @@
animate(cursor, {
duration: smoothCursor ? $cursorSmoothness : 0,
translateX: mouseX,
translateY: mouseY - 50,
translateY: mouseY,
ease: (t: number) => (t - 1) ** 5 + 1,
});
@@ -17,7 +17,7 @@
bind:ref
{value}
class={cn(
'data-[highlighted]:bg-primary-800/30 data-[highlighted]:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'data-[highlighted]:bg-primary-300 data-[highlighted]:text-primary-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className
)}
{...restProps}
@@ -0,0 +1,21 @@
<script lang="ts">
import { createElement } from 'react'
import { createRoot } from 'react-dom/client'
import type { SileoOptions } from 'sileo'
let props: SileoOptions = $props()
let rootEl: HTMLElement
$effect(() => {
const root = createRoot(rootEl)
import('sileo').then(({ Toaster }) => {
const sileo = createElement(Toaster, { ...props })
root.render(sileo)
})
return () => root.unmount()
})
</script>
<div bind:this={rootEl}></div>
+7
View File
@@ -0,0 +1,7 @@
import Root from './switch.svelte';
export {
Root,
//
Root as Switch,
};
@@ -0,0 +1,27 @@
<script lang="ts">
import { Switch as SwitchPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
checked = $bindable(false),
...restProps
}: WithoutChildrenOrChild<SwitchPrimitive.RootProps> = $props();
</script>
<SwitchPrimitive.Root
bind:ref
bind:checked
class={cn(
'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...restProps}
>
<SwitchPrimitive.Thumb
class={cn(
'bg-background pointer-events-none block size-5 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0'
)}
/>
</SwitchPrimitive.Root>
+9 -18
View File
@@ -19,27 +19,18 @@
});
</script>
<div data-tauri-drag-region class="titlebar z-[60] border-b border-theme-800/90">
<div
class="mr-auto ms-2 flex flex-row gap-2 items-center text-[1.05rem] font-semibold pointer-events-none"
>
<img src={Logo} alt="EZPP Launcher Logo" class="h-11 w-11 inline-block" />
<span>EZPPLauncher</span>
<Badge class="!text-[0.6rem] py-[0.5px] bg-primary-500 hover:bg-primary-500"
>{$launcherVersion}</Badge
>
<div data-tauri-drag-region class="titlebar z-[100]">
<div class="titlebar-button rounded transition-colors duration-75" id="titlebar-minimize">
<Minimize size={14} />
</div>
<div class="titlebar-button rounded-lg transition-colors duration-75" id="titlebar-minimize">
<Minimize size={18} />
</div>
<div class="titlebar-button close rounded-lg transition-colors duration-75" id="titlebar-close">
<Close size={18} />
<div class="titlebar-button close rounded transition-colors duration-75" id="titlebar-close">
<Close size={14} />
</div>
</div>
<style lang="scss">
.titlebar {
height: 50px;
height: 35px;
/* background: #040612; */
user-select: none;
display: flex;
@@ -52,14 +43,14 @@
right: 0;
margin-bottom: 10px;
padding-right: 5px;
pointer-events: all !important;
pointer-events: auto;
}
.titlebar-button {
display: inline-flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
width: 25px;
height: 25px;
user-select: none;
-webkit-user-select: none;
}
+4 -2
View File
@@ -44,8 +44,7 @@ export class Config {
this.encrypt && this.crypto ? this.crypto.decrypt(fileStream) : fileStream
) as Record<string, unknown>;
this.config = decryptedJSON;
} catch (err) {
console.log(err);
} catch {
this.config = {};
await this.save();
}
@@ -69,6 +68,9 @@ export class Config {
set: <T>(val: T) => {
this.config[key] = val;
},
exists: () => {
return this.config[key] !== undefined;
},
get: <T>(fallback: T): T => {
return (this.config[key] as T) ?? fallback;
},
+1 -2
View File
@@ -8,8 +8,7 @@ export function estimateRefreshRate(): Promise<number> {
frames++;
if (now - last >= 1000) {
console.log(`Estimated Refresh Rate: ${frames - 2} FPS`);
resolve(frames - 2); // estimated Hz
resolve(frames - 2);
} else {
requestAnimationFrame(loop);
}
+2
View File
@@ -14,6 +14,8 @@ export const newVersion = writable<Release | undefined>(undefined);
export const launcherStreams = writable<string[]>(['stable']);
export const launcherStream = writable<string>('stable');
export const trackingEnabled = writable<boolean>(false);
export const discordPresence = writable<boolean>(false);
export const presenceLoading = writable<boolean>(false);
+1 -2
View File
@@ -3,7 +3,7 @@ import type { UpdateFile, UpdateStatus } from './types';
import { listen } from '@tauri-apps/api/event';
import { betterFetch } from '@better-fetch/fetch';
const updateUrl = 'https://next.ez-pp.farm/api/ezpplauncher';
const updateUrl = 'https://ez-pp.farm/api/ezpplauncher';
export const getHWID = async () => {
const hwid = await invoke('get_hwid');
@@ -82,7 +82,6 @@ export const getEZPPLauncherStreams = async () => {
if (!resp.error) {
return resp.data.streams;
}
return undefined;
};
-1
View File
@@ -44,7 +44,6 @@ export const formatTimeReadable = (initialSeconds: number) => {
};
export const releaseStreamToReadable = (releaseStream: string) => {
console.log(releaseStream.replaceAll(' ', '').toLowerCase());
if (releaseStream.replaceAll(' ', '').toLowerCase() === 'cuttingedge') return 'Cutting Edge';
return 'Stable';
};
+11 -2
View File
@@ -12,6 +12,7 @@
platform,
presenceLoading,
setupValues,
trackingEnabled,
} from '@/global';
import { onMount } from 'svelte';
import OsuCursor from '@/components/ui/osu-cursor/OsuCursor.svelte';
@@ -24,7 +25,7 @@
userSettings,
} from '@/userSettings';
import { Buffer } from 'buffer';
import { Toaster } from '@/components/ui/sonner';
import SileoToast from '@/components/ui/sileo/sileo-toast.svelte';
import { userAuth } from '@/userAuthentication';
import { encryptString, exit, getLauncherVersion, getPlatform } from '@/osuUtil';
import Button from '@/components/ui/button/button.svelte';
@@ -32,6 +33,7 @@
import '@fontsource/sora';
import '@fontsource/space-mono';
import AnimatedBg from '@/components/ui/animated-bg/AnimatedBg.svelte';
let { children } = $props();
@@ -103,6 +105,7 @@
const config_reduce_animations = $userSettings.value('reduce_animations');
const config_osu_installation_path = $userSettings.value('osu_installation_path');
const config_discord_presence = $userSettings.value('discord_presence');
const config_tracking_enabled = $userSettings.value('tracking_consent');
patch.set(config_patching.get(true));
customCursor.set(config_custom_cursor.get(true));
@@ -110,6 +113,9 @@
reduceAnimations.set(config_reduce_animations.get(false));
osuInstallationPath.set(config_osu_installation_path.get(''));
discordPresence.set(config_discord_presence.get(true));
if (config_tracking_enabled.exists()) {
trackingEnabled.set(config_tracking_enabled.get(false));
}
patch.subscribe((val) => config_patching.set(val));
customCursor.subscribe((val) => config_custom_cursor.set(val));
@@ -145,7 +151,7 @@
<OsuCursor smoothCursor={$cursorSmoothening} />
{/if}
<Toaster richColors closeButton />
<SileoToast position="top-center" fill="black" />
<Titlebar />
@@ -173,5 +179,8 @@
</AlertDialog.Root>
<main>
<div class="opacity-30">
<AnimatedBg />
</div>
{@render children()}
</main>
+12 -1
View File
@@ -1,10 +1,21 @@
<script lang="ts">
import { currentView } from '@/global';
import { currentView, launcherVersion, trackingEnabled } from '@/global';
import { fade } from 'svelte/transition';
const View = $derived($currentView);
</script>
<svelte:head>
{#if $launcherVersion !== '' && $trackingEnabled}
<script
defer
src="https://analytics.ez-pp.farm/script.js"
data-website-id="b03f0013-64f0-42ce-85c0-abd56e8b3c64"
data-tag={$launcherVersion}
></script>
{/if}
</svelte:head>
{#key View}
<div in:fade={{ duration: 300 }}>
<View />
+565 -382
View File
File diff suppressed because it is too large Load Diff
+51 -14
View File
@@ -28,7 +28,6 @@
import Launch from './Launch.svelte';
import { currentUser, userAuth } from '@/userAuthentication';
import { ezppfarm } from '@/api/ezpp';
import { toast } from 'svelte-sonner';
import { currentUserInfo } from '@/data';
import {
getBeatmapSetsCount,
@@ -40,6 +39,8 @@
isValidOsuFolder,
} from '@/osuUtil';
import { git } from '@/api/git';
import { sileo } from 'sileo';
import type { EZPPUser } from '@/types';
let ezppLogo: HTMLImageElement;
let spinnerCircle: SVGCircleElement;
@@ -84,25 +85,32 @@
const username = $userAuth.value('username').get('');
const password = $userAuth.value('password').get('');
if (username.length > 0 && password.length > 0) {
const shouldLogin = username.length > 0 && password.length > 0;
let userLoginResult: { message: string; user?: EZPPUser } = {
message: 'An unknown error occured!',
};
if (shouldLogin) {
currentLoadingInfo.set('Logging in...');
try {
const loginResult = await ezppfarm.login(username, password);
if (loginResult && loginResult.user) {
toast.success('Login successful!', {
description: `Welcome back, ${loginResult.user.name}!`,
});
userLoginResult = {
message: `Welcome back, ${loginResult.user.name}!`,
user: loginResult.user,
};
currentUser.set(loginResult.user);
} else {
toast.error('Login failed!', {
description: 'Please check your username and password.',
});
userLoginResult = {
message: 'Please check your username and password.',
};
}
} catch {
toast.error('Server error occurred during login.', {
description: 'There was an issue connecting to the server. Please try again later.',
});
userLoginResult = {
message: 'There was an issue connecting to the server. Please try again later.',
};
}
}
if ($currentUser) {
@@ -123,8 +131,13 @@
osuInstallationPath.set('');
$userSettings.value('osu_installation_path').del();
await $userSettings.save();
toast.error('Oops...', {
sileo.error({
title: 'Hmm...',
description: 'Your previously set osu! installation path seems to be invalid.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
} else {
currentLoadingInfo.set('Getting osu version...');
@@ -174,7 +187,31 @@
});
setTimeout(() => {
if ($firstStartup) currentView.set(SetupWizard);
else currentView.set(Launch);
else {
currentView.set(Launch);
if (shouldLogin) {
if (userLoginResult.user) {
sileo.success({
title: 'Login successful!',
description: userLoginResult.message,
fill: '#181825',
styles: {
description: 'text-center!',
},
duration: 2500,
});
} else {
sileo.error({
title: 'Login failed!',
description: userLoginResult.message,
fill: '#181825',
styles: {
description: 'text-center!',
},
});
}
}
}
}, 250);
};
@@ -202,7 +239,7 @@
});
</script>
<div class="flex flex-col items-center justify-center mt-[50px] h-[calc(100vh-50px)] w-full">
<div class="flex flex-col items-center justify-center h-[100vh] w-full">
<div class="relative w-80 h-80 flex items-center justify-center">
<svg
class="absolute top-0 left-0 w-full h-full animate-spin"
-127
View File
@@ -1,127 +0,0 @@
<script lang="ts">
import Logo from '$assets/logo.png';
import { ezppfarm } from '@/api/ezpp';
import Button from '@/components/ui/button/button.svelte';
import Input from '@/components/ui/input/input.svelte';
import Label from '@/components/ui/label/label.svelte';
import { currentView } from '@/global';
import { currentUser, userAuth } from '@/userAuthentication';
import { animate } from 'animejs';
import { LoaderCircle } from 'lucide-svelte';
import { toast } from 'svelte-sonner';
import Launch from './Launch.svelte';
import { currentUserInfo } from '@/data';
import { preferredMode, preferredType } from '@/userSettings';
let username = $state('');
let password = $state('');
let isLoading = $state(false);
let ezppLogo: HTMLImageElement | undefined = $state(undefined);
const logo_mouseenter = () => {
if (ezppLogo) {
animate(ezppLogo, {
duration: 700,
scale: 1.2,
ease: (t: number) => Math.pow(2, -5 * t) * Math.sin((t - 0.075) * 20.94) + 1 - 0.0005 * t,
});
}
};
const logo_mouseleave = () => {
if (ezppLogo) {
animate(ezppLogo, {
duration: 700,
scale: 1,
ease: (t: number) => (t - 1) ** 7 + 1,
});
}
};
const performLogin = async () => {
isLoading = true;
try {
const loginResult = await ezppfarm.login(username, password);
if (loginResult && loginResult.user) {
toast.success('Login successful!', {
description: `Welcome back, ${loginResult.user.name}!`,
});
$userAuth.value('username').set(username);
$userAuth.value('password').set(password);
await $userAuth.save();
currentUser.set(loginResult.user);
currentView.set(Launch);
} else {
toast.error('Login failed!', {
description: 'Please check your username and password.',
});
isLoading = false;
}
} catch {
toast.error('Server error occurred during login.', {
description: 'There was an issue connecting to the server. Please try again later.',
});
isLoading = false;
}
if ($currentUser) {
const userInfo = await ezppfarm.getUserInfo($currentUser.id);
if (userInfo) {
currentUserInfo.set(userInfo.player);
preferredMode.set(userInfo.player.info.preferred_mode);
preferredType.set(userInfo.player.info.preferred_type);
}
}
};
</script>
<div class="mt-[50px] h-[calc(100vh-50px)] w-full">
<div class="w-full h-full flex flex-col items-center justify-center">
<img
src={Logo}
alt="EZPPLauncher Logo"
class="w-52 h-52 mb-2"
bind:this={ezppLogo}
onmouseenter={logo_mouseenter}
onmouseleave={logo_mouseleave}
/>
<form onsubmit={performLogin} class="w-full max-w-sm">
<div class="mb-4">
<Label for="username" class="block text-sm font-medium">Username</Label>
<Input
class="mt-4 w-full bg-theme-900 border-theme-800"
type="text"
id="username"
bind:value={username}
disabled={isLoading}
autocomplete="off"
autocorrect="off"
/>
</div>
<div class="mb-4">
<Label for="password" class="block text-sm font-medium">Password</Label>
<Input
class="mt-4 w-full bg-theme-900 border-theme-800"
type="password"
id="password"
bind:value={password}
disabled={isLoading}
autocomplete="off"
autocorrect="off"
/>
</div>
<Button class="w-full" type="submit" disabled={isLoading}>
{#if isLoading}
<LoaderCircle class="animate-spin" />
{:else}
Login
{/if}
</Button>
</form>
</div>
</div>
+15 -14
View File
@@ -110,6 +110,7 @@
onMount(async () => {
const osuPath = await autoDetectOsuInstallFolder();
console.log(osuPath);
if (osuPath) {
osuInstallPath = osuPath;
autoDetectedOsuPath = true;
@@ -119,7 +120,7 @@
</script>
{#if wizardFinished}
<div class="relative flex flex-col items-center justify-center mt-[50px] h-[calc(100vh-50px)]">
<div class="relative flex flex-col items-center justify-center h-[100vh] z-50">
<div class="absolute h-fit w-fit top-1/2 left-1/2">
<Confetti amount={200} y={[-1, 1.5]} x={[-2.3, 2.3]} colorArray={['#C6A0F3']} />
</div>
@@ -128,14 +129,14 @@
<Button class="mt-4" onclick={saveConfig}>Finish</Button>
</div>
{:else}
<div class="grid grid-cols-[0.41fr_1fr] mt-[50px] h-[calc(100vh-50px)]">
<div class="w-full h-full border-r border-theme-800/90 flex flex-col gap-6 p-3">
<div class="grid grid-cols-[0.41fr_1fr] h-[100vh] z-50">
<div class="w-full h-full border-r border-theme-800 bg-black/20 backdrop-blur-md flex flex-col gap-6 p-3 z-50">
{#each steps as step, i (step)}
<div
class="flex flex-row items-center gap-2 border {selectedStep === i + 1
? 'border-primary-800/30 bg-primary-900/30'
? 'border-primary-800 bg-primary-900'
: selectedStep > i
? 'border-green-800/30 bg-green-900/30'
? 'border-green-800 bg-green-900'
: 'border-theme-800 bg-theme-900'} rounded-lg p-2 transition-all"
>
<div
@@ -160,10 +161,10 @@
</div>
{/each}
</div>
<div class="flex flex-col gap-6 w-full h-full bg-theme-900/40 p-6">
<div class="flex flex-col gap-6 w-full h-full backdrop-blur-md p-6 z-50">
{#if selectedStep === 1}
<div
class="my-auto h-full w-full bg-theme-800/15 rounded-lg border border-900/60 p-6 flex flex-col items-center justify-center"
class="my-auto h-full w-full bg-black/20 rounded-lg border border-theme-900/20 p-6 mt-5 flex flex-col items-center justify-center"
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
>
<img
@@ -178,13 +179,13 @@
<p class="text-muted-foreground mt-2">
This setup wizard will guide you through the initial setup of EZPPLauncher.
</p>
<div class="bg-red-800/20 border border-red-900/20 text-red-500 p-4 rounded-lg mt-4">
<div class="bg-red-800 border border-red-900 text-red-500 p-4 rounded-lg mt-4">
Please make sure you have osu! installed on your system before proceeding.
</div>
</div>
{:else if selectedStep === 2}
<div
class="my-auto h-full w-full bg-theme-800/15 rounded-lg border border-900/60 p-6 flex flex-col items-center justify-center"
class="my-auto h-full w-full bg-theme-800 rounded-lg border border-theme-900 p-6 mt-5 flex flex-col items-center justify-center"
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
>
<h1 class="text-3xl font-semibold">Locate your osu! Installation</h1>
@@ -207,14 +208,14 @@
{#if !manualSelect}
{#if autoDetectedOsuPath}
<div
class="flex flex-row gap-3 bg-green-800/20 border border-green-900/20 text-green-500 p-4 rounded-lg mt-4"
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
>
<CheckCircle />
<span>Auto-detected osu! installation path! Please check if its correct!</span>
</div>
{:else}
<div
class="flex flex-row gap-3 bg-red-800/20 border border-red-900/20 text-red-500 p-4 rounded-lg mt-4"
class="flex flex-row gap-3 bg-red-800 border border-red-900 text-red-500 p-4 rounded-lg mt-4"
>
<CircleOff />
<span>Could not auto-detect osu! installation path. Please select it manually.</span
@@ -223,14 +224,14 @@
{/if}
{:else if manualSelectValid}
<div
class="flex flex-row gap-3 bg-green-800/20 border border-green-900/20 text-green-500 p-4 rounded-lg mt-4"
class="flex flex-row gap-3 bg-green-800 border border-green-900 text-green-500 p-4 rounded-lg mt-4"
>
<CheckCircle />
<span>Selected osu! installation path is valid!</span>
</div>
{:else}
<div
class="flex flex-row gap-3 bg-red-800/20 border border-red-900/20 text-red-500 p-4 rounded-lg mt-4"
class="flex flex-row gap-3 bg-red-800 border border-red-900 text-red-500 p-4 rounded-lg mt-4"
>
<CircleOff />
<span
@@ -242,7 +243,7 @@
</div>
{:else if selectedStep === 3}
<div
class="bg-theme-900/90 flex flex-col justify-center gap-3 border border-theme-800/90 rounded-lg"
class="bg-theme-900 flex flex-col justify-center gap-3 mt-5 border border-theme-800 rounded-lg"
in:fade={{ duration: $reduceAnimations ? 0 : 200 }}
>
<div class="flex flex-row items-center gap-3 font-semibold text-xl px-3 pt-3">