diff --git a/package.json b/package.json index 8e3daa1..9714b69 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,16 @@ "tauri": "tauri" }, "dependencies": { - "vue": "^3.5.13", "@tauri-apps/api": "^2", - "@tauri-apps/plugin-opener": "^2" + "@tauri-apps/plugin-dialog": "^2.7.0", + "@tauri-apps/plugin-opener": "^2", + "vue": "^3.5.13" }, "devDependencies": { + "@tauri-apps/cli": "^2", "@vitejs/plugin-vue": "^5.2.1", "typescript": "~5.6.2", "vite": "^6.0.3", - "vue-tsc": "^2.1.10", - "@tauri-apps/cli": "^2" + "vue-tsc": "^2.1.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28bf8ba..856e31f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@tauri-apps/api': specifier: ^2 version: 2.10.1 + '@tauri-apps/plugin-dialog': + specifier: ^2.7.0 + version: 2.7.0 '@tauri-apps/plugin-opener': specifier: ^2 version: 2.5.3 @@ -429,6 +432,9 @@ packages: engines: {node: '>= 10'} hasBin: true + '@tauri-apps/plugin-dialog@2.7.0': + resolution: {integrity: sha512-4nS/hfGMGCXiAS3LtVjH9AgsSAPJeG/7R+q8agTFqytjnMa4Zq95Bq8WzVDkckpanX+yyRHXnRtrKXkANKDHvw==} + '@tauri-apps/plugin-opener@2.5.3': resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==} @@ -859,6 +865,10 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.10.1 '@tauri-apps/cli-win32-x64-msvc': 2.10.1 + '@tauri-apps/plugin-dialog@2.7.0': + dependencies: + '@tauri-apps/api': 2.10.1 + '@tauri-apps/plugin-opener@2.5.3': dependencies: '@tauri-apps/api': 2.10.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f253f6d..e3b4ceb 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -453,6 +453,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-dialog", "tauri-plugin-opener", ] @@ -2276,6 +2277,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.1", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -3007,6 +3009,30 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + [[package]] name = "rustc-hash" version = "2.1.2" @@ -3749,6 +3775,48 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fa4150c95ae391946cc8b8f905ab14797427caba3a8a2f79628e956da91809" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36e1ec28b79f3d0683f4507e1615c36292c0ea6716668770d4396b9b39871ed8" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "url", +] + [[package]] name = "tauri-plugin-opener" version = "2.5.3" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 136f1a0..60b868f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -23,4 +23,5 @@ tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" base64 = "0.22" +tauri-plugin-dialog = "2.7.0" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 4cdbf49..01a4101 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -5,6 +5,7 @@ "windows": ["main"], "permissions": [ "core:default", + "dialog:default", "opener:default" ] } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a9f7066..576c485 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -8,6 +8,7 @@ mod utils; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_opener::init()) .invoke_handler(tauri::generate_handler![ commands::scan_browsers, diff --git a/src/App.vue b/src/App.vue index 0a673e1..74aed5d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -27,6 +27,8 @@ const { openProfileError, openBrowserProfile, page, + pickExecutablePath, + pickUserDataPath, profileSortKey, refreshAll, savingConfig, @@ -115,17 +117,35 @@ const {
diff --git a/src/features/browser-assistant/useBrowserAssistant.ts b/src/features/browser-assistant/useBrowserAssistant.ts index 87a34fe..2e80c9d 100644 --- a/src/features/browser-assistant/useBrowserAssistant.ts +++ b/src/features/browser-assistant/useBrowserAssistant.ts @@ -1,5 +1,6 @@ import { computed, onMounted, ref, watch } from "vue"; import { invoke } from "@tauri-apps/api/core"; +import { open } from "@tauri-apps/plugin-dialog"; import { sortBookmarks, sortExtensions, sortProfiles } from "./sort"; import type { @@ -179,6 +180,34 @@ export function useBrowserAssistant() { } } + async function pickExecutablePath() { + const selected = await open({ + multiple: false, + directory: false, + filters: [ + { + name: "Executable", + extensions: ["exe"], + }, + ], + }); + + if (typeof selected === "string") { + createConfigForm.value.executablePath = selected; + } + } + + async function pickUserDataPath() { + const selected = await open({ + multiple: false, + directory: true, + }); + + if (typeof selected === "string") { + createConfigForm.value.userDataPath = selected; + } + } + function isDeletingConfig(configId: string) { return deletingConfigId.value === configId; } @@ -289,6 +318,8 @@ export function useBrowserAssistant() { openProfileError, openBrowserProfile, page, + pickExecutablePath, + pickUserDataPath, profileSortKey, refreshAll, savingConfig, diff --git a/src/styles.css b/src/styles.css index af33a00..a2bfe1e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -357,6 +357,12 @@ button { gap: 6px; } +.path-input-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 10px; +} + .field-group span, .config-label { color: var(--muted); @@ -390,6 +396,7 @@ button { } .primary-button, +.secondary-button, .danger-button { padding: 9px 14px; border-radius: 12px; @@ -403,6 +410,12 @@ button { color: #fff; } +.secondary-button { + border: 1px solid rgba(148, 163, 184, 0.24); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(241, 245, 249, 0.92)); + color: var(--text); +} + .danger-button { border: 1px solid rgba(239, 68, 68, 0.18); background: rgba(254, 242, 242, 0.96); @@ -410,6 +423,7 @@ button { } .primary-button:disabled, +.secondary-button:disabled, .danger-button:disabled { cursor: default; opacity: 0.72;