From 13f6fe2c3f631676ac35e8d289fc9a7aa5ea1daa Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 27 Feb 2026 23:42:44 +0100 Subject: [PATCH] Save and load task notes --- src/components/Router.tsx | 7 +++++-- src/components/view/edit/DocDialog.tsx | 17 +++++++++++------ src/lib/export.ts | 5 +++++ src/lib/import.ts | 5 +++++ src/lib/types.ts | 3 +++ 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/components/Router.tsx b/src/components/Router.tsx index 4fbd5da..ad74ade 100644 --- a/src/components/Router.tsx +++ b/src/components/Router.tsx @@ -33,13 +33,16 @@ export default function Router({ switch (entity.type) { case "todo": { const createTask = (statusId: string) => { + const now = new Date().getTime(); const task: Task = { id: id("task"), title: "New task", statusId, tagIds: [], - createdAt: new Date().getTime(), - updatedAt: new Date().getTime(), + // initialize empty rich document notes + doc: { version: "2.28.0", time: now, blocks: [] }, + createdAt: now, + updatedAt: now, }; updateEntity(entityId, (e) => ({ diff --git a/src/components/view/edit/DocDialog.tsx b/src/components/view/edit/DocDialog.tsx index 43058eb..47e6f5e 100644 --- a/src/components/view/edit/DocDialog.tsx +++ b/src/components/view/edit/DocDialog.tsx @@ -26,11 +26,16 @@ export default function DocDialog({ tags: Record; children: React.ReactNode; }) { - const [doc, setDoc] = useState({ - version: "2.28.0", - time: Date.now(), - blocks: [], - }); + // if there is an existing document on the task use it, otherwise start with a blank one + const doc = task.doc || { version: "2.28.0", time: Date.now(), blocks: [] }; + + const handleDocChange = (newDoc: OutputData) => { + setTask({ + ...task, + doc: newDoc, + updatedAt: Date.now(), + }); + }; return ( @@ -62,7 +67,7 @@ export default function DocDialog({ - + diff --git a/src/lib/export.ts b/src/lib/export.ts index 18a61ca..a2f0780 100644 --- a/src/lib/export.ts +++ b/src/lib/export.ts @@ -168,6 +168,7 @@ export function exportTodoAsCsv(todo: TodoEntity): string { const headers = [ "Title", "Description", + "Doc", "Status", "Tags", "Created", @@ -176,6 +177,7 @@ export function exportTodoAsCsv(todo: TodoEntity): string { const rows = Object.values(todo.tasks).map((task) => [ task.title, task.description || "", + task.doc ? JSON.stringify(task.doc) : "", todo.config.statuses.find((s) => s.id === task.statusId)?.name || "", task.tagIds.map((id) => todo.tags[id]?.name || "").join(";"), new Date(task.createdAt).toISOString(), @@ -228,6 +230,9 @@ export function exportTodoAsMarkdown(todo: TodoEntity): string { if (task.description) { markdown += `\n - ${task.description}`; } + if (task.doc) { + markdown += `\n\n${docToMarkdown(task.doc)}`; + } markdown += "\n"; } } diff --git a/src/lib/import.ts b/src/lib/import.ts index c000f1f..6b58225 100644 --- a/src/lib/import.ts +++ b/src/lib/import.ts @@ -96,6 +96,7 @@ export function importTodoFromCsv( const descriptionIndex = headers.indexOf("description"); const statusIndex = headers.indexOf("status"); const tagsIndex = headers.indexOf("tags"); + const docIndex = headers.indexOf("doc"); if (titleIndex === -1) { errors.push("CSV must have a 'Title' column"); @@ -145,6 +146,10 @@ export function importTodoFromCsv( id: taskId, title, description: descriptionIndex !== -1 ? values[descriptionIndex] : "", + doc: + docIndex !== -1 && values[docIndex] + ? JSON.parse(values[docIndex]) + : undefined, statusId, tagIds, createdAt: Date.now(), diff --git a/src/lib/types.ts b/src/lib/types.ts index e25eb75..c1e0f3b 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -70,6 +70,9 @@ export interface Task { title: string; description?: string; + /** rich notes/documentation for the task */ + doc?: OutputData; + statusId: string; tagIds: TagId[];