diff --git a/bun.lock b/bun.lock index 6e9cab1..85698b3 100644 --- a/bun.lock +++ b/bun.lock @@ -28,7 +28,7 @@ "@commitlint/config-conventional": "^21.0.1", "@eslint/js": "^10.0.1", "@tauri-apps/cli": "^2.11.2", - "@types/react": "^19.2.14", + "@types/react": "^19.2.15", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.2", "eslint": "^10.4.0", @@ -217,37 +217,37 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], - "@oxc-project/types": ["@oxc-project/types@0.130.0", "", {}, "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q=="], + "@oxc-project/types": ["@oxc-project/types@0.132.0", "", {}, "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.1", "", { "os": "android", "cpu": "arm64" }, "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.2", "", { "os": "android", "cpu": "arm64" }, "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.1", "", { "os": "none", "cpu": "arm64" }, "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.1", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.2", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.1", "", { "os": "win32", "cpu": "x64" }, "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0", "", {}, "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ=="], @@ -285,9 +285,9 @@ "@tailwindcss/vite": ["@tailwindcss/vite@4.3.0", "", { "dependencies": { "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "tailwindcss": "4.3.0" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw=="], - "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.24", "", { "dependencies": { "@tanstack/virtual-core": "3.14.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-aIJvz5OSkhNIhZIpYivrxrPTKYsjW9Uzy+sP/mx0S3sev2HyvPb7xmjbYvokzEpfgYHy/HjzJ2zFAETuUfgCpg=="], + "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.25", "", { "dependencies": { "@tanstack/virtual-core": "3.15.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-bmNoqMu6gcAW9JGrKVB0Q1tN1i5RONZF8r1fW0bbE4Oyf3DwEGnzzQJ2OW+Ozg1P4s8PyugkHg2ULZoFQN+cqw=="], - "@tanstack/virtual-core": ["@tanstack/virtual-core@3.14.0", "", {}, "sha512-JLANqGy/D6k4Ujmh8Tr25lGimuOXNiaVyXaCAZS0W+1390sADdGnyUdSWNIfd49gebtIxGMij4IktRVzrdr12Q=="], + "@tanstack/virtual-core": ["@tanstack/virtual-core@3.15.0", "", {}, "sha512-0AwPGx0I8QxPYjAxShT/+z+ZOe9u8mW5rsXvivCTjRfRmz9a43+3mRyi4wwlyoUqOC56q/jatKa0Bh9M99BEHQ=="], "@tauri-apps/api": ["@tauri-apps/api@2.11.0", "", {}, "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA=="], @@ -577,7 +577,7 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -601,7 +601,7 @@ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], - "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="], + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], @@ -619,7 +619,7 @@ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "rolldown": ["rolldown@1.0.1", "", { "dependencies": { "@oxc-project/types": "=0.130.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.1", "@rolldown/binding-darwin-arm64": "1.0.1", "@rolldown/binding-darwin-x64": "1.0.1", "@rolldown/binding-freebsd-x64": "1.0.1", "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", "@rolldown/binding-linux-arm64-gnu": "1.0.1", "@rolldown/binding-linux-arm64-musl": "1.0.1", "@rolldown/binding-linux-ppc64-gnu": "1.0.1", "@rolldown/binding-linux-s390x-gnu": "1.0.1", "@rolldown/binding-linux-x64-gnu": "1.0.1", "@rolldown/binding-linux-x64-musl": "1.0.1", "@rolldown/binding-openharmony-arm64": "1.0.1", "@rolldown/binding-wasm32-wasi": "1.0.1", "@rolldown/binding-win32-arm64-msvc": "1.0.1", "@rolldown/binding-win32-x64-msvc": "1.0.1" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ=="], + "rolldown": ["rolldown@1.0.2", "", { "dependencies": { "@oxc-project/types": "=0.132.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.2", "@rolldown/binding-darwin-arm64": "1.0.2", "@rolldown/binding-darwin-x64": "1.0.2", "@rolldown/binding-freebsd-x64": "1.0.2", "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", "@rolldown/binding-linux-arm64-gnu": "1.0.2", "@rolldown/binding-linux-arm64-musl": "1.0.2", "@rolldown/binding-linux-ppc64-gnu": "1.0.2", "@rolldown/binding-linux-s390x-gnu": "1.0.2", "@rolldown/binding-linux-x64-gnu": "1.0.2", "@rolldown/binding-linux-x64-musl": "1.0.2", "@rolldown/binding-openharmony-arm64": "1.0.2", "@rolldown/binding-wasm32-wasi": "1.0.2", "@rolldown/binding-win32-arm64-msvc": "1.0.2", "@rolldown/binding-win32-x64-msvc": "1.0.2" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g=="], "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], @@ -663,7 +663,7 @@ "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], - "vite": ["vite@8.0.13", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.14", "rolldown": "1.0.1", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.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", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw=="], + "vite": ["vite@8.0.14", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.2", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.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", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw=="], "void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="], diff --git a/package.json b/package.json index c45017f..1a164da 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-virtual": "^3.13.24", + "@tanstack/react-virtual": "^3.13.25", "@tauri-apps/api": "^2.11.0", "@tauri-apps/plugin-dialog": "^2.7.1", "@tauri-apps/plugin-opener": "^2.5.4", @@ -52,6 +52,6 @@ "sharp": "^0.34.5", "typescript": "~6.0.3", "typescript-eslint": "^8.59.4", - "vite": "^8.0.13" + "vite": "^8.0.14" } } diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 124c659..10dc5b3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1344,9 +1344,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" dependencies = [ "serde", ] diff --git a/src/components/common/Artwork.tsx b/src/components/common/Artwork.tsx index fd5118f..0b6a7df 100644 --- a/src/components/common/Artwork.tsx +++ b/src/components/common/Artwork.tsx @@ -71,10 +71,16 @@ export function Artwork({ xl: "rounded-xl", "2xl": "rounded-2xl", }[rounded]; - // Gradient + border combo reused as the placeholder background, both - // when no image is available and behind the fading . + // Gradient placeholder reused as the background behind the fading + // . The border is split off because it would otherwise consume + // 2 px inside the wrapper's content box (Tailwind defaults to + // `box-sizing: border-box`), shrinking the visible image by 2 px on + // every Artwork in the app. The border is invisible behind a loaded + // image anyway — keep it only on the no-src placeholder branch. const placeholderBg = - "bg-linear-to-br from-emerald-100 to-emerald-200 dark:from-emerald-900/40 dark:to-emerald-800/30 border border-emerald-200/60 dark:border-emerald-800/40"; + "bg-linear-to-br from-emerald-100 to-emerald-200 dark:from-emerald-900/40 dark:to-emerald-800/30"; + const placeholderBorder = + "border border-emerald-200/60 dark:border-emerald-800/40"; const discIcon = ( +
); } @@ -42,7 +42,7 @@ export function AudioQualityFooter({ track }: AudioQualityFooterProps) { const hiRes = isHiRes(track.bit_depth, track.sample_rate); return ( -
+
{leftBits.join(" · ")} {hiRes && ( diff --git a/src/components/player/PlaybackControls.tsx b/src/components/player/PlaybackControls.tsx index ed82941..d757ebf 100644 --- a/src/components/player/PlaybackControls.tsx +++ b/src/components/player/PlaybackControls.tsx @@ -34,7 +34,7 @@ export function PlaybackControls() { const isRepeatActive = repeatMode !== "off"; return ( -
+
); diff --git a/src/components/player/PlayerBar.tsx b/src/components/player/PlayerBar.tsx index f51eca0..2a1f82f 100644 --- a/src/components/player/PlayerBar.tsx +++ b/src/components/player/PlayerBar.tsx @@ -53,6 +53,10 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { // we re-read without polling. const [pinSleepTimer, setPinSleepTimer] = useState(false); const [pinAbLoop, setPinAbLoop] = useState(false); + // Audio quality strip (kHz / kbps / codec / bit depth) — hidden by + // default so the bar stays slim, opt-in via Settings. Same dispatch + // pattern as the other UI toggles above. + const [showAudioQualityFooter, setShowAudioQualityFooter] = useState(false); useEffect(() => { const refreshSleep = () => { getProfileSetting("ui.show_sleep_timer") @@ -69,16 +73,35 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { }) .catch(() => {}); }; + const refreshAudioQuality = () => { + getProfileSetting("ui.show_audio_quality_footer") + .then((v) => { + // Missing key → off (slim bar by default). + setShowAudioQualityFooter( + v == null ? false : v === "1" || v === "true", + ); + }) + .catch(() => {}); + }; refreshSleep(); refreshAb(); + refreshAudioQuality(); window.addEventListener("waveflow:sleep-timer-visibility", refreshSleep); window.addEventListener("waveflow:ab-loop-visibility", refreshAb); + window.addEventListener( + "waveflow:audio-quality-footer-visibility", + refreshAudioQuality, + ); return () => { window.removeEventListener( "waveflow:sleep-timer-visibility", refreshSleep, ); window.removeEventListener("waveflow:ab-loop-visibility", refreshAb); + window.removeEventListener( + "waveflow:audio-quality-footer-visibility", + refreshAudioQuality, + ); }; }, []); @@ -141,9 +164,9 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { return ( <>
-
+
{/* Left: Track Info */} -
+
{/* Click the cover to open the immersive Now Playing overlay (mirrors Apple Music). Disabled when no track is loaded so the user doesn't open an empty card. */} @@ -160,7 +183,7 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { path1x={currentTrack?.artwork_path_1x ?? null} path2x={currentTrack?.artwork_path_2x ?? null} size="1x" - className="w-14 h-14 shadow-sm border border-zinc-200 dark:border-transparent" + className="w-14 h-14 shadow-sm" iconSize={24} alt={title} rounded="xl" @@ -187,13 +210,13 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { type="button" onClick={handleToggleLike} aria-label={isLiked ? t("liked.unlike") : t("liked.like")} - className={`p-1.5 rounded-full transition-colors shrink-0 ${ + className={`p-2 rounded-full transition-colors shrink-0 ${ isLiked ? "text-pink-500" : "text-zinc-300 dark:text-zinc-600 hover:text-pink-500" }`} > - + )}
@@ -205,7 +228,7 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) {
{/* Right: Extra Controls */} -
+
{/* A-B repeat (primary slot — opt-in pin via Settings). When unpinned, the entry lives in the "..." menu so the bar stays calm by default. */} @@ -257,7 +280,7 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { aria-label={t("playerBar.devices")} title={t("playerBar.devices")} aria-expanded={isDeviceMenuOpen} - className={`p-2 rounded-lg transition-colors border ${ + className={`p-1.5 rounded-lg transition-colors border ${ isDeviceMenuOpen ? "border-emerald-500 text-emerald-500 bg-emerald-500/10" : "border-transparent text-zinc-400 hover:text-zinc-800 dark:hover:text-white hover:bg-zinc-100 dark:hover:bg-zinc-800" @@ -303,7 +326,7 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { }} aria-label={t("playerBar.miniPlayer")} title={t("playerBar.miniPlayer")} - className="p-2 rounded-lg text-zinc-400 hover:text-zinc-800 dark:hover:text-white transition-colors" + className="p-1.5 rounded-lg text-zinc-400 hover:text-zinc-800 dark:hover:text-white transition-colors" > @@ -315,13 +338,17 @@ export function PlayerBar({ onNavigateToArtist }: PlayerBarProps) { disabled={!currentTrack} aria-label={t("playerBar.openFullscreen")} title={t("playerBar.openFullscreen")} - className="p-2 rounded-lg text-zinc-400 hover:text-zinc-800 dark:hover:text-white transition-colors disabled:opacity-40 disabled:cursor-not-allowed" + className="p-1.5 rounded-lg text-zinc-400 hover:text-zinc-800 dark:hover:text-white transition-colors disabled:opacity-40 disabled:cursor-not-allowed" >
- + {showAudioQualityFooter && ( + + )}
{isFullscreenOpen && currentTrack && ( {}); + getProfileSetting("ui.show_audio_quality_footer") + .then((v) => { + if (cancelled) return; + // Missing key → off (matches PlayerBar default). + if (v != null) setShowAudioQualityFooter(v === "true" || v === "1"); + }) + .catch(() => {}); getProfileSetting("ui.show_spotify") .then((v) => { if (cancelled) return; @@ -537,6 +548,25 @@ export function SettingsView({ onNavigate }: SettingsViewProps) { }); }, [showAbLoop]); + const handleToggleShowAudioQualityFooter = useCallback(() => { + const next = !showAudioQualityFooter; + setShowAudioQualityFooter(next); + setProfileSetting( + "ui.show_audio_quality_footer", + next ? "true" : "false", + "bool", + ) + .then(() => { + window.dispatchEvent( + new CustomEvent("waveflow:audio-quality-footer-visibility"), + ); + }) + .catch((err) => { + console.error("[Settings] set show_audio_quality_footer failed", err); + setShowAudioQualityFooter(!next); + }); + }, [showAudioQualityFooter]); + const handleToggleAutoStart = useCallback(() => { const next = !autoStart; setAutoStart(next); @@ -1555,6 +1585,26 @@ export function SettingsView({ onNavigate }: SettingsViewProps) { />
+ {/* Visibilité du bandeau qualité audio sous la player bar */} +
+
+
+ +
+ {/* Visibilité de l'entrée Spotify dans la sidebar */}
diff --git a/src/i18n/locales/ar.json b/src/i18n/locales/ar.json index 257aa12..77e93f2 100644 --- a/src/i18n/locales/ar.json +++ b/src/i18n/locales/ar.json @@ -1333,6 +1333,10 @@ "decreaseAria": "تصغير", "increaseAria": "تكبير", "resetAria": "إعادة التكبير إلى 100 %" + }, + "showAudioQualityFooter": { + "title": "إظهار شريط جودة الصوت", + "subtitle": "تفاصيل تقنية (kHz، kbps، الترميز، عمق البت) أسفل شريط المشغل. معطل افتراضيًا للحفاظ على شريط أنحف." } }, "scanProgress": { diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 7e06048..f816270 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Verkleinern", "increaseAria": "Vergrößern", "resetAria": "Zoom auf 100 % zurücksetzen" + }, + "showAudioQualityFooter": { + "title": "Audioqualitätsleiste anzeigen", + "subtitle": "Technische Details (kHz, kbps, Codec, Bittiefe) unter der Player-Leiste. Standardmäßig aus für eine schlankere Leiste." } }, "scanProgress": { diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 1fa9de7..af18d65 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1395,6 +1395,10 @@ "decreaseAria": "Zoom out", "increaseAria": "Zoom in", "resetAria": "Reset zoom to 100 %" + }, + "showAudioQualityFooter": { + "title": "Show audio quality strip", + "subtitle": "Technical details (kHz, kbps, codec, bit depth) under the player bar. Off by default for a slimmer bar." } }, "spotify": { diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 963f3ba..a88e92f 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Reducir zoom", "increaseAria": "Aumentar zoom", "resetAria": "Restablecer al 100 %" + }, + "showAudioQualityFooter": { + "title": "Mostrar tira de calidad de audio", + "subtitle": "Detalles técnicos (kHz, kbps, códec, profundidad) bajo la barra de reproducción. Desactivado por defecto para una barra más fina." } }, "scanProgress": { diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 9298467..7870039 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1395,6 +1395,10 @@ "decreaseAria": "Dézoomer l’interface", "increaseAria": "Zoomer l’interface", "resetAria": "Réinitialiser le zoom à 100 %" + }, + "showAudioQualityFooter": { + "title": "Afficher la qualité audio sous la barre", + "subtitle": "Détails techniques (kHz, kb/s, codec, profondeur) sous la player bar. Désactivé par défaut pour une barre plus fine." } }, "spotify": { diff --git a/src/i18n/locales/hi.json b/src/i18n/locales/hi.json index cd85f7d..bd6f918 100644 --- a/src/i18n/locales/hi.json +++ b/src/i18n/locales/hi.json @@ -1329,6 +1329,10 @@ "decreaseAria": "ज़ूम घटाएं", "increaseAria": "ज़ूम बढ़ाएं", "resetAria": "ज़ूम को 100 % पर रीसेट करें" + }, + "showAudioQualityFooter": { + "title": "ऑडियो गुणवत्ता पट्टी दिखाएं", + "subtitle": "प्लेयर बार के नीचे तकनीकी विवरण (kHz, kbps, कोडेक, बिट डेप्थ)। पतले बार के लिए डिफ़ॉल्ट रूप से बंद।" } }, "scanProgress": { diff --git a/src/i18n/locales/id.json b/src/i18n/locales/id.json index 86402db..28db2a7 100644 --- a/src/i18n/locales/id.json +++ b/src/i18n/locales/id.json @@ -1328,6 +1328,10 @@ "decreaseAria": "Perkecil", "increaseAria": "Perbesar", "resetAria": "Reset zoom ke 100 %" + }, + "showAudioQualityFooter": { + "title": "Tampilkan strip kualitas audio", + "subtitle": "Detail teknis (kHz, kbps, codec, kedalaman bit) di bawah bilah pemutar. Mati secara default untuk bilah yang lebih ramping." } }, "scanProgress": { diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 2231478..050b201 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Riduci zoom", "increaseAria": "Aumenta zoom", "resetAria": "Ripristina al 100 %" + }, + "showAudioQualityFooter": { + "title": "Mostra la striscia di qualità audio", + "subtitle": "Dettagli tecnici (kHz, kbps, codec, profondità) sotto la player bar. Disattivato di default per una barra più sottile." } }, "scanProgress": { diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 2dd4dbe..24a212b 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1328,6 +1328,10 @@ "decreaseAria": "縮小", "increaseAria": "拡大", "resetAria": "ズームを 100 % にリセット" + }, + "showAudioQualityFooter": { + "title": "オーディオ品質バーを表示", + "subtitle": "プレイヤーバー下に技術詳細(kHz、kbps、コーデック、ビット深度)を表示。スリムなバーを保つため既定でオフ。" } }, "scanProgress": { diff --git a/src/i18n/locales/ko.json b/src/i18n/locales/ko.json index 47a40c8..a24767a 100644 --- a/src/i18n/locales/ko.json +++ b/src/i18n/locales/ko.json @@ -1328,6 +1328,10 @@ "decreaseAria": "축소", "increaseAria": "확대", "resetAria": "확대/축소를 100 %로 재설정" + }, + "showAudioQualityFooter": { + "title": "오디오 품질 바 표시", + "subtitle": "플레이어 바 아래에 기술 정보(kHz, kbps, 코덱, 비트 깊이)를 표시합니다. 슬림한 바를 위해 기본값은 꺼짐입니다." } }, "scanProgress": { diff --git a/src/i18n/locales/nl.json b/src/i18n/locales/nl.json index c2d7b8b..04ea427 100644 --- a/src/i18n/locales/nl.json +++ b/src/i18n/locales/nl.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Uitzoomen", "increaseAria": "Inzoomen", "resetAria": "Zoom terugzetten op 100 %" + }, + "showAudioQualityFooter": { + "title": "Audiokwaliteitsbalk tonen", + "subtitle": "Technische details (kHz, kbps, codec, bitdiepte) onder de afspeelbalk. Standaard uit voor een slankere balk." } }, "scanProgress": { diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index cb335fe..9fce115 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Diminuir zoom", "increaseAria": "Aumentar zoom", "resetAria": "Redefinir para 100 %" + }, + "showAudioQualityFooter": { + "title": "Mostrar faixa de qualidade de áudio", + "subtitle": "Detalhes técnicos (kHz, kbps, codec, profundidade) sob a barra do player. Desativado por padrão para uma barra mais fina." } }, "scanProgress": { diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 6eb7246..0749624 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -1329,6 +1329,10 @@ "decreaseAria": "Diminuir zoom", "increaseAria": "Aumentar zoom", "resetAria": "Repor para 100 %" + }, + "showAudioQualityFooter": { + "title": "Mostrar faixa de qualidade de áudio", + "subtitle": "Detalhes técnicos (kHz, kbps, codec, profundidade) sob a barra do leitor. Desativado por padrão para uma barra mais fina." } }, "scanProgress": { diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index a0c0701..ee9c59f 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -1331,6 +1331,10 @@ "decreaseAria": "Уменьшить", "increaseAria": "Увеличить", "resetAria": "Сбросить масштаб до 100 %" + }, + "showAudioQualityFooter": { + "title": "Показывать полосу качества аудио", + "subtitle": "Технические данные (кГц, кбит/с, кодек, разрядность) под панелью плеера. По умолчанию выключено для более компактной панели." } }, "scanProgress": { diff --git a/src/i18n/locales/tr.json b/src/i18n/locales/tr.json index 31df74f..5d3bcf0 100644 --- a/src/i18n/locales/tr.json +++ b/src/i18n/locales/tr.json @@ -1328,6 +1328,10 @@ "decreaseAria": "Uzaklaştır", "increaseAria": "Yakınlaştır", "resetAria": "Yakınlaştırmayı %100'e sıfırla" + }, + "showAudioQualityFooter": { + "title": "Ses kalitesi şeridini göster", + "subtitle": "Teknik ayrıntılar (kHz, kbps, codec, bit derinliği) oynatıcı çubuğunun altında. Daha ince bir çubuk için varsayılan olarak kapalı." } }, "scanProgress": { diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 9ac9548..1fb9b58 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -1328,6 +1328,10 @@ "decreaseAria": "缩小", "increaseAria": "放大", "resetAria": "重置缩放为 100 %" + }, + "showAudioQualityFooter": { + "title": "显示音频质量条", + "subtitle": "在播放栏下方显示技术详情(kHz、kbps、编解码、位深)。为保持播放栏轻巧,默认关闭。" } }, "scanProgress": { diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 7425908..ad1a42a 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -1328,6 +1328,10 @@ "decreaseAria": "縮小", "increaseAria": "放大", "resetAria": "重置縮放為 100 %" + }, + "showAudioQualityFooter": { + "title": "顯示音訊品質列", + "subtitle": "在播放列下方顯示技術詳情(kHz、kbps、編解碼、位元深度)。為保持播放列輕巧,預設關閉。" } }, "scanProgress": {