diff --git a/bun.lock b/bun.lock index ebda629..5f506ce 100644 --- a/bun.lock +++ b/bun.lock @@ -216,33 +216,33 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.6", "", { "os": "win32", "cpu": "x64" }, "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.2", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.2" } }, "sha512-ZwFnxH+1z8Ehh8bNTMX3YFrYdzAv7JLY5X5X7XSFY+G9QGJVce/P9xb2mh+j5hKt8NceuHmdtllJvAHWKtsNrQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.3", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.3" } }, "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.2", "@tailwindcss/oxide-darwin-arm64": "4.1.2", "@tailwindcss/oxide-darwin-x64": "4.1.2", "@tailwindcss/oxide-freebsd-x64": "4.1.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.2", "@tailwindcss/oxide-linux-arm64-musl": "4.1.2", "@tailwindcss/oxide-linux-x64-gnu": "4.1.2", "@tailwindcss/oxide-linux-x64-musl": "4.1.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.2", "@tailwindcss/oxide-win32-x64-msvc": "4.1.2" } }, "sha512-Zwz//1QKo6+KqnCKMT7lA4bspGfwEgcPAHlSthmahtgrpKDfwRGk8PKQrW8Zg/ofCDIlg6EtjSTKSxxSufC+CQ=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.3", "@tailwindcss/oxide-darwin-arm64": "4.1.3", "@tailwindcss/oxide-darwin-x64": "4.1.3", "@tailwindcss/oxide-freebsd-x64": "4.1.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", "@tailwindcss/oxide-linux-x64-musl": "4.1.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" } }, "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.2", "", { "os": "android", "cpu": "arm64" }, "sha512-IxkXbntHX8lwGmwURUj4xTr6nezHhLYqeiJeqa179eihGv99pRlKV1W69WByPJDQgSf4qfmwx904H6MkQqTA8w=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.3", "", { "os": "android", "cpu": "arm64" }, "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZRtiHSnFYHb4jHKIdzxlFm6EDfijTCOT4qwUhJ3GWxfDoW2yT3z/y8xg0nE7e72unsmSj6dtfZ9Y5r75FIrlpA=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BiKUNZf1A0pBNzndBvnPnBxonCY49mgbOsPfILhcCE5RM7pQlRoOgN7QnwNhY284bDbfQSEOWnFR0zbPo6IDTw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Z30VcpUfRGkiddj4l5NRCpzbSGjhmmklVoqkVQdkEC0MOelpY+fJrVhzSaXHmWrmSvnX8yiaEqAbdDScjVujYQ=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.2", "", { "os": "linux", "cpu": "arm" }, "sha512-w3wsK1ChOLeQ3gFOiwabtWU5e8fY3P1Ss8jR3IFIn/V0va3ir//hZ8AwURveS4oK1Pu6b8i+yxesT4qWnLVUow=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3", "", { "os": "linux", "cpu": "arm" }, "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oY/u+xJHpndTj7B5XwtmXGk8mQ1KALMfhjWMMpE8pdVAznjJsF5KkCceJ4Fmn5lS1nHMCwZum5M3/KzdmwDMdw=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-k7G6vcRK/D+JOWqnKzKN/yQq1q4dCkI49fMoLcfs2pVcaUAXEqCP9NmA8Jv+XahBv5DtDjSAY3HJbjosEdKczg=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-fLL+c678TkYKgkDLLNxSjPPK/SzTec7q/E5pTwvpTqrth867dftV4ezRyhPM5PaiCqX651Y8Yk0wRQMcWUGnmQ=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0tU1Vjd1WucZ2ooq6y4nI9xyTSaH2g338bhrqk+2yzkMHskBm+pMsOCfY7nEIvALkA1PKPOycR4YVdlV7Czo+A=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-r8QaMo3QKiHqUcn+vXYCypCEha+R0sfYxmaZSgZshx9NfkY+CHz91aS2xwNV/E4dmUDkTPUag7sSdiCHPzFVTg=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-lYCdkPxh9JRHXoBsPE8Pu/mppUsC2xihYArNAESub41PKhHTnvn6++5RpmFM+GLSt3ewyS8fwCVvht7ulWm6cw=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.3", "", { "os": "win32", "cpu": "x64" }, "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.1.2", "", { "dependencies": { "@tailwindcss/node": "4.1.2", "@tailwindcss/oxide": "4.1.2", "tailwindcss": "4.1.2" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-3r/ZdMW0gxY8uOx1To0lpYa4coq4CzINcCX4laM1rS340Kcn0ac4A/MMFfHN8qba51aorZMYwMcOxYk4wJ9FYg=="], + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.3", "", { "dependencies": { "@tailwindcss/node": "4.1.3", "@tailwindcss/oxide": "4.1.3", "tailwindcss": "4.1.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ=="], "@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="], @@ -292,7 +292,7 @@ "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "@types/node": ["@types/node@22.14.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA=="], + "@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/type-utils": "8.29.0", "@typescript-eslint/utils": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ=="], @@ -602,7 +602,7 @@ "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="], - "pinia": ["pinia@3.0.1", "", { "dependencies": { "@vue/devtools-api": "^7.7.2" }, "peerDependencies": { "typescript": ">=4.4.4", "vue": "^2.7.0 || ^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg=="], + "pinia": ["pinia@3.0.2", "", { "dependencies": { "@vue/devtools-api": "^7.7.2" }, "peerDependencies": { "typescript": ">=4.4.4", "vue": "^2.7.0 || ^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g=="], "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], @@ -706,7 +706,7 @@ "sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="], - "tailwindcss": ["tailwindcss@4.1.2", "", {}, "sha512-VCsK+fitIbQF7JlxXaibFhxrPq4E2hDcG8apzHUdWFMCQWD8uLdlHg4iSkZ53cgLCCcZ+FZK7vG8VjvLcnBgKw=="], + "tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="], "tailwindcss-primeui": ["tailwindcss-primeui@0.4.0", "", { "peerDependencies": { "tailwindcss": ">=3.1.0" } }, "sha512-YYC7B7Yyzm1/4pEGgpf1ABAhbrKY++LuPoUamnKE7fTPO5Ct/Qr/dT+Uq2yiVhQnaW1zHQpYnThxfksaxhlDfQ=="], @@ -722,7 +722,7 @@ "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], - "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], "typescript-eslint": ["typescript-eslint@8.29.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.29.0", "@typescript-eslint/parser": "8.29.0", "@typescript-eslint/utils": "8.29.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg=="], @@ -744,7 +744,7 @@ "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="], - "vite": ["vite@6.2.5", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA=="], + "vite": ["vite@6.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw=="], "vite-plugin-vuetify": ["vite-plugin-vuetify@2.1.1", "", { "dependencies": { "@vuetify/loader-shared": "^2.1.0", "debug": "^4.3.3", "upath": "^2.0.1" }, "peerDependencies": { "vite": ">=5", "vue": "^3.0.0", "vuetify": "^3.0.0" } }, "sha512-Pb7bKhQH8qPMzURmEGq2aIqCJkruFNsyf1NcrrtnjsOIkqJPMcBbiP0oJoO8/uAmyB5W/1JTbbUEsyXdMM0QHQ=="], @@ -756,7 +756,7 @@ "vue-tsc": ["vue-tsc@2.2.8", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.8" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ=="], - "vuetify": ["vuetify@3.8.0", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=2.1.0", "vue": "^3.5.0", "webpack-plugin-vuetify": ">=3.1.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-ROC0Xq2G/25ZyUpQMhaynMyXZBJY1WbOGlqOB810yubp8hfY8RlrOw+mzXJonOq6jylCY32muQ9xiJF1JPTLVA=="], + "vuetify": ["vuetify@3.8.1", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=2.1.0", "vue": "^3.5.0", "webpack-plugin-vuetify": ">=3.1.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-3qReKBBWIIdJJmwnFU1blVIKHDtnLfIP7kk0MwUrrfjYkWmsDpsymtDnsukkTCnlJ1WvhLr64eQFosr0RVbj9w=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], diff --git a/package.json b/package.json index 93eff8a..b9c6fcc 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@mdi/font": "7.4.47", "@primevue/forms": "^4.3.3", "@primevue/themes": "^4.3.3", - "@tailwindcss/vite": "^4.1.2", + "@tailwindcss/vite": "^4.1.3", "@tauri-apps/api": "^2.4.1", "@tauri-apps/plugin-cli": "^2.2.0", "@tauri-apps/plugin-deep-link": "~2.2.1", @@ -23,29 +23,29 @@ "@tauri-apps/plugin-shell": "~2.2.1", "@tauri-apps/plugin-updater": "^2.7.0", "@trivago/prettier-plugin-sort-imports": "^5.2.2", - "pinia": "^3.0.1", + "pinia": "^3.0.2", "primeicons": "^7.0.0", "primevue": "^4.3.3", "roboto-fontface": "^0.10.0", - "tailwindcss": "^4.1.2", + "tailwindcss": "^4.1.3", "tailwindcss-primeui": "^0.4.0", "vue": "^3.5.13", - "vuetify": "^3.8.0" + "vuetify": "^3.8.1" }, "devDependencies": { "@tauri-apps/cli": "^2.4.1", "@tsconfig/node22": "^22.0.1", - "@types/node": "^22.14.0", + "@types/node": "^22.14.1", "@vitejs/plugin-vue": "^5.2.3", "@vue/eslint-config-typescript": "^14.5.0", "@vue/tsconfig": "^0.5.1", "npm-run-all2": "^7.0.2", "sass": "1.77.8", "sass-embedded": "^1.86.3", - "typescript": "^5.8.2", + "typescript": "^5.8.3", "unplugin-fonts": "^1.3.1", "unplugin-vue-components": "^0.27.5", - "vite": "^6.2.5", + "vite": "^6.2.6", "vite-plugin-vuetify": "^2.1.1", "vue-tsc": "^2.2.8" } diff --git a/rust/src/model/misc.rs b/rust/src/model/misc.rs index ebb4832..cf9f300 100644 --- a/rust/src/model/misc.rs +++ b/rust/src/model/misc.rs @@ -66,7 +66,7 @@ impl Game { pub fn has_module(&self, module: ProfileModule) -> bool { match self { Game::Ongeki => make_bitflags!(ProfileModule::{Segatools | Display | Network | BepInEx | Mu3Ini | Keyboard}), - Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Network | Keyboard}), + Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Display | Network | Keyboard | Mempatcher}), }.contains(module) } } diff --git a/rust/src/model/patch.rs b/rust/src/model/patch.rs index 25bc4bf..be45619 100644 --- a/rust/src/model/patch.rs +++ b/rust/src/model/patch.rs @@ -58,6 +58,7 @@ pub struct NormalPatchField { #[derive(Deserialize, Serialize, Clone, Debug)] pub struct NumberPatch { pub offset: u64, + pub default: i32, pub size: i64, pub min: i32, pub max: i32 @@ -77,6 +78,7 @@ impl Serialize for Patch { PatchData::Number(patch) => { state.serialize_field("type", "number")?; state.serialize_field("offset", &patch.offset)?; + state.serialize_field("default", &patch.default)?; state.serialize_field("size", &patch.size)?; state.serialize_field("min", &patch.min)?; state.serialize_field("max", &patch.max)?; @@ -95,6 +97,10 @@ impl<'de> serde::Deserialize<'de> for Patch { offset: value.get("offset") .and_then(Value::as_u64) .ok_or_else(|| de::Error::missing_field("offset"))?, + default: i32::try_from(value.get("default") + .and_then(Value::as_i64) + .ok_or_else(|| de::Error::missing_field("default"))? + ).map_err(|_| de::Error::missing_field("default"))?, size: value.get("size") .and_then(Value::as_i64) .ok_or_else(|| de::Error::missing_field("size"))?, diff --git a/rust/src/model/profile.rs b/rust/src/model/profile.rs index edbe6ec..e93a6e0 100644 --- a/rust/src/model/profile.rs +++ b/rust/src/model/profile.rs @@ -74,7 +74,7 @@ pub struct Display { pub target: String, pub rez: (i32, i32), pub mode: DisplayMode, - pub rotation: i32, + pub rotation: Option, pub frequency: i32, pub borderless_fullscreen: bool, @@ -94,7 +94,7 @@ impl Display { Game::Ongeki => (1080, 1920), }, mode: DisplayMode::Borderless, - rotation: 0, + rotation: None, frequency: match game { Game::Chunithm => 120, Game::Ongeki => 60, @@ -232,7 +232,7 @@ pub enum Keyboard { } #[bitflags] -#[repr(u8)] +#[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum ProfileModule { Segatools, @@ -241,4 +241,5 @@ pub enum ProfileModule { BepInEx, Mu3Ini, Keyboard, + Mempatcher } \ No newline at end of file diff --git a/rust/src/modules/display_windows.rs b/rust/src/modules/display_windows.rs index 9c2729a..b201da3 100644 --- a/rust/src/modules/display_windows.rs +++ b/rust/src/modules/display_windows.rs @@ -1,6 +1,7 @@ -use crate::model::profile::{Display, DisplayMode}; +use crate::{model::{misc::Game, profile::{Display, DisplayMode}}, util::bool_to_01}; use anyhow::Result; use displayz::{query_displays, DisplaySet}; +use ini::Ini; use tauri::{AppHandle, Listener}; #[derive(Clone)] @@ -30,7 +31,7 @@ impl Display { }); } - pub fn line_up(&self) -> Result> { + pub fn prepare(&self) -> Result> { use anyhow::anyhow; use displayz::{query_displays, Orientation, Resolution, Frequency}; @@ -63,11 +64,23 @@ impl Display { set: Some(display_set.clone()), }; - if self.rotation == 90 || self.rotation == 270 { + if let Some(rotation) = self.rotation { let rez = settings.borrow_mut().resolution; - settings.borrow_mut().orientation = if self.rotation == 90 { Orientation::PortraitFlipped } else { Orientation::Portrait }; + settings.borrow_mut().orientation = match rotation { + 0 => Orientation::Landscape, + 90 => Orientation::PortraitFlipped, + 180 => Orientation::LandscapeFlipped, + 270 => Orientation::Portrait, + _ => panic!("Invalid display rotation") + }; if rez.height < rez.width { - settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width); + if rotation == 90 || rotation == 270 { + settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width); + } + } else { + if rotation == 0 || rotation == 180 { + settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width); + } } } @@ -99,6 +112,20 @@ impl Display { Ok(Some(res)) } + pub fn line_up(&self, game: Game, ini: &mut Ini) { + if game == Game::Chunithm { + let autism = self.monitor_index_override.unwrap_or(0).to_string(); + ini.with_section(Some("gfx")) + .set("enable", "1") + .set("windowed", bool_to_01(self.mode != DisplayMode::Fullscreen)) + .set("framed", bool_to_01(self.mode == DisplayMode::Window)) + .set("monitor", if self.dont_switch_primary { &autism } else { "0" }); + ini.with_section(Some("system")) + .set("dipsw2", bool_to_01(self.frequency == 60)) + .set("dipsw3", bool_to_01(self.frequency == 60)); + } + } + pub fn clean_up(info: &DisplayInfo) -> Result<()> { use anyhow::anyhow; diff --git a/rust/src/modules/mempatcher.rs b/rust/src/modules/mempatcher.rs new file mode 100644 index 0000000..e69de29 diff --git a/rust/src/modules/mod.rs b/rust/src/modules/mod.rs index eca6bde..c17bc6f 100644 --- a/rust/src/modules/mod.rs +++ b/rust/src/modules/mod.rs @@ -4,6 +4,7 @@ pub mod network; pub mod bepinex; pub mod mu3ini; pub mod keyboard; +pub mod mempatcher; #[cfg(target_os = "windows")] pub mod display_windows; \ No newline at end of file diff --git a/rust/src/profiles/mod.rs b/rust/src/profiles/mod.rs index 7245871..776c865 100644 --- a/rust/src/profiles/mod.rs +++ b/rust/src/profiles/mod.rs @@ -72,7 +72,7 @@ impl Profile { mods: BTreeSet::new(), sgt: Segatools::default_for(meta.game), #[cfg(target_os = "windows")] - display: if meta.game == Game::Ongeki { Some(Display::default_for(meta.game)) } else { None }, + display: Some(Display::default_for(meta.game)), #[cfg(not(target_os = "windows"))] display: None, network: Network::default(), @@ -120,6 +120,9 @@ impl Profile { if data.patches.is_none() { data.patches = Some(PatchSelection(BTreeMap::new())); } + if data.display.is_none() { + data.display = Some(Display::default_for(Game::Chunithm)); + } } Ok(Profile { @@ -205,7 +208,7 @@ impl Profile { pub async fn line_up(&self, pkg_hash: String, refresh: bool, _app: AppHandle) -> Result<()> { let info = match &self.data.display { None => None, - Some(display) => display.line_up()? + Some(display) => display.prepare()? }; let res = self.line_up_the_rest(pkg_hash, refresh).await; @@ -238,6 +241,10 @@ impl Profile { .map_err(|e| anyhow!("segatools configuration failed:\n{:?}", e))?; self.data.network.line_up(&mut ini)?; + if let Some(display) = &self.data.display { + display.line_up(self.meta.game, &mut ini); + } + if let Some(keyboard) = &self.data.keyboard { keyboard.line_up(&mut ini)?; } @@ -305,24 +312,30 @@ impl Profile { "INOHARA_CONFIG_PATH", self.config_dir().join("inohara.cfg"), ) + .env( + "SAEKAWA_CONFIG_PATH", + self.config_dir().join("saekawa.toml"), + ) .current_dir(&exe_dir) .args(["-d", "-k"]) .arg(sgt_dir.join(self.meta.game.hook_exe())) .arg(self.meta.game.exe()); - if let Some(display) = &self.data.display { - if display.dont_switch_primary && display.target != "default" { - game_builder.args(["-monitor", &display.monitor_index_override.unwrap_or_else(|| 1).to_string()]); - } else { - game_builder.args(["-monitor", "1"]); - } - game_builder.args([ - "-screen-width", &display.rez.0.to_string(), - "-screen-height", &display.rez.1.to_string(), - "-screen-fullscreen", if display.mode == DisplayMode::Fullscreen { "1" } else { "0" } - ]); - if display.mode == DisplayMode::Borderless { - game_builder.arg("-popupwindow"); + if self.meta.game.has_module(ProfileModule::BepInEx) { + if let Some(display) = &self.data.display { + if display.dont_switch_primary && display.target != "default" { + game_builder.args(["-monitor", &display.monitor_index_override.unwrap_or_else(|| 1).to_string()]); + } else { + game_builder.args(["-monitor", "1"]); + } + game_builder.args([ + "-screen-width", &display.rez.0.to_string(), + "-screen-height", &display.rez.1.to_string(), + "-screen-fullscreen", if display.mode == DisplayMode::Fullscreen { "1" } else { "0" } + ]); + if display.mode == DisplayMode::Borderless { + game_builder.arg("-popupwindow"); + } } } diff --git a/rust/src/util.rs b/rust/src/util.rs index c367354..00147be 100644 --- a/rust/src/util.rs +++ b/rust/src/util.rs @@ -150,4 +150,8 @@ impl PathStr for PathBuf { fn stringify(&self) -> Result { path_to_str(&self) } +} + +pub fn bool_to_01(val: bool) -> &'static str { + return if val { "1" } else { "0" } } \ No newline at end of file diff --git a/rust/static/segatools-chunithm.ini b/rust/static/segatools-chunithm.ini index a29a927..3c6d17b 100644 --- a/rust/static/segatools-chunithm.ini +++ b/rust/static/segatools-chunithm.ini @@ -15,26 +15,11 @@ freeplay=0 ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 -; Monitor type: 0 = 120FPS, 1 = 60FPS -dipsw2=1 -; Cab type: 0 = SP, 1 = CVT. SP will enable VFD and eMoney. This setting will switch -; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well. -dipsw3=1 ; ----------------------------------------------------------------------------- ; Misc. hooks settings ; ----------------------------------------------------------------------------- -[gfx] -; Enables the graphics hook. -enable=1 -; Force the game to run windowed. -windowed=1 -; Add a frame to the game window if running windowed. -framed=0 -; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) -monitor=0 - ; ----------------------------------------------------------------------------- ; LED settings ; ----------------------------------------------------------------------------- diff --git a/src/components/App.vue b/src/components/App.vue index 2b3a793..51a20e0 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -5,6 +5,7 @@ import ConfirmDialog from 'primevue/confirmdialog'; import Dialog from 'primevue/dialog'; import InputIcon from 'primevue/inputicon'; import InputText from 'primevue/inputtext'; +import ProgressBar from 'primevue/progressbar'; import ScrollPanel from 'primevue/scrollpanel'; import Tab from 'primevue/tab'; import TabList from 'primevue/tablist'; @@ -43,7 +44,7 @@ const isProfileDisabled = computed(() => prf.current === null); const updateProgress: Ref = ref(null); listen('update-progress', (ev) => { - updateProgress.value = ev.payload; + updateProgress.value = Math.floor(ev.payload * 100); }); listen('update-end', (_) => { @@ -152,7 +153,7 @@ listen<{ message: string; header: string }>('invoke-error', (event) => { header="Updating" :style="{ width: '200px' }" > - {{ ((updateProgress ?? 0) * 100).toFixed(0) }}% + diff --git a/src/components/OptionList.vue b/src/components/OptionList.vue index 3657ec2..cf919d3 100644 --- a/src/components/OptionList.vue +++ b/src/components/OptionList.vue @@ -69,10 +69,21 @@ prf.reload(); diff --git a/src/components/PatchList.vue b/src/components/PatchList.vue index 63ace77..25f04ec 100644 --- a/src/components/PatchList.vue +++ b/src/components/PatchList.vue @@ -11,8 +11,8 @@ const prf = usePrfStore(); prf.reload(); -const gamePatches: Ref = ref([]); -const amdPatches: Ref = ref([]); +const gamePatches: Ref = ref(null); +const amdPatches: Ref = ref(null); invoke('list_patches', { target: prf.current!.data.sgt.target }).then( (patches) => { @@ -29,25 +29,40 @@ invoke('list_patches', { target: prf.current!.data.sgt.target }).then( target: amd, })) as Patch[]; })(); + +const errorMessage = + "No compatible patches found. Make sure you're using unpacked and unpatched files."; diff --git a/src/components/options/Display.vue b/src/components/options/Display.vue index cda52c1..049fff1 100644 --- a/src/components/options/Display.vue +++ b/src/components/options/Display.vue @@ -63,6 +63,11 @@ const loadDisplays = () => { }; loadDisplays(); + +const game = prf.current!.meta.game; +const isVertical = game === 'ongeki'; +const adjustableRez = game === 'ongeki'; +const canSkipPrimarySwitch = game === 'ongeki';