commit
fdc556ddd5
|
|
@ -14,7 +14,7 @@
|
|||
</script>
|
||||
|
||||
<div class={app.isDark ? "dark" : ""} data-theme={app.currentTheme ?? ""}>
|
||||
<div class="h-screen w-screen" class:p-2={isLinux}>
|
||||
<div class="h-screen w-screen" class:p-2={isLinux} class:onyx-border={app.currentTheme === "onyx"}>
|
||||
<div
|
||||
class="relative h-full w-full overflow-hidden bg-surface-light text-text-light dark:bg-surface-dark dark:text-text-dark"
|
||||
class:rounded-xl={isLinux}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,67 @@ body {
|
|||
--color-danger: #ff5555;
|
||||
}
|
||||
|
||||
[data-theme="onyx"] {
|
||||
--color-primary: #f5ecd0;
|
||||
--color-primary-hover: #e0d5b3;
|
||||
--color-surface-light: #141414;
|
||||
--color-surface-dark: #141414;
|
||||
--color-card-light: #1e1e1e;
|
||||
--color-card-dark: #1e1e1e;
|
||||
--color-text-light: #d1bf82;
|
||||
--color-text-dark: #d1bf82;
|
||||
--color-text-secondary-light: #a6905a;
|
||||
--color-text-secondary-dark: #a6905a;
|
||||
--color-border-light: #5c4d2e;
|
||||
--color-border-dark: #5c4d2e;
|
||||
--color-danger: #ef4444;
|
||||
}
|
||||
|
||||
[data-theme="onyx"] * {
|
||||
scrollbar-color: #a6905a transparent;
|
||||
}
|
||||
[data-theme="onyx"] ::-webkit-scrollbar-thumb {
|
||||
background: #a6905a;
|
||||
}
|
||||
[data-theme="onyx"] select option {
|
||||
background-color: #141414;
|
||||
color: #d1bf82;
|
||||
}
|
||||
|
||||
/* Dark text/icons on primary buttons/FAB */
|
||||
[data-theme="onyx"] .bg-primary,
|
||||
[data-theme="onyx"] .bg-primary .text-white {
|
||||
color: #141414;
|
||||
}
|
||||
|
||||
/* FAB: match text gold instead of cream primary */
|
||||
[data-theme="onyx"] .rounded-full.bg-primary.shadow-lg {
|
||||
background-color: #d1bf82;
|
||||
}
|
||||
|
||||
/* Checkbox borders: gold instead of gray */
|
||||
[data-theme="onyx"] .border-gray-400,
|
||||
[data-theme="onyx"] .border-gray-500 {
|
||||
border-color: #a6905a;
|
||||
}
|
||||
|
||||
/* Hover/focus highlights: gold tint instead of white */
|
||||
[data-theme="onyx"] .dark\:hover\:bg-white\/10:hover,
|
||||
[data-theme="onyx"] .dark\:hover\:bg-white\/5:hover,
|
||||
[data-theme="onyx"] .dark\:bg-white\/10 {
|
||||
background-color: rgb(209 191 130 / 0.1);
|
||||
}
|
||||
|
||||
/* Linux window border */
|
||||
[data-theme="onyx"] .linux-window-border {
|
||||
border-color: rgba(209, 191, 130, 0.15);
|
||||
}
|
||||
|
||||
/* Thick gold window border */
|
||||
[data-theme="onyx"] .onyx-border {
|
||||
border: 3px solid #a6905a;
|
||||
}
|
||||
|
||||
[data-theme="solarized"] {
|
||||
--color-primary: #268bd2;
|
||||
--color-primary-hover: #1e7ac0;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@
|
|||
<option value="nord">Nord</option>
|
||||
<option value="dracula">Dracula</option>
|
||||
<option value="solarized">Solarized Dark</option>
|
||||
<option value="onyx">Black and Gold</option>
|
||||
</select>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue