diff --git a/apps/tauri/src/app.css b/apps/tauri/src/app.css index c6f76be..926b3cf 100644 --- a/apps/tauri/src/app.css +++ b/apps/tauri/src/app.css @@ -139,6 +139,33 @@ body { --color-danger: #ff5555; } +[data-theme="onyx"] { + --color-primary: #ffffff; + --color-primary-hover: #e0e0e0; + --color-surface-light: #0a0a0a; + --color-surface-dark: #0a0a0a; + --color-card-light: #161616; + --color-card-dark: #161616; + --color-text-light: #c4a95a; + --color-text-dark: #c4a95a; + --color-text-secondary-light: #917a3e; + --color-text-secondary-dark: #917a3e; + --color-border-light: #2a2418; + --color-border-dark: #2a2418; + --color-danger: #ef4444; +} + +[data-theme="onyx"] * { + scrollbar-color: #917a3e transparent; +} +[data-theme="onyx"] ::-webkit-scrollbar-thumb { + background: #917a3e; +} +[data-theme="onyx"] select option { + background-color: #0a0a0a; + color: #c4a95a; +} + [data-theme="solarized"] { --color-primary: #268bd2; --color-primary-hover: #1e7ac0; diff --git a/apps/tauri/src/lib/screens/SettingsScreen.svelte b/apps/tauri/src/lib/screens/SettingsScreen.svelte index f35bc72..11c3219 100644 --- a/apps/tauri/src/lib/screens/SettingsScreen.svelte +++ b/apps/tauri/src/lib/screens/SettingsScreen.svelte @@ -259,6 +259,7 @@ + diff --git a/apps/tauri/src/lib/stores/app.svelte.ts b/apps/tauri/src/lib/stores/app.svelte.ts index c1f8bec..298c7d7 100644 --- a/apps/tauri/src/lib/stores/app.svelte.ts +++ b/apps/tauri/src/lib/stores/app.svelte.ts @@ -67,7 +67,7 @@ let hasWorkspace = $derived( Object.keys(config.workspaces).length > 0, ); -const DARK_THEMES = new Set(["dark", "nord", "dracula", "solarized"]); +const DARK_THEMES = new Set(["dark", "nord", "dracula", "solarized", "onyx"]); let currentTheme = $derived( config?.current_workspace ? config.workspaces[config.current_workspace]?.theme ?? null diff --git a/crates/onyx-core/src/sync.rs b/crates/onyx-core/src/sync.rs index dc7de5f..7f2c5e5 100644 --- a/crates/onyx-core/src/sync.rs +++ b/crates/onyx-core/src/sync.rs @@ -688,7 +688,18 @@ async fn execute_action( match action { SyncAction::Upload { path } => { let local_path = workspace_path.join(path.replace('/', std::path::MAIN_SEPARATOR_STR)); - let data = std::fs::read(&local_path)?; + let data = match std::fs::read(&local_path) { + Ok(d) => d, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // File was moved or deleted since the action was computed (e.g. task + // moved between lists). Drop the stale upload and clean up sync state + // so the next cycle can re-evaluate from a clean baseline. + report(&format!(" - Skipping upload for missing file {}", path)); + sync_state.files.remove(path.as_str()); + return Ok(()); + } + Err(e) => return Err(e.into()), + }; let checksum = compute_checksum(&data); if let Some(parent) = path_parent(path) { @@ -707,7 +718,16 @@ async fn execute_action( SyncAction::Conflict { path } => { let local_path = workspace_path.join(path.replace('/', std::path::MAIN_SEPARATOR_STR)); - let local_data = std::fs::read(&local_path)?; + let local_data = match std::fs::read(&local_path) { + Ok(d) => d, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // Local file gone — treat as remote-wins: download it on next cycle. + report(&format!(" - Skipping conflict for missing local file {}", path)); + sync_state.files.remove(path.as_str()); + return Ok(()); + } + Err(e) => return Err(e.into()), + }; let local_checksum = compute_checksum(&local_data); let remote_data = client.get_file(path).await?;