Enhance calendars: unify daily and Tasks calendars, remember List/Calendar choice per vault

This commit is contained in:
Yuri Karamian
2026-06-08 02:53:34 +02:00
parent 26fa22afaa
commit bd59f6dbee
6 changed files with 31 additions and 17 deletions
+3
View File
@@ -254,6 +254,8 @@ pub struct VaultState {
pub last_notebook: Option<String>, pub last_notebook: Option<String>,
#[serde(default)] #[serde(default)]
pub last_tag: Option<String>, pub last_tag: Option<String>,
#[serde(default)]
pub tasks_layout: String,
} }
impl Default for VaultState { impl Default for VaultState {
@@ -270,6 +272,7 @@ impl Default for VaultState {
last_view_mode: String::new(), last_view_mode: String::new(),
last_notebook: None, last_notebook: None,
last_tag: None, last_tag: None,
tasks_layout: String::new(),
} }
} }
} }
+5 -1
View File
@@ -37,6 +37,7 @@
rootNoteCount, rootNoteCount,
viewMode, viewMode,
sortMode, sortMode,
tasksLayout,
activeTag, activeTag,
updateAvailable as globalUpdateAvailable, updateAvailable as globalUpdateAvailable,
settingsTab, settingsTab,
@@ -200,7 +201,8 @@
sort_mode: $sortMode, sort_mode: $sortMode,
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
}; };
try { try {
await saveVaultState(state); await saveVaultState(state);
@@ -501,6 +503,7 @@
$effect(() => { $effect(() => {
$sortMode; $sortMode;
$tasksLayout;
persistState(); persistState();
}); });
@@ -525,6 +528,7 @@
$notebookSortMode = state.notebook_sort_mode === 'manual' ? 'manual' : 'alphabetical'; $notebookSortMode = state.notebook_sort_mode === 'manual' ? 'manual' : 'alphabetical';
$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;
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;
+7 -8
View File
@@ -2237,8 +2237,7 @@
.cal-grid { .cal-grid {
display: grid; display: grid;
grid-template-columns: repeat(7, 1fr); grid-template-columns: repeat(7, 1fr);
gap: 4px 2px; gap: 2px;
padding: 0 2px;
} }
.cal-head { .cal-head {
@@ -2250,19 +2249,18 @@
} }
.cal-cell { .cal-cell {
position: relative;
aspect-ratio: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.72rem; font-size: 12px;
width: 28px; border: 1px solid transparent;
height: 28px; border-radius: 6px;
border-radius: 50%;
border: none;
background: none; background: none;
color: var(--text-secondary); color: var(--text-secondary);
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
margin: 0 auto;
} }
.cal-cell.empty { .cal-cell.empty {
@@ -2274,6 +2272,7 @@
} }
.cal-cell.today { .cal-cell.today {
border-color: var(--accent);
color: var(--accent); color: var(--accent);
font-weight: 700; font-weight: 700;
} }
+14 -8
View File
@@ -3,6 +3,8 @@
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 } from '$lib/stores/app';
import { isAndroid } from '$lib/platform';
import type { TaskItem, FileEvent } from '$lib/types'; import type { TaskItem, FileEvent } from '$lib/types';
let { onOpenTask = (_t: TaskItem) => {}, onToggleTask = async (_t: TaskItem) => {}, onSetTaskPriority = async (_t: TaskItem, _p: string | null) => {}, onSetTaskDue = async (_t: TaskItem, _d: string | null) => {} }: { let { onOpenTask = (_t: TaskItem) => {}, onToggleTask = async (_t: TaskItem) => {}, onSetTaskPriority = async (_t: TaskItem, _p: string | null) => {}, onSetTaskDue = async (_t: TaskItem, _d: string | null) => {} }: {
@@ -94,14 +96,15 @@
} }
// ── Calendar ── // ── Calendar ──
let viewLayout = $state<'list' | 'calendar'>('list'); // Layout persists per-vault (tasksLayout store -> VaultState). Android is always List.
const viewLayout = $derived(isAndroid ? 'list' : $tasksLayout);
const calNow = new Date(); const calNow = new Date();
let calMonth = $state(calNow.getMonth()); let calMonth = $state(calNow.getMonth());
let calYear = $state(calNow.getFullYear()); let calYear = $state(calNow.getFullYear());
let selectedDate = $state(today); let selectedDate = $state(today);
const calMonthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; const calMonthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const calDayNames = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']; const calDayNames = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
// 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) => !hideCompleted || !t.completed));
@@ -130,7 +133,8 @@
); );
function calDays() { function calDays() {
const firstWeekday = new Date(calYear, calMonth, 1).getDay(); // Monday-first: shift so Mon=0 ... Sun=6
const firstWeekday = (new Date(calYear, calMonth, 1).getDay() + 6) % 7;
const lastDate = new Date(calYear, calMonth + 1, 0).getDate(); const lastDate = new Date(calYear, calMonth + 1, 0).getDate();
const cells: { day: number; date: string; current: boolean }[] = []; const cells: { day: number; date: string; current: boolean }[] = [];
for (let i = 0; i < firstWeekday; i++) cells.push({ day: 0, date: '', current: false }); for (let i = 0; i < firstWeekday; i++) cells.push({ day: 0, date: '', current: false });
@@ -181,10 +185,12 @@
{/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={hideCompleted} onclick={() => (hideCompleted = !hideCompleted)} title="Hide completed tasks">Hide done</button>
<div class="tasks-layout"> {#if !isAndroid}
<button class="tasks-ctl" class:active={viewLayout === 'list'} onclick={() => (viewLayout = 'list')} title="List view">List</button> <div class="tasks-layout">
<button class="tasks-ctl" class:active={viewLayout === 'calendar'} onclick={() => (viewLayout = 'calendar')} title="Calendar view">Calendar</button> <button class="tasks-ctl" class:active={viewLayout === 'list'} onclick={() => ($tasksLayout = 'list')} title="List view">List</button>
</div> <button class="tasks-ctl" class:active={viewLayout === 'calendar'} onclick={() => ($tasksLayout = 'calendar')} title="Calendar view">Calendar</button>
</div>
{/if}
{#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]}
@@ -638,7 +644,7 @@
} }
.cal-cell.empty { cursor: default; } .cal-cell.empty { cursor: default; }
.cal-cell:not(.empty):hover { background: var(--bg-hover); } .cal-cell:not(.empty):hover { background: var(--bg-hover); }
.cal-cell.today { border-color: var(--accent); } .cal-cell.today { border-color: var(--accent); color: var(--accent); font-weight: 700; }
.cal-cell.active { background: var(--accent); color: #fff; } .cal-cell.active { background: var(--accent); color: #fff; }
.cal-cell.drop-over { .cal-cell.drop-over {
border: 1px dashed var(--accent); border: 1px dashed var(--accent);
+1
View File
@@ -16,6 +16,7 @@ export const vaultReady = writable(false);
// UI state // UI state
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 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);
+1
View File
@@ -106,6 +106,7 @@ export interface VaultState {
last_view_mode?: string; last_view_mode?: string;
last_notebook?: string | null; last_notebook?: string | null;
last_tag?: string | null; last_tag?: string | null;
tasks_layout?: string;
} }
export interface SearchResult { export interface SearchResult {