diff --git a/apps/tauri/src/App.svelte b/apps/tauri/src/App.svelte index 304b6a2..80d38ec 100644 --- a/apps/tauri/src/App.svelte +++ b/apps/tauri/src/App.svelte @@ -12,7 +12,7 @@ }); -
+
+ {:else} {/if} diff --git a/apps/tauri/src/app.css b/apps/tauri/src/app.css index ec6380a..2e94fc4 100644 --- a/apps/tauri/src/app.css +++ b/apps/tauri/src/app.css @@ -68,3 +68,68 @@ body { background-color: #242424; color: #e5e7eb; } + +/* ── Theme overrides ─────────────────────────────────────────────── */ + +[data-theme="dark"] { + --color-primary: #2d87b8; + --color-primary-hover: #2474a0; + --color-surface-light: #242424; + --color-surface-dark: #242424; + --color-card-light: #303030; + --color-card-dark: #303030; + --color-text-light: #e5e7eb; + --color-text-dark: #e5e7eb; + --color-text-secondary-light: #9ca3af; + --color-text-secondary-dark: #9ca3af; + --color-border-light: #3d3d3d; + --color-border-dark: #3d3d3d; +} + +[data-theme="nord"] { + --color-primary: #88c0d0; + --color-primary-hover: #7ab3c3; + --color-surface-light: #2e3440; + --color-surface-dark: #2e3440; + --color-card-light: #3b4252; + --color-card-dark: #3b4252; + --color-text-light: #eceff4; + --color-text-dark: #eceff4; + --color-text-secondary-light: #d8dee9; + --color-text-secondary-dark: #d8dee9; + --color-border-light: #434c5e; + --color-border-dark: #434c5e; + --color-danger: #bf616a; +} + +[data-theme="dracula"] { + --color-primary: #bd93f9; + --color-primary-hover: #a87ef0; + --color-surface-light: #282a36; + --color-surface-dark: #282a36; + --color-card-light: #343746; + --color-card-dark: #343746; + --color-text-light: #f8f8f2; + --color-text-dark: #f8f8f2; + --color-text-secondary-light: #bfbfbf; + --color-text-secondary-dark: #bfbfbf; + --color-border-light: #44475a; + --color-border-dark: #44475a; + --color-danger: #ff5555; +} + +[data-theme="solarized"] { + --color-primary: #268bd2; + --color-primary-hover: #1e7ac0; + --color-surface-light: #002b36; + --color-surface-dark: #002b36; + --color-card-light: #073642; + --color-card-dark: #073642; + --color-text-light: #93a1a1; + --color-text-dark: #93a1a1; + --color-text-secondary-light: #657b83; + --color-text-secondary-dark: #657b83; + --color-border-light: #094959; + --color-border-dark: #094959; + --color-danger: #dc322f; +} diff --git a/apps/tauri/src/lib/stores/app.svelte.ts b/apps/tauri/src/lib/stores/app.svelte.ts index fd42e50..b23e8b7 100644 --- a/apps/tauri/src/lib/stores/app.svelte.ts +++ b/apps/tauri/src/lib/stores/app.svelte.ts @@ -20,9 +20,7 @@ let config = $state(null); let lists = $state([]); let activeListId = $state(null); let tasks = $state([]); -let darkMode = $state( - globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false, -); +let osDark = globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false; let syncing = $state(false); let syncMode = $state<"full" | "push" | "pull">("full"); let lastSyncResult = $state(null); @@ -56,6 +54,16 @@ let hasWorkspace = $derived( Object.keys(config.workspaces).length > 0, ); +const DARK_THEMES = new Set(["dark", "nord", "dracula", "solarized"]); +let currentTheme = $derived( + config?.current_workspace + ? config.workspaces[config.current_workspace]?.theme ?? null + : null, +); +let isDark = $derived( + currentTheme ? DARK_THEMES.has(currentTheme) : osDark, +); + // ── Actions ────────────────────────────────────────────────────────── async function loadConfig() { @@ -311,8 +319,31 @@ function setSyncMode(mode: "full" | "push" | "pull") { syncMode = mode; } -function toggleDarkMode() { - darkMode = !darkMode; +async function setTheme(theme: string | null) { + if (!config?.current_workspace) return; + try { + await invoke("set_workspace_theme", { + workspaceName: config.current_workspace, + theme, + }); + config = await invoke("get_config"); + } catch (e) { + error = String(e); + } +} + +async function addWebdavWorkspace(name: string, webdavUrl: string, username: string, password: string) { + try { + await invoke("add_webdav_workspace", { name, webdavUrl, username, password }); + config = await invoke("get_config"); + await loadLists(); + const ws = config?.workspaces[name]; + if (ws) invoke("watch_workspace", { path: ws.path }).catch((e) => console.warn("File watcher failed:", e)); + screen = "tasks"; + error = null; + } catch (e) { + error = String(e); + } } function setScreen(s: Screen) { @@ -350,8 +381,11 @@ export const app = { get completedTasks() { return completedTasks; }, - get darkMode() { - return darkMode; + get currentTheme() { + return currentTheme; + }, + get isDark() { + return isDark; }, get syncing() { return syncing; @@ -388,7 +422,8 @@ export const app = { setGroupByDueDate, triggerSync, setSyncMode, - toggleDarkMode, + setTheme, + addWebdavWorkspace, setScreen, clearError, };