commit
fdc556ddd5
|
|
@ -14,7 +14,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={app.isDark ? "dark" : ""} data-theme={app.currentTheme ?? ""}>
|
<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
|
<div
|
||||||
class="relative h-full w-full overflow-hidden bg-surface-light text-text-light dark:bg-surface-dark dark:text-text-dark"
|
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}
|
class:rounded-xl={isLinux}
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,67 @@ body {
|
||||||
--color-danger: #ff5555;
|
--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"] {
|
[data-theme="solarized"] {
|
||||||
--color-primary: #268bd2;
|
--color-primary: #268bd2;
|
||||||
--color-primary-hover: #1e7ac0;
|
--color-primary-hover: #1e7ac0;
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,7 @@
|
||||||
<option value="nord">Nord</option>
|
<option value="nord">Nord</option>
|
||||||
<option value="dracula">Dracula</option>
|
<option value="dracula">Dracula</option>
|
||||||
<option value="solarized">Solarized Dark</option>
|
<option value="solarized">Solarized Dark</option>
|
||||||
|
<option value="onyx">Black and Gold</option>
|
||||||
</select>
|
</select>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ let hasWorkspace = $derived(
|
||||||
Object.keys(config.workspaces).length > 0,
|
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(
|
let currentTheme = $derived(
|
||||||
config?.current_workspace
|
config?.current_workspace
|
||||||
? config.workspaces[config.current_workspace]?.theme ?? null
|
? config.workspaces[config.current_workspace]?.theme ?? null
|
||||||
|
|
|
||||||
|
|
@ -688,7 +688,18 @@ async fn execute_action(
|
||||||
match action {
|
match action {
|
||||||
SyncAction::Upload { path } => {
|
SyncAction::Upload { path } => {
|
||||||
let local_path = workspace_path.join(path.replace('/', std::path::MAIN_SEPARATOR_STR));
|
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);
|
let checksum = compute_checksum(&data);
|
||||||
|
|
||||||
if let Some(parent) = path_parent(path) {
|
if let Some(parent) = path_parent(path) {
|
||||||
|
|
@ -707,7 +718,16 @@ async fn execute_action(
|
||||||
|
|
||||||
SyncAction::Conflict { path } => {
|
SyncAction::Conflict { path } => {
|
||||||
let local_path = workspace_path.join(path.replace('/', std::path::MAIN_SEPARATOR_STR));
|
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 local_checksum = compute_checksum(&local_data);
|
||||||
|
|
||||||
let remote_data = client.get_file(path).await?;
|
let remote_data = client.get_file(path).await?;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue