Skip to content

Commit c419761

Browse files
author
codewec
committed
feat(editor): task list
1 parent 45ee178 commit c419761

6 files changed

Lines changed: 53 additions & 4 deletions

File tree

app/components/editoro/MainContent.vue

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
3+
import { ListKeymap, TaskItem, TaskList } from '@tiptap/extension-list'
34
import type { DirectoryTreeNode, EditorSuggestionItems, EditorToolbarItems, EditorViewMode, TreeNode, TreeNodeType } from '~/types/editoro'
45
import { useEditoroMainContentMedia } from '~/composables/editor/useEditoroMainContentMedia'
56
@@ -69,6 +70,9 @@ const richEditorHandlers = computed(() => ({
6970
isActive: () => false
7071
}
7172
}))
73+
74+
// Enable markdown task list (`- [ ]`) support in Nuxt UI editor.
75+
const editorExtensions = [TaskList, TaskItem, ListKeymap]
7276
</script>
7377

7478
<template>
@@ -187,6 +191,7 @@ const richEditorHandlers = computed(() => ({
187191
:model-value="props.editorContent"
188192
class="editoro-editor"
189193
content-type="markdown"
194+
:extensions="editorExtensions"
190195
:handlers="richEditorHandlers"
191196
:placeholder="t('main.editorPlaceholder')"
192197
@update:model-value="emit('updateEditorContent', String($event || ''))"
@@ -316,6 +321,42 @@ const richEditorHandlers = computed(() => ({
316321
padding-top: 1rem;
317322
}
318323
324+
/* Force TaskList layout: checkbox and text must stay on the same row. */
325+
.editoro-editor :deep(.tiptap ul[data-type='taskList']) {
326+
list-style: none;
327+
padding-left: 0;
328+
}
329+
330+
.editoro-editor :deep(.tiptap ul[data-type='taskList'] li),
331+
.editoro-editor :deep(.tiptap li[data-type='taskItem']) {
332+
display: flex !important;
333+
align-items: center;
334+
gap: 0.5rem;
335+
}
336+
337+
.editoro-editor :deep(.tiptap li[data-type='taskItem'] > label) {
338+
margin: 0;
339+
display: inline-flex !important;
340+
align-items: center;
341+
line-height: 1;
342+
flex: 0 0 auto;
343+
}
344+
345+
.editoro-editor :deep(.tiptap li[data-type='taskItem'] > label > input[type='checkbox']) {
346+
margin: 0;
347+
}
348+
349+
.editoro-editor :deep(.tiptap li[data-type='taskItem'] > div) {
350+
display: block !important;
351+
flex: 1 1 auto;
352+
min-width: 0;
353+
}
354+
355+
.editoro-editor :deep(.tiptap li[data-type='taskItem'] > div > p) {
356+
margin: 0;
357+
line-height: 1.5;
358+
}
359+
319360
.editoro-raw {
320361
height: 100%;
321362
width: 100%;

app/constants/editoro.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function createEditorToolbarItems(t: Translator) {
2222
[
2323
{ kind: 'bulletList', icon: 'i-lucide-list', tooltip: { text: t('toolbar.bulletList') } },
2424
{ kind: 'orderedList', icon: 'i-lucide-list-ordered', tooltip: { text: t('toolbar.orderedList') } },
25+
{ kind: 'taskList', icon: 'i-lucide-list-todo', tooltip: { text: t('toolbar.taskList') } },
2526
{ kind: 'blockquote', icon: 'i-lucide-text-quote', tooltip: { text: t('toolbar.quote') } },
2627
{ kind: 'codeBlock', icon: 'i-lucide-square-code', tooltip: { text: t('toolbar.codeBlock') } },
2728
{ kind: 'horizontalRule', icon: 'i-lucide-minus', tooltip: { text: t('toolbar.divider') } }
@@ -47,7 +48,8 @@ export function createEditorSuggestionItems(t: Translator) {
4748
[
4849
{ type: 'label', label: t('suggestion.lists') },
4950
{ kind: 'bulletList', label: t('toolbar.bulletList'), icon: 'i-lucide-list' },
50-
{ kind: 'orderedList', label: t('toolbar.orderedList'), icon: 'i-lucide-list-ordered' }
51+
{ kind: 'orderedList', label: t('toolbar.orderedList'), icon: 'i-lucide-list-ordered' },
52+
{ kind: 'taskList', label: t('toolbar.taskList'), icon: 'i-lucide-list-todo' }
5153
],
5254
[
5355
{ type: 'label', label: t('suggestion.insert') },

i18n/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"paragraph": "Paragraph",
8080
"bulletList": "Bullet list",
8181
"orderedList": "Ordered list",
82+
"taskList": "Task list",
8283
"quote": "Quote",
8384
"codeBlock": "Code block",
8485
"divider": "Divider",
@@ -131,4 +132,4 @@
131132
"emptyFileName": "File name cannot be empty",
132133
"specifyFileOrFolder": "Specify file or folder name"
133134
}
134-
}
135+
}

i18n/locales/ru.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"paragraph": "Параграф",
8080
"bulletList": "Маркированный список",
8181
"orderedList": "Нумерованный список",
82+
"taskList": "Список задач",
8283
"quote": "Цитата",
8384
"codeBlock": "Блок кода",
8485
"divider": "Разделитель",
@@ -131,4 +132,4 @@
131132
"emptyFileName": "Имя файла не может быть пустым",
132133
"specifyFileOrFolder": "Укажите имя файла или папки"
133134
}
134-
}
135+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"dependencies": {
1818
"@iconify-json/lucide": "^1.2.87",
1919
"@pinia/nuxt": "^0.11.2",
20+
"@tiptap/extension-list": "^3.17.1",
2021
"@tiptap/vue-3": "^3.17.1",
2122
"@nuxtjs/i18n": "^10.2.0",
2223
"@nuxt/ui": "^4.4.0",
@@ -32,4 +33,4 @@
3233
"vue-tsc": "^3.2.4"
3334
},
3435
"packageManager": "pnpm@10.28.2"
35-
}
36+
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)