mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-24 07:45:57 +02:00
Enhance calendars: unify daily and Tasks calendars, remember List/Calendar choice per vault
This commit is contained in:
@@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user