From 854e6f3499b2d6931e0a739914e649b2d5fec146 Mon Sep 17 00:00:00 2001 From: sakastudio Date: Fri, 4 Jul 2025 20:43:33 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E3=82=B3=E3=83=94=E3=83=9A=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src-tauri/Cargo.lock | 215 +++++++++++++++++++++++++++++++- frontend/src-tauri/Cargo.toml | 1 + frontend/src-tauri/src/main.rs | 10 +- frontend/src/store/skitStore.ts | 16 ++- 4 files changed, 236 insertions(+), 6 deletions(-) diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock index 8d78bbb..498d5b9 100644 --- a/frontend/src-tauri/Cargo.lock +++ b/frontend/src-tauri/Cargo.lock @@ -66,12 +66,33 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" name = "app" version = "0.1.0" dependencies = [ + "arboard", "serde", "serde_json", "tauri", "tauri-build", ] +[[package]] +name = "arboard" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f533f8e0af236ffe5eb979b99381df3258853f00ba2e44b6e1955292c75227" +dependencies = [ + "clipboard-win", + "image 0.25.6", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "parking_lot", + "percent-encoding", + "windows-sys 0.59.0", + "x11rb", +] + [[package]] name = "atk" version = "0.15.1" @@ -211,6 +232,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.1" @@ -315,6 +342,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "cocoa" version = "0.24.1" @@ -601,6 +637,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.0", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -678,6 +724,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + [[package]] name = "fastrand" version = "2.3.0" @@ -955,6 +1007,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -1400,6 +1462,19 @@ dependencies = [ "num-traits", ] +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "num-traits", + "png", + "tiff", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -1495,6 +1570,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.77" @@ -1564,6 +1645,12 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1783,6 +1870,79 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.9.0", + "objc2", + "objc2-core-graphics", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +dependencies = [ + "bitflags 2.9.0", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +dependencies = [ + "bitflags 2.9.0", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc_exception" version = "0.1.2" @@ -2347,6 +2507,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + [[package]] name = "rustix" version = "1.0.7" @@ -2356,7 +2529,7 @@ dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] @@ -2752,7 +2925,7 @@ dependencies = [ "glib", "glib-sys", "gtk", - "image", + "image 0.24.9", "instant", "jni", "lazy_static", @@ -3002,7 +3175,7 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -3053,6 +3226,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.41" @@ -3533,6 +3717,12 @@ dependencies = [ "windows-metadata", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "winapi" version = "0.3.9" @@ -4001,6 +4191,23 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "gethostname", + "rustix 0.38.44", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + [[package]] name = "xattr" version = "1.5.0" @@ -4008,7 +4215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "rustix", + "rustix 1.0.7", ] [[package]] diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index cc4f1a1..ebd9c3a 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -18,6 +18,7 @@ tauri-build = { version = "1.5.1", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.5.4", features = ["dialog-all", "fs-all", "path-all", "protocol-asset"] } +arboard = "3.3.0" [features] # this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index 41cba42..9e94f8d 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -4,6 +4,7 @@ use tauri::{Manager, State}; use std::sync::Mutex; use std::path::PathBuf; +use arboard::Clipboard; // State to hold the current project path struct ProjectState { @@ -41,6 +42,12 @@ fn get_project_path(state: State) -> Result, String Ok(project_path.clone()) } +#[tauri::command] +fn read_clipboard_text() -> Result { + let mut clipboard = Clipboard::new().map_err(|e| e.to_string())?; + clipboard.get_text().map_err(|e| e.to_string()) +} + fn main() { tauri::Builder::default() .setup(|app| { @@ -56,7 +63,8 @@ fn main() { .invoke_handler(tauri::generate_handler![ get_commands_path, set_project_path, - get_project_path + get_project_path, + read_clipboard_text ]) // Register all commands .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/frontend/src/store/skitStore.ts b/frontend/src/store/skitStore.ts index 2af38ec..6991127 100644 --- a/frontend/src/store/skitStore.ts +++ b/frontend/src/store/skitStore.ts @@ -758,7 +758,21 @@ export const useSkitStore = create()( }, pasteCommandsFromClipboard: async () => { - const text = await navigator.clipboard.readText(); + let text: string; + try { + // Try to use Tauri's clipboard API if available + if (typeof window !== 'undefined' && '__TAURI__' in window) { + const { invoke } = await import('@tauri-apps/api'); + text = await invoke('read_clipboard_text'); + } else { + // Fallback to browser API for development + text = await navigator.clipboard.readText(); + } + } catch (error) { + console.error('Failed to read clipboard:', error); + return; + } + let commands: SkitCommand[]; try { commands = JSON.parse(text) as SkitCommand[]; From a8a28f3293309e3766c7c3a106323687f7799805 Mon Sep 17 00:00:00 2001 From: sakastudio Date: Fri, 4 Jul 2025 22:20:30 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=82=AF=E3=83=88=E3=83=87=E3=82=A3=E3=83=AC=E3=82=AF=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=82=92=E9=96=8B=E3=81=8F=E3=83=9C=E3=82=BF=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src-tauri/Cargo.lock | 76 ++++++++++++++++++++++++ frontend/src-tauri/Cargo.toml | 2 +- frontend/src-tauri/src/main.rs | 45 +++++++++++++- frontend/src-tauri/tauri.conf.json | 3 + frontend/src/components/skit/Toolbar.tsx | 26 +++++++- frontend/src/i18n/config.ts | 4 +- frontend/src/utils/fileSystem.ts | 16 +++++ 7 files changed, 167 insertions(+), 5 deletions(-) diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock index 498d5b9..b57e8d4 100644 --- a/frontend/src-tauri/Cargo.lock +++ b/frontend/src-tauri/Cargo.lock @@ -1976,6 +1976,16 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "open" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" +dependencies = [ + "pathdiff", + "windows-sys 0.42.0", +] + [[package]] name = "overload" version = "0.1.1" @@ -2030,6 +2040,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3001,10 +3017,12 @@ dependencies = [ "log", "objc", "once_cell", + "open", "percent-encoding", "plist", "rand 0.8.5", "raw-window-handle", + "regex", "rfd", "semver", "serde", @@ -3060,6 +3078,7 @@ dependencies = [ "png", "proc-macro2", "quote", + "regex", "semver", "serde", "serde_json", @@ -3875,6 +3894,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3939,6 +3973,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3963,6 +4003,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3987,6 +4033,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -4017,6 +4069,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -4041,6 +4099,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -4053,6 +4117,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -4077,6 +4147,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index ebd9c3a..a1cfab2 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -17,7 +17,7 @@ tauri-build = { version = "1.5.1", features = [] } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } -tauri = { version = "1.5.4", features = ["dialog-all", "fs-all", "path-all", "protocol-asset"] } +tauri = { version = "1.5.4", features = [ "shell-open", "dialog-all", "fs-all", "path-all", "protocol-asset"] } arboard = "3.3.0" [features] diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index 9e94f8d..47eff15 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -48,6 +48,48 @@ fn read_clipboard_text() -> Result { clipboard.get_text().map_err(|e| e.to_string()) } +#[tauri::command] +fn open_project_directory(path: String) -> Result<(), String> { + #[cfg(target_os = "windows")] + { + std::process::Command::new("explorer") + .arg(&path) + .spawn() + .map_err(|e| format!("Failed to open directory: {}", e))?; + } + + #[cfg(target_os = "macos")] + { + std::process::Command::new("open") + .arg(&path) + .spawn() + .map_err(|e| format!("Failed to open directory: {}", e))?; + } + + #[cfg(target_os = "linux")] + { + // Try common file managers + let file_managers = ["xdg-open", "nautilus", "dolphin", "thunar", "pcmanfm"]; + let mut opened = false; + + for fm in &file_managers { + if let Ok(_) = std::process::Command::new(fm) + .arg(&path) + .spawn() + { + opened = true; + break; + } + } + + if !opened { + return Err("Failed to open directory: No suitable file manager found".to_string()); + } + } + + Ok(()) +} + fn main() { tauri::Builder::default() .setup(|app| { @@ -64,7 +106,8 @@ fn main() { get_commands_path, set_project_path, get_project_path, - read_clipboard_text + read_clipboard_text, + open_project_directory ]) // Register all commands .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index 5bf29b2..cadc879 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -36,6 +36,9 @@ "protocol": { "asset": true, "assetScope": ["**"] + }, + "shell": { + "open": true } }, "bundle": { diff --git a/frontend/src/components/skit/Toolbar.tsx b/frontend/src/components/skit/Toolbar.tsx index dc61501..a4539b0 100644 --- a/frontend/src/components/skit/Toolbar.tsx +++ b/frontend/src/components/skit/Toolbar.tsx @@ -9,7 +9,8 @@ import { Save, ChevronDown, ClipboardPaste, - Scissors + Scissors, + FolderOpen } from 'lucide-react'; import { SidebarTrigger } from '../ui/sidebar'; import { @@ -25,6 +26,7 @@ import { DraggableCommand } from '../dnd/DraggableCommand'; import { DropZone } from '../dnd/DropZone'; import { useTranslation } from 'react-i18next'; import { useCommandTranslation } from '../../hooks/useCommandTranslation'; +import { openProjectDirectory } from '../../utils/fileSystem'; // Helper component to display translated command label function CommandMenuLabel({ commandId, label }: { commandId: string; label?: string }) { @@ -47,6 +49,7 @@ export function Toolbar() { redo, saveSkit, commandDefinitions, + projectPath, } = useSkitStore(); const handleAddCommand = (commandType: string) => { @@ -83,6 +86,16 @@ export function Toolbar() { } }; + const handleOpenProjectDirectory = async () => { + if (!projectPath) return; + + try { + await openProjectDirectory(projectPath); + } catch (error) { + toast.error(t('editor.toolbar.openProjectFolderFailed', { error: error instanceof Error ? error.message : String(error) })); + } + }; + const isDisabled = !currentSkitId; const isCommandSelected = selectedCommandIds.length > 0; @@ -189,10 +202,21 @@ export function Toolbar() { size="sm" disabled={isDisabled} onClick={handleSave} + className="mr-2" > {t('editor.menu.file.save')} + + diff --git a/frontend/src/i18n/config.ts b/frontend/src/i18n/config.ts index 27ad894..82b41b6 100644 --- a/frontend/src/i18n/config.ts +++ b/frontend/src/i18n/config.ts @@ -34,7 +34,7 @@ const editorTranslations = { projectLoadFailed: 'Failed to load project', skitSaved: 'Skit saved', saveFailed: 'Failed to save: {{error}}', - openProjectFolder: 'Open project folder', + openProjectFolder: 'Open folder', folder: 'Folder', currentDirectory: 'Current Directory', noFolderOpen: 'No folder open', @@ -122,7 +122,7 @@ const editorTranslations = { projectLoadFailed: 'プロジェクトの読み込みに失敗しました', skitSaved: 'スキットを保存しました', saveFailed: '保存に失敗しました: {{error}}', - openProjectFolder: 'プロジェクトフォルダを開く', + openProjectFolder: 'フォルダを開く', folder: 'フォルダ', currentDirectory: '現在のディレクトリ', noFolderOpen: 'フォルダが開かれていません', diff --git a/frontend/src/utils/fileSystem.ts b/frontend/src/utils/fileSystem.ts index 9ce49f6..6f7d682 100644 --- a/frontend/src/utils/fileSystem.ts +++ b/frontend/src/utils/fileSystem.ts @@ -1,6 +1,7 @@ import { readTextFile, writeTextFile, createDir, readDir, exists } from '@tauri-apps/api/fs'; import { join, resolveResource } from '@tauri-apps/api/path'; import { open } from '@tauri-apps/api/dialog'; +import { invoke } from '@tauri-apps/api/tauri'; import { Skit, CommandDefinition, SkitCommand } from '../types'; import { validateSkitData, validateCommandsYaml } from './validation'; import { loadConfigFile } from './configLoader'; @@ -29,6 +30,21 @@ export async function selectProjectFolder(): Promise { } } +/** + * Opens the project directory in the system's file explorer + * @param projectPath The path to the project directory + * @returns Promise that resolves when the directory is opened + */ +export async function openProjectDirectory(projectPath: string): Promise { + try { + // Use custom Tauri command instead of shell.open + await invoke('open_project_directory', { path: projectPath }); + } catch (error) { + console.error('Failed to open project directory:', error); + throw new Error(`Failed to open project directory: ${error instanceof Error ? error.message : String(error)}`); + } +} + /** * Loads commands.yaml file based on configuration * @param projectPath Optional project path From 0e72c889e2a009368ddbb7297ff0a06054016ecc Mon Sep 17 00:00:00 2001 From: sakastudio Date: Fri, 4 Jul 2025 23:22:54 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=E6=8C=87=E6=91=98=E4=BA=8B=E9=A0=85?= =?UTF-8?q?=E5=8F=8E=E8=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- specification/text-assets-integration-plan.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/specification/text-assets-integration-plan.md b/specification/text-assets-integration-plan.md index 47947ce..25d31bb 100644 --- a/specification/text-assets-integration-plan.md +++ b/specification/text-assets-integration-plan.md @@ -1,7 +1,7 @@ # Text Assets Integration Plan - CommandForgeEditor & mooreseditor ## 概要 -mooreseditorで管理するテキストアセット(テキストID、テキスト内容、ボイスID)をCommandForgeEditorで利用できるようにする連携機能の実装計画。 +mooreseditor(/Users/katsumi.sato/WebstormProjects/mooreseditor)で管理するテキストアセット(テキストID、テキスト内容、ボイスID)をCommandForgeEditorで利用できるようにする連携機能の実装計画。 ## 実装目標 - mooreseditorでテキストアセットを一元管理 @@ -14,9 +14,9 @@ mooreseditorで管理するテキストアセット(テキストID、テキス ### システム構成図 ``` mooreseditor(マスターデータ管理) - ├── テキストアセット編集UI + ├── テキストアセット編集UI 指摘:これは不要です。そもそもmooreseditorにはこのような機能はありません。純粋にマスターデータのjsonの出力しかできません。 ├── カテゴリ/タグ管理 - └── エクスポート機能 + └── エクスポート機 ↓ text_assets.json ↓ @@ -28,13 +28,22 @@ CommandForgeEditor(読み込み専用) ### データフロー 1. mooreseditorでテキストアセットを作成・編集 + 指摘:テキストアセットといっても、本質的には単なるマスターのjsonデータでしかありません。そのため、jsonをマスタデーターとして扱いたいです。 2. text_assets.jsonとしてエクスポート -3. CommandForgeEditorが自動検知して読み込み -4. show_messageコマンドでテキストIDを選択 +3. CommandForgeEditorが自動検知して読み込み +指摘:自動検知せず、CommandForgeEditor.config.yamlでマスターデータのプロジェクトパスを指定するようにしてください。 + +4. show_messageコマンドでテキストIDを選択 +指摘:プロパティでマスターのIDとjsonのパスを指定するようにしてください。jsonのパスの指定方法はmooreseditorに準拠してください。mooreseditorのforigenKyeと同じ仕様にしたいです。 + 5. スキットファイルにはテキストIDのみ保存 +指摘:同じく外部キーで指定してください。 ## データ仕様 +これはmooreseditorのマスターデータの形に準拠します。 +これ以下の仕様はすべて書き直してください。 + ### text_assets.json ```json { From 090b87e9b0a170a3ffcc6ca63f4666a08dedfbaa Mon Sep 17 00:00:00 2001 From: sakastudio Date: Fri, 4 Jul 2025 23:41:06 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E3=83=A9=E3=83=99=E3=83=AB=E3=81=AE?= =?UTF-8?q?=E8=89=B2=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/skit/CommandEditor.tsx | 15 +++++++++++++++ frontend/src/components/skit/CommandList.tsx | 18 ++++++++++++++---- frontend/src/i18n/config.ts | 2 ++ frontend/src/types/index.ts | 2 ++ frontend/src/utils/fileSystem.ts | 18 ++++++++++++++---- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/skit/CommandEditor.tsx b/frontend/src/components/skit/CommandEditor.tsx index 21a5471..bcaab98 100644 --- a/frontend/src/components/skit/CommandEditor.tsx +++ b/frontend/src/components/skit/CommandEditor.tsx @@ -98,6 +98,10 @@ export function CommandEditor() { const isBgMixed = !backgroundColors.every(c => c === backgroundColors[0]); const bgColorValue = isBgMixed ? "#ffffff" : backgroundColors[0]; + const labelColors = selectedCommands.map(cmd => cmd.commandLabelColor || (commandsMap.get(cmd.type)?.defaultCommandLabelColor ?? "#000000")); + const isLabelColorMixed = !labelColors.every(c => c === labelColors[0]); + const labelColorValue = isLabelColorMixed ? "#000000" : labelColors[0]; + const selectedLabels = selectedCommands.map(cmd => commandsMap.get(cmd.type)?.label || cmd.type); const uniqueLabels = Array.from(new Set(selectedLabels)); @@ -122,6 +126,17 @@ export function CommandEditor() { /> + {/* Command Label Color Picker */} +
+ + handlePropertyChange("commandLabelColor", value)} + placeholder={isLabelColorMixed ? '-' : undefined} + isMixed={isLabelColorMixed} + /> +
+ {/* Command Properties */} {commonProperties.map(([propName, propDef]) => { const values = selectedCommands.map(cmd => cmd[propName]); diff --git a/frontend/src/components/skit/CommandList.tsx b/frontend/src/components/skit/CommandList.tsx index fd45353..0167240 100644 --- a/frontend/src/components/skit/CommandList.tsx +++ b/frontend/src/components/skit/CommandList.tsx @@ -351,9 +351,10 @@ const CommandItem = memo(({ return lines; }, [nestLevel, command.type]); - // Get command definition to check for defaultBackgroundColor + // Get command definition to check for defaultBackgroundColor and defaultCommandLabelColor const commandDef = commandsMap?.get(command.type); const defaultBgColor = commandDef?.defaultBackgroundColor || "#ffffff"; + const defaultLabelColor = commandDef?.defaultCommandLabelColor || ""; const bgColor = command.backgroundColor || defaultBgColor; @@ -362,7 +363,12 @@ const CommandItem = memo(({ ...(isSelected ? {} : { backgroundColor: bgColor }) }; - const getTextColor = (bgColor: string) => { + const getTextColorClass = (bgColor: string, labelColor?: string) => { + if (labelColor) { + // If label color is set, use it directly as inline style + return ''; + } + if (!bgColor || bgColor === '') return ''; const hex = bgColor.replace('#', ''); @@ -375,7 +381,11 @@ const CommandItem = memo(({ return brightness < 128 ? 'text-white' : 'text-black'; }; - const textColorClass = getTextColor(bgColor); + const labelColor = command.commandLabelColor || defaultLabelColor; + const textColorClass = getTextColorClass(bgColor, labelColor); + + // Add inline style for custom label color + const textColorStyle = labelColor && !isSelected ? { color: labelColor } : {}; return (
handleCommandClick(command.id, e)} data-testid={`command-item-${command.id}`} - style={backgroundColorStyle} + style={{...backgroundColorStyle, ...textColorStyle}} > {/* ネストレベルを示す垂直ライン */} {nestLines} diff --git a/frontend/src/i18n/config.ts b/frontend/src/i18n/config.ts index 82b41b6..c80d61b 100644 --- a/frontend/src/i18n/config.ts +++ b/frontend/src/i18n/config.ts @@ -66,6 +66,7 @@ const editorTranslations = { noCommandSelected: 'No command selected', commandDefinitionNotFound: 'Command definition not found', backgroundColor: 'Background Color', + commandLabelColor: 'Text Color', itemsSelected: '{{count}} items selected', newSkit: 'New Skit', createNewSkit: 'Create New Skit', @@ -154,6 +155,7 @@ const editorTranslations = { noCommandSelected: 'コマンドが選択されていません', commandDefinitionNotFound: 'コマンド定義が見つかりません', backgroundColor: '背景色', + commandLabelColor: '文字色', itemsSelected: '{{count}}個選択中', newSkit: '新規作成', createNewSkit: '新規スキット作成', diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 963ba93..4c5ff88 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -34,6 +34,7 @@ export interface CommandDefinition { description: string; commandListLabelFormat: string; defaultBackgroundColor?: string; + defaultCommandLabelColor?: string; properties: Record; } @@ -54,6 +55,7 @@ export interface SkitCommand { id: number; type: string; backgroundColor?: string; // Background color for the command + commandLabelColor?: string; // Text color for the command isCollapsed?: boolean; // For group_start commands groupName?: string; // For group_start commands // 必須プロパティの型も含めたインデックスシグネチャ diff --git a/frontend/src/utils/fileSystem.ts b/frontend/src/utils/fileSystem.ts index 6f7d682..7ba6b5c 100644 --- a/frontend/src/utils/fileSystem.ts +++ b/frontend/src/utils/fileSystem.ts @@ -160,10 +160,20 @@ async function loadSkitsFromPath(skitsPath: string, projectPath: string | null): if (commandsConfig && commandsConfig.commands) { skit.commands = skit.commands.map((command: SkitCommand) => { - if (!command.backgroundColor) { - const commandDef = commandsConfig.commands.find((def: CommandDefinition) => def.id === command.type); - if (commandDef && commandDef.defaultBackgroundColor) { - return { ...command, backgroundColor: commandDef.defaultBackgroundColor }; + const commandDef = commandsConfig.commands.find((def: CommandDefinition) => def.id === command.type); + if (commandDef) { + const updates: Partial = {}; + + if (!command.backgroundColor && commandDef.defaultBackgroundColor) { + updates.backgroundColor = commandDef.defaultBackgroundColor; + } + + if (!command.commandLabelColor && commandDef.defaultCommandLabelColor) { + updates.commandLabelColor = commandDef.defaultCommandLabelColor; + } + + if (Object.keys(updates).length > 0) { + return { ...command, ...updates }; } } return command; From 73b4939e3bbefbb24854ef6f66009a76e87e9dfe Mon Sep 17 00:00:00 2001 From: sakastudio Date: Fri, 4 Jul 2025 23:51:17 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E6=96=87=E5=AD=97=E8=89=B2=E3=80=81?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E4=B8=A6=E3=81=B3=E6=9B=BF=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/skit/CommandEditor.tsx | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/skit/CommandEditor.tsx b/frontend/src/components/skit/CommandEditor.tsx index bcaab98..15c2a67 100644 --- a/frontend/src/components/skit/CommandEditor.tsx +++ b/frontend/src/components/skit/CommandEditor.tsx @@ -8,6 +8,8 @@ import { CommandDefinition, PropertyDefinition } from '../../types'; import { SkitCommand } from '../../types'; import { formatCommandPreview } from '../../utils/commandFormatting'; import { ColorPicker } from '../ui/color-picker'; +import { HexColorPicker } from 'react-colorful'; +import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { VectorInput } from '../ui/vector-input'; import { useTranslation } from 'react-i18next'; import { useCommandTranslation } from '../../hooks/useCommandTranslation'; @@ -115,26 +117,55 @@ export function CommandEditor() { - {/* Background Color Picker */} + {/* Color Pickers - Inline Side by Side */}
- - handlePropertyChange("backgroundColor", value)} - placeholder={isBgMixed ? '-' : undefined} - isMixed={isBgMixed} - /> -
+
+ {/* Background Color Picker */} +
+ + + +
- {/* Command Label Color Picker */} -
- - handlePropertyChange("commandLabelColor", value)} - placeholder={isLabelColorMixed ? '-' : undefined} - isMixed={isLabelColorMixed} - /> + {/* Command Label Color Picker */} +
+ + + +
+
{/* Command Properties */}