diff --git a/bun.lockb b/bun.lockb
index f91f653..a9d19e1 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 59062f8..2b102c7 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,8 @@
"@tiptap/extension-table-cell": "^3.14.0",
"@tiptap/extension-table-header": "^3.14.0",
"@tiptap/extension-table-row": "^3.14.0",
+ "@tiptap/extension-task-item": "^3.14.0",
+ "@tiptap/extension-task-list": "^3.14.0",
"@tiptap/extension-text-style": "^3.14.0",
"@tiptap/pm": "^3.14.0",
"@tiptap/starter-kit": "^3.14.0",
diff --git a/src/app.css b/src/app.css
index df5de34..8d8aed7 100644
--- a/src/app.css
+++ b/src/app.css
@@ -809,3 +809,44 @@ a.hover-underline-animation:hover::after {
background-color: var(--color-blue);
pointer-events: none;
}
+
+/* Task list styles */
+ul[data-type="taskList"] {
+ list-style: none;
+ padding: 0;
+ margin: 1rem 0;
+}
+
+ul[data-type="taskList"] li {
+ display: flex;
+ align-items: flex-start;
+ margin: 0.5rem 0;
+}
+
+ul[data-type="taskList"] li > label {
+ flex: 0 0 auto;
+ margin-right: 0.5rem;
+ user-select: none;
+}
+
+ul[data-type="taskList"] li > div {
+ flex: 1 1 auto;
+}
+
+ul[data-type="taskList"] input[type="checkbox"] {
+ cursor: pointer;
+ width: 1.2em;
+ height: 1.2em;
+ margin-top: 0.2em;
+ accent-color: var(--color-blue);
+}
+
+ul[data-type="taskList"] li[data-checked="true"] > div {
+ text-decoration: line-through;
+ opacity: 0.6;
+}
+
+/* Nested task lists */
+ul[data-type="taskList"] ul[data-type="taskList"] {
+ margin: 0.5rem 0 0.5rem 1.5rem;
+}
diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx
index 9d80ae1..174e2c0 100644
--- a/src/components/blog/TextEditor.tsx
+++ b/src/components/blog/TextEditor.tsx
@@ -8,6 +8,8 @@ import { Table } from "@tiptap/extension-table";
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 { Node } from "@tiptap/core";
import { createLowlight, common } from "lowlight";
import css from "highlight.js/lib/languages/css";
@@ -216,6 +218,13 @@ export default function TextEditor(props: TextEditorProps) {
}),
Image,
IframeEmbed,
+ TaskList,
+ TaskItem.configure({
+ nested: true,
+ HTMLAttributes: {
+ class: "task-item"
+ }
+ }),
Table.configure({
resizable: true,
HTMLAttributes: {
@@ -711,6 +720,20 @@ export default function TextEditor(props: TextEditorProps) {
>
Code
+
{/* Table controls in bubble menu */}
@@ -962,6 +985,20 @@ export default function TextEditor(props: TextEditorProps) {
>
1. List
+