Hide subtask counter when parent subtask shown
When "show subtasks" is enabled, the UI could display both the parent subtask and its counter, leading to redundant information. Hide the subtask counter under a parent subtask when the parent itself is shown to reduce visual clutter and avoid duplicate counts. This change ensures a cleaner presentation of tasks and subtasks by preventing the counter from appearing alongside the visible parent subtask. if I drag a task in this mode, I would love to be able to drag it anywhere and have the task update its date - Added `date: Date | null` to TaskGroup (null = Overdue or No Date, Date = the group's calendar day) - Cross-group drops now update the task's due_date to the target group's date; preserves time-of-day when has_time is set; clears due_date when dropping into No Date - Dropping INTO Overdue is still blocked (it's a computed group); dragging OUT of Overdue to any other group works - Within-group drops still just reorder Close open submenus when clicking outside When submenu elements (like the kebab menu or workspace picker) were open, clicking elsewhere in the app did not close them and allowed interacting with underlying UI. This change adds a full-screen invisible overlay element whenever either menu is open that captures outside clicks and closes the menus, and removes the previous window-level mousedown handler and related element bindings. This ensures that clicking outside a submenu only closes it and prevents accidental interactions with other parts of the app. Prevent task clicks when closing dropdown menus When the list menu or workspace picker is open, clicking outside should close the menu but not also trigger underlying task click handlers. Add a mouse down handler that closes dropdowns when clicking outside and a capture-phase click handler that swallows the click immediately after a menu close to avoid propagation to task elements. This avoids accidental task activation right after closing a menu. Prevent clicks reaching background when menus open Stop clicks on the main task area from interacting with underlying elements when the workspace picker or list menu are open. Previously a global mousedown/click handler attempted to close menus and prevent a single stray click from propagating; this change replaces that logic by adding overlay divs inside the drawer and task list panels that capture clicks and close the respective menus. This simplifies interaction handling and fixes a bug where clicking menu items also triggered task clicks. the kebab menu calls the date on tasks a due date, but it's not a due date... it's just a date. can we make sure the codebase, documentation and everything is consistent about this? - Renamed `due_date` field on Task struct to `date` (Rust, TypeScript, all usages) - Renamed `group_by_due_date` field on TaskList/ListMetadata to `group_by_date` - Renamed `set_group_by_due_date`/`get_group_by_due_date` methods to `set_group_by_date`/`get_group_by_date` in repository, Tauri commands, and JS store - Renamed `with_due_date()` builder method to `with_date()` - Renamed `parse_due_date` CLI function to `parse_date` - Updated UI text "Group by due date" → "Group by date" in TasksScreen.svelte kebab menu - Renamed JS variables `dueDate`/`dueDateHasTime` → `date`/`dateHasTime` in NewTaskInput.svelte - Updated all test names and assertions across models.rs and repository.rs - Updated CLAUDE.md documentation to use "date" terminology consistently
This commit is contained in:
parent
105ed1ef62
commit
a0c183df82
|
|
@ -161,7 +161,7 @@
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if subtaskCount > 0}
|
{#if subtaskCount > 0 && showSubtaskCount}
|
||||||
<span class="mt-1 inline-flex items-center gap-1 text-xs opacity-40" aria-label="{subtasks.filter(s => s.status === 'completed').length} of {subtaskCount} subtasks completed">
|
<span class="mt-1 inline-flex items-center gap-1 text-xs opacity-40" aria-label="{subtasks.filter(s => s.status === 'completed').length} of {subtaskCount} subtasks completed">
|
||||||
<svg class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
<svg class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm2 4a1 1 0 011-1h10a1 1 0 110 2H6a1 1 0 01-1-1zm2 4a1 1 0 011-1h8a1 1 0 110 2H8a1 1 0 01-1-1z" />
|
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm2 4a1 1 0 011-1h10a1 1 0 110 2H6a1 1 0 01-1-1zm2 4a1 1 0 011-1h8a1 1 0 110 2H8a1 1 0 01-1-1z" />
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,6 @@
|
||||||
let settingsWorkspace = $state<string | null>(null);
|
let settingsWorkspace = $state<string | null>(null);
|
||||||
let showNewList = $state(false);
|
let showNewList = $state(false);
|
||||||
let showWorkspacePicker = $state(false);
|
let showWorkspacePicker = $state(false);
|
||||||
let workspacePickerEl = $state<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
function handleWindowClick(e: MouseEvent) {
|
|
||||||
if (showWorkspacePicker && workspacePickerEl && !workspacePickerEl.contains(e.target as Node))
|
|
||||||
showWorkspacePicker = false;
|
|
||||||
if (showListMenu && listMenuEl && !listMenuEl.contains(e.target as Node))
|
|
||||||
showListMenu = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newListName = $state("");
|
let newListName = $state("");
|
||||||
let showCompleted = $state(false);
|
let showCompleted = $state(false);
|
||||||
|
|
@ -61,7 +53,6 @@
|
||||||
let renamingListId = $state<string | null>(null);
|
let renamingListId = $state<string | null>(null);
|
||||||
let renameValue = $state("");
|
let renameValue = $state("");
|
||||||
let showListMenu = $state(false);
|
let showListMenu = $state(false);
|
||||||
let listMenuEl = $state<HTMLDivElement | null>(null);
|
|
||||||
let showSubtasks = $state(false);
|
let showSubtasks = $state(false);
|
||||||
let confirmDeleteList = $state(false);
|
let confirmDeleteList = $state(false);
|
||||||
let confirmDeleteCompleted = $state(false);
|
let confirmDeleteCompleted = $state(false);
|
||||||
|
|
@ -73,19 +64,16 @@
|
||||||
let resizeTimer: ReturnType<typeof setTimeout>;
|
let resizeTimer: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
window.addEventListener("mousedown", handleWindowClick);
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
resizing = true;
|
resizing = true;
|
||||||
clearTimeout(resizeTimer);
|
clearTimeout(resizeTimer);
|
||||||
resizeTimer = setTimeout(() => (resizing = false), 150);
|
resizeTimer = setTimeout(() => (resizing = false), 150);
|
||||||
};
|
};
|
||||||
window.addEventListener("resize", handleResize);
|
window.addEventListener("resize", handleResize);
|
||||||
return () => {
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
window.removeEventListener("mousedown", handleWindowClick);
|
|
||||||
window.removeEventListener("resize", handleResize);
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
async function handleNewList() {
|
async function handleNewList() {
|
||||||
if (!newListName.trim()) return;
|
if (!newListName.trim()) return;
|
||||||
await app.createList(newListName.trim());
|
await app.createList(newListName.trim());
|
||||||
|
|
@ -295,7 +283,11 @@
|
||||||
style="width: calc(100cqi + 80cqi); transform: translateX({translateX})"
|
style="width: calc(100cqi + 80cqi); transform: translateX({translateX})"
|
||||||
>
|
>
|
||||||
<!-- Drawer panel -->
|
<!-- Drawer panel -->
|
||||||
<div class="flex h-full shrink-0 flex-col bg-surface-light dark:bg-surface-dark" style="width: 80cqi">
|
<div class="relative flex h-full shrink-0 flex-col bg-surface-light dark:bg-surface-dark" style="width: 80cqi">
|
||||||
|
{#if showWorkspacePicker}
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="absolute inset-0 z-[39]" onclick={() => (showWorkspacePicker = false)}></div>
|
||||||
|
{/if}
|
||||||
<div class="shrink-0" style="height: var(--safe-top)"></div>
|
<div class="shrink-0" style="height: var(--safe-top)"></div>
|
||||||
<!-- Drawer header: workspace switcher + settings -->
|
<!-- Drawer header: workspace switcher + settings -->
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
|
@ -303,7 +295,7 @@
|
||||||
onmousedown={handleHeaderMouseDown}
|
onmousedown={handleHeaderMouseDown}
|
||||||
class="flex h-11 shrink-0 items-center justify-between border-b border-border-light px-3 dark:border-border-dark"
|
class="flex h-11 shrink-0 items-center justify-between border-b border-border-light px-3 dark:border-border-dark"
|
||||||
>
|
>
|
||||||
<div class="relative min-w-0 flex-1" bind:this={workspacePickerEl}>
|
<div class="relative min-w-0 flex-1">
|
||||||
<button
|
<button
|
||||||
onclick={() => (showWorkspacePicker = !showWorkspacePicker)}
|
onclick={() => (showWorkspacePicker = !showWorkspacePicker)}
|
||||||
class="flex items-center gap-1.5 rounded-lg px-2 py-1 text-sm font-semibold hover:bg-black/5 dark:hover:bg-white/10"
|
class="flex items-center gap-1.5 rounded-lg px-2 py-1 text-sm font-semibold hover:bg-black/5 dark:hover:bg-white/10"
|
||||||
|
|
@ -468,6 +460,10 @@
|
||||||
>
|
>
|
||||||
<!-- Sub-panel: Task list -->
|
<!-- Sub-panel: Task list -->
|
||||||
<div class="relative flex h-full w-1/3 flex-col">
|
<div class="relative flex h-full w-1/3 flex-col">
|
||||||
|
{#if showListMenu}
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="absolute inset-0 z-[39]" onclick={() => (showListMenu = false)}></div>
|
||||||
|
{/if}
|
||||||
<div class="shrink-0" style="height: var(--safe-top)"></div>
|
<div class="shrink-0" style="height: var(--safe-top)"></div>
|
||||||
<!-- Header / drag region -->
|
<!-- Header / drag region -->
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
|
@ -516,7 +512,7 @@
|
||||||
<div class="relative px-4 pt-3 pb-2">
|
<div class="relative px-4 pt-3 pb-2">
|
||||||
{#if app.activeListId}
|
{#if app.activeListId}
|
||||||
<!-- Kebab menu -->
|
<!-- Kebab menu -->
|
||||||
<div class="absolute right-3 top-1" bind:this={listMenuEl}>
|
<div class="absolute right-3 top-1">
|
||||||
<button
|
<button
|
||||||
onclick={() => (showListMenu = !showListMenu)}
|
onclick={() => (showListMenu = !showListMenu)}
|
||||||
class="rounded-lg p-1.5 opacity-50 hover:bg-black/5 hover:opacity-80 dark:hover:bg-white/10"
|
class="rounded-lg p-1.5 opacity-50 hover:bg-black/5 hover:opacity-80 dark:hover:bg-white/10"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue