diff --git a/apps/tauri/src/App.svelte b/apps/tauri/src/App.svelte index 63f596d..c14a839 100644 --- a/apps/tauri/src/App.svelte +++ b/apps/tauri/src/App.svelte @@ -3,7 +3,7 @@ import { app } from "./lib/stores/app.svelte"; import SetupScreen from "./lib/screens/SetupScreen.svelte"; import TasksScreen from "./lib/screens/TasksScreen.svelte"; - import SettingsScreen from "./lib/screens/SettingsScreen.svelte"; + onMount(() => { app.loadConfig(); diff --git a/apps/tauri/src/lib/components/TaskItem.svelte b/apps/tauri/src/lib/components/TaskItem.svelte index 5b11f71..003e63d 100644 --- a/apps/tauri/src/lib/components/TaskItem.svelte +++ b/apps/tauri/src/lib/components/TaskItem.svelte @@ -16,9 +16,24 @@ let swiping = $state(false); let containerEl = $state(null); let titleInputEl = $state(null); + let showMenu = $state(false); + let menuEl = $state(null); let isCompleted = $derived(task.status === "completed"); + function handleMenuClickOutside(e: MouseEvent) { + if (showMenu && menuEl && !menuEl.contains(e.target as Node)) { + showMenu = false; + } + } + + $effect(() => { + if (showMenu) { + window.addEventListener("mousedown", handleMenuClickOutside); + return () => window.removeEventListener("mousedown", handleMenuClickOutside); + } + }); + function startEditing() { if (editing) return; editingTaskId = task.id; @@ -78,7 +93,7 @@
@@ -157,22 +172,30 @@
- - {#if !editing} - - {/if} + +
+ + {#if showMenu} +
+ +
+ {/if} +
diff --git a/apps/tauri/src/lib/screens/SettingsScreen.svelte b/apps/tauri/src/lib/screens/SettingsScreen.svelte index 6afdce6..afca842 100644 --- a/apps/tauri/src/lib/screens/SettingsScreen.svelte +++ b/apps/tauri/src/lib/screens/SettingsScreen.svelte @@ -7,7 +7,6 @@ let webdavUser = $state(""); let webdavPass = $state(""); let testStatus = $state<"idle" | "testing" | "ok" | "fail">("idle"); - let confirmRemove = $state(null); async function testConnection() { testStatus = "testing"; @@ -39,10 +38,6 @@ } } - async function handleRemoveWorkspace(name: string) { - await app.removeWorkspace(name); - confirmRemove = null; - }
- -
-

- Workspaces -

- {#if app.config} - {#each Object.entries(app.config.workspaces) as [name, ws]} -
-
-
-

- {name} -

-

{ws.path}

-
-
- {#if name !== app.config.current_workspace} - - {/if} - {#if confirmRemove === name} - - - {:else} - - {/if} -
-
- {#if ws.webdav_url} -

Sync: {ws.webdav_url}

- {/if} - {#if ws.last_sync} -

- Last synced: {new Date(ws.last_sync).toLocaleString()} -

- {/if} -
- {/each} - {/if} - - -
-

diff --git a/apps/tauri/src/lib/screens/TasksScreen.svelte b/apps/tauri/src/lib/screens/TasksScreen.svelte index 11f3c5d..215d731 100644 --- a/apps/tauri/src/lib/screens/TasksScreen.svelte +++ b/apps/tauri/src/lib/screens/TasksScreen.svelte @@ -7,9 +7,25 @@ let showDrawer = $state(false); let showSettings = $state(false); let showNewList = $state(false); + let showWorkspacePicker = $state(false); + let workspacePickerEl = $state(null); + + function handleWindowClick(e: MouseEvent) { + if (showWorkspacePicker && workspacePickerEl && !workspacePickerEl.contains(e.target as Node)) { + showWorkspacePicker = false; + } + const target = e.target as HTMLElement; + if (listMenuId && !target.closest("[data-list-menu]")) listMenuId = null; + if (wsMenuName && !target.closest("[data-ws-menu]")) wsMenuName = null; + } + + if (typeof window !== "undefined") { + window.addEventListener("mousedown", handleWindowClick); + } let newListName = $state(""); let showCompleted = $state(true); - let confirmDeleteList = $state(null); + let listMenuId = $state(null); + let wsMenuName = $state(null); let dragId = $state(null); let dragOverId = $state(null); let resizing = $state(false); @@ -28,13 +44,11 @@ await app.createList(newListName.trim()); newListName = ""; showNewList = false; - showDrawer = false; } async function handleDeleteList(id: string) { + listMenuId = null; await app.deleteList(id); - confirmDeleteList = null; - showDrawer = false; } function handleDragStart(e: DragEvent, taskId: string) { @@ -42,7 +56,6 @@ if (e.dataTransfer) { e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/plain", taskId); - // Create an unclipped drag image const el = (e.target as HTMLElement).closest("[draggable]") as HTMLElement; if (el) { const clone = el.cloneNode(true) as HTMLElement; @@ -88,160 +101,226 @@ function closeDrawer() { showDrawer = false; showNewList = false; - confirmDeleteList = null; + listMenuId = null; } function openSettings() { showSettings = true; - showDrawer = false; } function closeSettings() { showSettings = false; } - let translateX = $derived(showDrawer ? '0' : showSettings ? '-160vw' : '-80vw'); + let workspaceNames = $derived(app.config ? Object.keys(app.config.workspaces) : []); + let translateX = $derived(showDrawer ? '0' : '-80vw');
- +
- +
- -
-

- {app.config?.current_workspace ?? ""} -

-

Lists

-
- - +
{#each app.lists as list (list.id)} -
+
- {#if confirmDeleteList === list.id} +
- - {:else} - - {/if} + {#if listMenuId === list.id} +
+ +
+ {/if} +
{/each} + + +
+ {#if showNewList} +
+ { if (e.key === "Enter") handleNewList(); if (e.key === "Escape") { showNewList = false; newListName = ""; } }} + /> + +
+ {:else} + + {/if} +
- -
- {#if showNewList} -
- { if (e.key === "Enter") handleNewList(); }} - /> - -
- {:else} + +
+ +
- {/if} + {#if showWorkspacePicker} + +
+ {#each workspaceNames as name} + {@const ws = app.config?.workspaces[name]} +
+ +
+ + {#if wsMenuName === name} +
+ +
+ {/if} +
+
+ {/each} +
+ +
+
+ {/if} +
+ + +
- +
{ if (showDrawer) closeDrawer(); if (showSettings) closeSettings(); }} - onkeydown={(e) => { if (e.key === "Escape") { closeDrawer(); closeSettings(); } }} + class="absolute inset-0 z-30 transition-opacity duration-250 ease-out {showDrawer ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}" + style="box-shadow: inset 8px 0 24px rgba(0,0,0,0.4); background: rgba(0,0,0,0.4)" + onclick={closeDrawer} + onkeydown={(e) => { if (e.key === "Escape") closeDrawer(); }} >
-
+ + + + +

{app.config?.current_workspace ?? ""}

- +

{app.activeList?.title ?? "Tasks"}

-
- {#if app.syncing} -
- {/if} - -
+ + {#if app.syncing} +
+ {/if}
@@ -275,10 +354,12 @@ {/if} {#if app.completedTasks.length > 0} +
{#if showCompleted} {#each app.completedTasks as task (task.id)} @@ -300,9 +380,9 @@ {/if}

- +
+ + - -
+ + +
+ +
{ if (e.key === "Escape") closeSettings(); }} + >
+ +
-