From b42dedfd534ba823b3b66ad47ea08fa648c75695 Mon Sep 17 00:00:00 2001 From: Frederic Cabassut Date: Mon, 9 Mar 2026 23:57:05 +0100 Subject: [PATCH] feat: add task list button to rich text editor toolbar Register TaskList and TaskItem TipTap extensions, add "Task list" option to the List dropdown in the formatting toolbar, and consolidate task list CSS between the editor and markdown-it preview into shared styles in app.css. Co-Authored-By: Claude Opus 4.6 --- src/app.css | 74 +++++++++++++++++++++ src/lib/components/FormattingToolbar.svelte | 11 ++- src/lib/components/NoteCard.svelte | 21 ------ src/lib/components/TiptapEditor.svelte | 4 ++ src/lib/utils/markdown.ts | 11 +++ 5 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/app.css b/src/app.css index 79453ec..c0c8817 100644 --- a/src/app.css +++ b/src/app.css @@ -102,3 +102,77 @@ body::before { .tiptap .selectedCell { background-color: color-mix(in srgb, var(--primary) 12%, transparent); } + +/* Task list styles — shared between TipTap editor and markdown-it preview */ + +/* TipTap: ul[data-type="taskList"] | markdown-it: ul.task-list */ +.tiptap ul[data-type="taskList"], +.prose ul.task-list { + list-style: none; + padding-left: 0; + margin: 0.25rem 0; +} + +.tiptap ul[data-type="taskList"] li, +.prose ul.task-list li { + display: flex; + align-items: center; + gap: 0.375rem; + margin: 0; + padding: 0; +} + +.tiptap ul[data-type="taskList"] li::marker, +.prose ul.task-list li::marker { + content: none; +} + +/* TipTap: checkbox is inside a label */ +.tiptap ul[data-type="taskList"] li label { + display: flex; + align-items: center; + flex-shrink: 0; +} + +/* Shared checkbox styles */ +.tiptap ul[data-type="taskList"] li label input[type="checkbox"], +.prose ul.task-list .task-checkbox { + cursor: pointer; + margin: 0; + flex-shrink: 0; +} + +/* TipTap: text content is in a div>p */ +.tiptap ul[data-type="taskList"] li > div { + flex: 1; + min-width: 0; +} + +.tiptap ul[data-type="taskList"] li > div p { + margin: 0; +} + +/* Checked item styling */ +.tiptap ul[data-type="taskList"] li[data-checked="true"] > div { + text-decoration: line-through; + color: var(--text-muted); +} + +/* Override prose spacing for task lists */ +.prose ul[data-type="taskList"], +.prose ul.task-list { + padding-left: 0; + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} + +.prose ul[data-type="taskList"] li, +.prose ul.task-list li { + padding-left: 0; + margin-top: 0; + margin-bottom: 0; +} + +.prose ul.task-list li p { + margin: 0; +} diff --git a/src/lib/components/FormattingToolbar.svelte b/src/lib/components/FormattingToolbar.svelte index 5a0e850..83b4075 100644 --- a/src/lib/components/FormattingToolbar.svelte +++ b/src/lib/components/FormattingToolbar.svelte @@ -6,6 +6,7 @@ Heading, List, ListOrdered, + ListChecks, TextQuote, CodeXml, Bold, @@ -222,7 +223,7 @@
+
{/if} diff --git a/src/lib/components/NoteCard.svelte b/src/lib/components/NoteCard.svelte index 4cbe25d..d68e21f 100644 --- a/src/lib/components/NoteCard.svelte +++ b/src/lib/components/NoteCard.svelte @@ -237,24 +237,3 @@ {/if} - diff --git a/src/lib/components/TiptapEditor.svelte b/src/lib/components/TiptapEditor.svelte index de09093..6880f79 100644 --- a/src/lib/components/TiptapEditor.svelte +++ b/src/lib/components/TiptapEditor.svelte @@ -10,6 +10,8 @@ import { TableRow } from '@tiptap/extension-table-row'; import { TableHeader } from '@tiptap/extension-table-header'; import { TableCell } from '@tiptap/extension-table-cell'; + import TaskList from '@tiptap/extension-task-list'; + import TaskItem from '@tiptap/extension-task-item'; import { Markdown } from 'tiptap-markdown'; interface Props { @@ -38,6 +40,8 @@ TableRow, TableHeader, TableCell, + TaskList, + TaskItem.configure({ nested: true }), Markdown ], content, diff --git a/src/lib/utils/markdown.ts b/src/lib/utils/markdown.ts index c3fb92a..ac45382 100644 --- a/src/lib/utils/markdown.ts +++ b/src/lib/utils/markdown.ts @@ -24,6 +24,17 @@ md.core.ruler.after('inline', 'task-lists', (state) => { const token = new state.Token('html_inline', '', 0); token.content = checkbox; tokens[i].children!.unshift(token); + + // Add task-list class to parent