feat(editor): add all slash commands
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
kolaente 2023-10-21 13:00:12 +02:00
parent e81c98fe5b
commit 02ab1b8c0a
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
5 changed files with 249 additions and 102 deletions

View File

@ -8,7 +8,11 @@
:key="index" :key="index"
@click="selectItem(index)" @click="selectItem(index)"
> >
{{ item }} <icon :icon="item.icon"/>
<div class="description">
<p>{{ item.title }}</p>
<p>{{ item.description }}</p>
</div>
</button> </button>
</template> </template>
<div class="item" v-else> <div class="item" v-else>
@ -99,17 +103,42 @@ export default {
} }
.item { .item {
display: block; display: flex;
align-items: center;
margin: 0; margin: 0;
width: 100%; width: 100%;
text-align: left; text-align: left;
background: transparent; background: transparent;
border-radius: 0.4rem; border-radius: $radius;
border: 1px solid transparent; border: 0;
padding: 0.2rem 0.4rem; padding: 0.2rem 0.4rem;
transition: background-color $transition;
&.is-selected { &.is-selected, &:hover {
border-color: #000; background: var(--grey-100);
cursor: pointer;
}
> svg {
box-sizing: border-box;
width: 2rem;
height: 2rem;
border: 1px solid var(--grey-300);
padding: .5rem;
margin-right: .5rem;
border-radius: $radius;
color: var(--grey-700);
}
}
.description {
display: flex;
flex-direction: column;
font-size: .9rem;
p:last-child {
font-size: .75rem;
color: var(--grey-500);
} }
} }
</style> </style>

View File

@ -47,7 +47,7 @@ import StarterKit from '@tiptap/starter-kit'
import {EditorContent, useEditor, VueNodeViewRenderer} from '@tiptap/vue-3' import {EditorContent, useEditor, VueNodeViewRenderer} from '@tiptap/vue-3'
import Commands from './commands' import Commands from './commands'
import suggestion from './suggestion' import suggestionSetup from './suggestion'
// load all highlight.js languages // load all highlight.js languages
import {lowlight} from 'lowlight' import {lowlight} from 'lowlight'
@ -58,6 +58,9 @@ import type {ITask} from '@/modelTypes/ITask'
import type {IAttachment} from '@/modelTypes/IAttachment' import type {IAttachment} from '@/modelTypes/IAttachment'
import AttachmentModel from '@/models/attachment' import AttachmentModel from '@/models/attachment'
import AttachmentService from '@/services/attachment' import AttachmentService from '@/services/attachment'
import {useI18n} from 'vue-i18n'
const {t} = useI18n()
// const CustomDocument = Document.extend({ // const CustomDocument = Document.extend({
// content: 'taskList', // content: 'taskList',
@ -204,7 +207,7 @@ const editor = useEditor({
// }).configure({ lowlight }), // }).configure({ lowlight }),
Commands.configure({ Commands.configure({
suggestion, suggestion: suggestionSetup(t),
}), }),
], ],
onUpdate: () => { onUpdate: () => {

View File

@ -3,112 +3,212 @@ import tippy from 'tippy.js'
import CommandsList from './CommandsList.vue' import CommandsList from './CommandsList.vue'
export default { export default function suggestionSetup(t) {
items: ({query}: { query: string }) => { return {
return [ items: ({query}: { query: string }) => {
{ return [
title: 'H1', {
command: ({editor, range}) => { title: t('input.editor.text'),
editor description: t('input.editor.textTooltip'),
.chain() icon: 'fa-font',
.focus() command: ({editor, range}) => {
.deleteRange(range) editor
.setNode('heading', {level: 1}) .chain()
.run() .focus()
.deleteRange(range)
.setNode('paragraph', {level: 1})
.run()
},
}, },
}, {
{ title: t('input.editor.heading1'),
title: 'H2', description: t('input.editor.heading1Tooltip'),
description: 'Lorem ipsum', icon: 'fa-header',
command: ({editor, range}) => { command: ({editor, range}) => {
editor editor
.chain() .chain()
.focus() .focus()
.deleteRange(range) .deleteRange(range)
.setNode('heading', {level: 2}) .setNode('heading', {level: 1})
.run() .run()
},
}, },
}, {
{ title: t('input.editor.heading2'),
title: 'bold', description: t('input.editor.heading2Tooltip'),
command: ({editor, range}) => { icon: 'fa-header',
editor command: ({editor, range}) => {
.chain() editor
.focus() .chain()
.deleteRange(range) .focus()
.setMark('bold') .deleteRange(range)
.run() .setNode('heading', {level: 2})
.run()
},
}, },
}, {
{ title: t('input.editor.heading3'),
title: 'italic', description: t('input.editor.heading3Tooltip'),
command: ({editor, range}) => { icon: 'fa-header',
editor command: ({editor, range}) => {
.chain() editor
.focus() .chain()
.deleteRange(range) .focus()
.setMark('italic') .deleteRange(range)
.run() .setNode('heading', {level: 2})
.run()
},
}, },
}, {
].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 10) title: t('input.editor.bulletList'),
}, description: t('input.editor.bulletListTooltip'),
icon: 'fa-list-ul',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleBulletList()
.run()
},
},
{
title: t('input.editor.orderedList'),
description: t('input.editor.orderedListTooltip'),
icon: 'fa-list-ol',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleOrderedList()
.run()
},
},
{
title: t('input.editor.taskList'),
description: t('input.editor.taskListTooltip'),
icon: 'fa-list-check',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleTaskList()
.run()
},
},
{
title: t('input.editor.quote'),
description: t('input.editor.quoteTooltip'),
icon: 'fa-quote-right',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleBlockquote()
.run()
},
},
{
title: t('input.editor.code'),
description: t('input.editor.codeTooltip'),
icon: 'fa-code',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleCodeBlock()
.run()
},
},
// {
// title: t('input.editor.')'Image',
// description: t('input.editor.')'Upload an image from your computer',
// icon: 'fa-image',
// command: ({editor, range}) => {
// editor
// .chain()
// .focus()
// .deleteRange(range)
// .toggle()
// .run()
// },
// },
{
title: t('input.editor.horizontalRule'),
description: t('input.editor.horizontalRuleTooltip'),
icon: 'fa-ruler-horizontal',
command: ({editor, range}) => {
editor
.chain()
.focus()
.deleteRange(range)
.setHorizontalRule()
.run()
},
},
].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase()))
},
render: () => { render: () => {
let component: VueRenderer let component: VueRenderer
let popup let popup
return { return {
onStart: props => { onStart: props => {
component = new VueRenderer(CommandsList, { component = new VueRenderer(CommandsList, {
// using vue 2: // using vue 2:
// parent: this, // parent: this,
// propsData: props, // propsData: props,
props, props,
editor: props.editor, editor: props.editor,
}) })
if (!props.clientRect) { if (!props.clientRect) {
return return
} }
popup = tippy('body', { popup = tippy('body', {
getReferenceClientRect: props.clientRect, getReferenceClientRect: props.clientRect,
appendTo: () => document.body, appendTo: () => document.body,
content: component.element, content: component.element,
showOnCreate: true, showOnCreate: true,
interactive: true, interactive: true,
trigger: 'manual', trigger: 'manual',
placement: 'bottom-start', placement: 'bottom-start',
}) })
}, },
onUpdate(props) { onUpdate(props) {
component.updateProps(props) component.updateProps(props)
if (!props.clientRect) { if (!props.clientRect) {
return return
} }
popup[0].setProps({ popup[0].setProps({
getReferenceClientRect: props.clientRect, getReferenceClientRect: props.clientRect,
}) })
}, },
onKeyDown(props) { onKeyDown(props) {
if (props.event.key === 'Escape') { if (props.event.key === 'Escape') {
popup[0].hide() popup[0].hide()
return true return true
} }
return component.ref?.onKeyDown(props) return component.ref?.onKeyDown(props)
}, },
onExit() { onExit() {
popup[0].destroy() popup[0].destroy()
component.destroy() component.destroy()
}, },
} }
}, },
}
} }

View File

@ -73,7 +73,7 @@ import {
faUnlink, faUnlink,
faParagraph, faParagraph,
faTable, faTable,
faX, faArrowTurnDown, faListCheck, faXmark, faXmarksLines, faX, faArrowTurnDown, faListCheck, faXmark, faXmarksLines, faFont, faRulerHorizontal,
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import { import {
faBellSlash, faBellSlash,
@ -183,6 +183,8 @@ library.add(faArrowTurnDown)
library.add(faListCheck) library.add(faListCheck)
library.add(faXmark) library.add(faXmark)
library.add(faXmarksLines) library.add(faXmarksLines)
library.add(faFont)
library.add(faRulerHorizontal)
// overwriting the wrong types // overwriting the wrong types
export default FontAwesomeIcon as unknown as FontAwesomeIconFixedTypes export default FontAwesomeIcon as unknown as FontAwesomeIconFixedTypes

View File

@ -514,24 +514,37 @@
"edit": "Edit", "edit": "Edit",
"done": "Done", "done": "Done",
"heading1": "Heading 1", "heading1": "Heading 1",
"heading1Tooltip": "Big section heading.",
"heading2": "Heading 2", "heading2": "Heading 2",
"heading2Tooltip": "Medium section heading.",
"heading3": "Heading 3", "heading3": "Heading 3",
"heading3Tooltip": "Smaller section header.",
"headingSmaller": "Heading Smaller", "headingSmaller": "Heading Smaller",
"headingBigger": "Heading Bigger", "headingBigger": "Heading Bigger",
"bold": "Bold", "bold": "Bold",
"italic": "Italic", "italic": "Italic",
"strikethrough": "Strikethrough", "strikethrough": "Strikethrough",
"code": "Code", "code": "Code",
"codeTooltip": "Capture a code snippet.",
"quote": "Quote", "quote": "Quote",
"quoteTooltip": "Capture a quote.",
"bulletList": "Bullet list",
"bulletListTooltip": "Create a simple bullet list.",
"unorderedList": "Unordered List", "unorderedList": "Unordered List",
"orderedList": "Ordered List", "orderedList": "Ordered List",
"orderedListTooltip": "Create a list with numbering.",
"cleanBlock": "Clean Block", "cleanBlock": "Clean Block",
"link": "Link", "link": "Link",
"image": "Image", "image": "Image",
"table": "Table", "table": "Table",
"horizontalRule": "Horizontal Rule", "horizontalRule": "Horizontal Rule",
"horizontalRuleTooltip": "Divide a section.",
"sideBySide": "Side By Side", "sideBySide": "Side By Side",
"guide": "Guide", "guide": "Guide",
"text": "Text",
"textTooltip": "Just start typing with plain text.",
"taskList": "Task list",
"taskListTooltip": "Track tasks with a to-do list.",
"table": { "table": {
"insert": "Insert table", "insert": "Insert table",
"addColumnBefore": "Add column before", "addColumnBefore": "Add column before",