mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-23 23:35:57 +02:00
Tasks: per-vault persistence for the Flagged filter, Hide done, and sort mode (issue #94)
This commit is contained in:
@@ -270,6 +270,12 @@ pub struct VaultState {
|
|||||||
pub last_tag: Option<String>,
|
pub last_tag: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub tasks_layout: String,
|
pub tasks_layout: String,
|
||||||
|
#[serde(default = "default_true")]
|
||||||
|
pub tasks_hide_completed: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tasks_only_flagged: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tasks_sort: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VaultState {
|
impl Default for VaultState {
|
||||||
@@ -287,6 +293,9 @@ impl Default for VaultState {
|
|||||||
last_notebook: None,
|
last_notebook: None,
|
||||||
last_tag: None,
|
last_tag: None,
|
||||||
tasks_layout: String::new(),
|
tasks_layout: String::new(),
|
||||||
|
tasks_hide_completed: true,
|
||||||
|
tasks_only_flagged: false,
|
||||||
|
tasks_sort: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@
|
|||||||
viewMode,
|
viewMode,
|
||||||
sortMode,
|
sortMode,
|
||||||
tasksLayout,
|
tasksLayout,
|
||||||
|
tasksHideCompleted,
|
||||||
|
tasksOnlyFlagged,
|
||||||
|
tasksSort,
|
||||||
activeTag,
|
activeTag,
|
||||||
updateAvailable as globalUpdateAvailable,
|
updateAvailable as globalUpdateAvailable,
|
||||||
settingsTab,
|
settingsTab,
|
||||||
@@ -202,7 +205,10 @@
|
|||||||
last_view_mode: $viewMode,
|
last_view_mode: $viewMode,
|
||||||
last_notebook: $activeNotebook?.relative_path ?? null,
|
last_notebook: $activeNotebook?.relative_path ?? null,
|
||||||
last_tag: $activeTag,
|
last_tag: $activeTag,
|
||||||
tasks_layout: $tasksLayout
|
tasks_layout: $tasksLayout,
|
||||||
|
tasks_hide_completed: $tasksHideCompleted,
|
||||||
|
tasks_only_flagged: $tasksOnlyFlagged,
|
||||||
|
tasks_sort: $tasksSort
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await saveVaultState(state);
|
await saveVaultState(state);
|
||||||
@@ -504,6 +510,9 @@
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
$sortMode;
|
$sortMode;
|
||||||
$tasksLayout;
|
$tasksLayout;
|
||||||
|
$tasksHideCompleted;
|
||||||
|
$tasksOnlyFlagged;
|
||||||
|
$tasksSort;
|
||||||
persistState();
|
persistState();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -529,6 +538,9 @@
|
|||||||
$notebookOrder = state.notebook_order ?? {};
|
$notebookOrder = state.notebook_order ?? {};
|
||||||
if (state.sort_mode === 'created' || state.sort_mode === 'title' || state.sort_mode === 'modified') $sortMode = state.sort_mode;
|
if (state.sort_mode === 'created' || state.sort_mode === 'title' || state.sort_mode === 'modified') $sortMode = state.sort_mode;
|
||||||
if (state.tasks_layout === 'calendar' || state.tasks_layout === 'list') $tasksLayout = state.tasks_layout;
|
if (state.tasks_layout === 'calendar' || state.tasks_layout === 'list') $tasksLayout = state.tasks_layout;
|
||||||
|
if (typeof state.tasks_hide_completed === 'boolean') $tasksHideCompleted = state.tasks_hide_completed;
|
||||||
|
if (typeof state.tasks_only_flagged === 'boolean') $tasksOnlyFlagged = state.tasks_only_flagged;
|
||||||
|
if (state.tasks_sort === 'due' || state.tasks_sort === 'priority' || state.tasks_sort === 'note') $tasksSort = state.tasks_sort;
|
||||||
lastNotePath = state.last_open_note ?? null;
|
lastNotePath = state.last_open_note ?? null;
|
||||||
lastViewMode = state.last_view_mode ?? '';
|
lastViewMode = state.last_view_mode ?? '';
|
||||||
lastNotebook = state.last_notebook ?? null;
|
lastNotebook = state.last_notebook ?? null;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { listen } from '@tauri-apps/api/event';
|
import { listen } from '@tauri-apps/api/event';
|
||||||
import { getTasks } from '$lib/api';
|
import { getTasks } from '$lib/api';
|
||||||
import { debounce } from '$lib/utils/debounce';
|
import { debounce } from '$lib/utils/debounce';
|
||||||
import { tasksLayout, appConfig } from '$lib/stores/app';
|
import { tasksLayout, tasksHideCompleted, tasksOnlyFlagged, tasksSort, appConfig } from '$lib/stores/app';
|
||||||
import { isAndroid } from '$lib/platform';
|
import { isAndroid } from '$lib/platform';
|
||||||
import type { TaskItem, FileEvent } from '$lib/types';
|
import type { TaskItem, FileEvent } from '$lib/types';
|
||||||
|
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
let tasks = $state<TaskItem[]>([]);
|
let tasks = $state<TaskItem[]>([]);
|
||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let hideCompleted = $state(true);
|
|
||||||
let sortBy = $state<'due' | 'priority' | 'note'>('due');
|
|
||||||
let unlisten: (() => void) | null = null;
|
let unlisten: (() => void) | null = null;
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
@@ -46,13 +44,14 @@
|
|||||||
|
|
||||||
const filtered = $derived.by(() => {
|
const filtered = $derived.by(() => {
|
||||||
let list = tasks.slice();
|
let list = tasks.slice();
|
||||||
if (hideCompleted) list = list.filter((t) => !t.completed);
|
if ($tasksHideCompleted) list = list.filter((t) => !t.completed);
|
||||||
|
if ($tasksOnlyFlagged) list = list.filter((t) => !!t.due || !!t.priority);
|
||||||
list.sort((a, b) => {
|
list.sort((a, b) => {
|
||||||
if (a.completed !== b.completed) return a.completed ? 1 : -1; // done last
|
if (a.completed !== b.completed) return a.completed ? 1 : -1; // done last
|
||||||
if (sortBy === 'priority') {
|
if ($tasksSort === 'priority') {
|
||||||
const d = prank(a.priority) - prank(b.priority);
|
const d = prank(a.priority) - prank(b.priority);
|
||||||
if (d) return d;
|
if (d) return d;
|
||||||
} else if (sortBy === 'note') {
|
} else if ($tasksSort === 'note') {
|
||||||
const d = a.note_title.localeCompare(b.note_title);
|
const d = a.note_title.localeCompare(b.note_title);
|
||||||
if (d) return d;
|
if (d) return d;
|
||||||
} else {
|
} else {
|
||||||
@@ -110,7 +109,7 @@
|
|||||||
const calDayNames = $derived([...DOW.slice(weekStartsOn), ...DOW.slice(0, weekStartsOn)]);
|
const calDayNames = $derived([...DOW.slice(weekStartsOn), ...DOW.slice(0, weekStartsOn)]);
|
||||||
|
|
||||||
// Calendar tasks share the list's hide-completed filter (no sort).
|
// Calendar tasks share the list's hide-completed filter (no sort).
|
||||||
const calBase = $derived(tasks.filter((t) => !hideCompleted || !t.completed));
|
const calBase = $derived(tasks.filter((t) => (!$tasksHideCompleted || !t.completed) && (!$tasksOnlyFlagged || !!t.due || !!t.priority)));
|
||||||
|
|
||||||
const tasksByDate = $derived.by(() => {
|
const tasksByDate = $derived.by(() => {
|
||||||
const m = new Map<string, TaskItem[]>();
|
const m = new Map<string, TaskItem[]>();
|
||||||
@@ -186,7 +185,8 @@
|
|||||||
<button class="prio-backdrop" onclick={() => { prioMenuFor = null; dueMenuFor = null; }} aria-label="Close menu"></button>
|
<button class="prio-backdrop" onclick={() => { prioMenuFor = null; dueMenuFor = null; }} aria-label="Close menu"></button>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="tasks-controls">
|
<div class="tasks-controls">
|
||||||
<button class="tasks-ctl" class:active={hideCompleted} onclick={() => (hideCompleted = !hideCompleted)} title="Hide completed tasks">Hide done</button>
|
<button class="tasks-ctl" class:active={$tasksHideCompleted} onclick={() => ($tasksHideCompleted = !$tasksHideCompleted)} title="Hide completed tasks">Hide done</button>
|
||||||
|
<button class="tasks-ctl" class:active={$tasksOnlyFlagged} onclick={() => ($tasksOnlyFlagged = !$tasksOnlyFlagged)} title="Only show tasks with a due date or priority">Flagged</button>
|
||||||
{#if !isAndroid}
|
{#if !isAndroid}
|
||||||
<div class="tasks-layout">
|
<div class="tasks-layout">
|
||||||
<button class="tasks-ctl" class:active={viewLayout === 'list'} onclick={() => ($tasksLayout = 'list')} title="List view">List</button>
|
<button class="tasks-ctl" class:active={viewLayout === 'list'} onclick={() => ($tasksLayout = 'list')} title="List view">List</button>
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
{#if viewLayout === 'list'}
|
{#if viewLayout === 'list'}
|
||||||
<div class="tasks-sort">
|
<div class="tasks-sort">
|
||||||
{#each [['due', 'Due'], ['priority', 'Priority'], ['note', 'Note']] as [v, label]}
|
{#each [['due', 'Due'], ['priority', 'Priority'], ['note', 'Note']] as [v, label]}
|
||||||
<button class="tasks-ctl" class:active={sortBy === v} onclick={() => (sortBy = v as 'due' | 'priority' | 'note')}>{label}</button>
|
<button class="tasks-ctl" class:active={$tasksSort === v} onclick={() => ($tasksSort = v as 'due' | 'priority' | 'note')}>{label}</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -458,7 +458,7 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--text-tertiary);
|
color: var(--text-tertiary);
|
||||||
border: 1px dashed var(--border-color);
|
border: 1px dashed var(--border-color);
|
||||||
opacity: 0;
|
opacity: 0.4;
|
||||||
transition: opacity 0.1s;
|
transition: opacity 0.1s;
|
||||||
}
|
}
|
||||||
.task-row:hover .task-prio.prio-none { opacity: 1; }
|
.task-row:hover .task-prio.prio-none { opacity: 1; }
|
||||||
@@ -529,7 +529,7 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
color: var(--text-tertiary);
|
color: var(--text-tertiary);
|
||||||
opacity: 0;
|
opacity: 0.4;
|
||||||
transition: opacity 0.1s;
|
transition: opacity 0.1s;
|
||||||
}
|
}
|
||||||
.task-row:hover .task-due:not(.set) { opacity: 1; }
|
.task-row:hover .task-due:not(.set) { opacity: 1; }
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ export const vaultReady = writable(false);
|
|||||||
export const viewMode = writable<ViewMode>("all");
|
export const viewMode = writable<ViewMode>("all");
|
||||||
export const sortMode = writable<SortMode>("modified");
|
export const sortMode = writable<SortMode>("modified");
|
||||||
export const tasksLayout = writable<"list" | "calendar">("list");
|
export const tasksLayout = writable<"list" | "calendar">("list");
|
||||||
|
export const tasksHideCompleted = writable<boolean>(true);
|
||||||
|
export const tasksOnlyFlagged = writable<boolean>(false);
|
||||||
|
export const tasksSort = writable<"due" | "priority" | "note">("due");
|
||||||
export const sidebarCollapsed = writable(false);
|
export const sidebarCollapsed = writable(false);
|
||||||
export const sidebarWidth = writable(220);
|
export const sidebarWidth = writable(220);
|
||||||
export const notelistWidth = writable(280);
|
export const notelistWidth = writable(280);
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ export interface VaultState {
|
|||||||
last_notebook?: string | null;
|
last_notebook?: string | null;
|
||||||
last_tag?: string | null;
|
last_tag?: string | null;
|
||||||
tasks_layout?: string;
|
tasks_layout?: string;
|
||||||
|
tasks_hide_completed?: boolean;
|
||||||
|
tasks_only_flagged?: boolean;
|
||||||
|
tasks_sort?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchResult {
|
export interface SearchResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user