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