diff --git a/src/components/input/editor/CommandsList.vue b/src/components/input/editor/CommandsList.vue index 4b8f55436..6221f3914 100644 --- a/src/components/input/editor/CommandsList.vue +++ b/src/components/input/editor/CommandsList.vue @@ -8,7 +8,11 @@ :key="index" @click="selectItem(index)" > - {{ item }} + +
+

{{ item.title }}

+

{{ item.description }}

+
@@ -99,17 +103,42 @@ export default { } .item { - display: block; + display: flex; + align-items: center; margin: 0; width: 100%; text-align: left; background: transparent; - border-radius: 0.4rem; - border: 1px solid transparent; + border-radius: $radius; + border: 0; padding: 0.2rem 0.4rem; + transition: background-color $transition; - &.is-selected { - border-color: #000; + &.is-selected, &:hover { + 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); } } \ No newline at end of file diff --git a/src/components/input/editor/TipTap.vue b/src/components/input/editor/TipTap.vue index 6da6de9bc..d6abeae76 100644 --- a/src/components/input/editor/TipTap.vue +++ b/src/components/input/editor/TipTap.vue @@ -47,7 +47,7 @@ import StarterKit from '@tiptap/starter-kit' import {EditorContent, useEditor, VueNodeViewRenderer} from '@tiptap/vue-3' import Commands from './commands' -import suggestion from './suggestion' +import suggestionSetup from './suggestion' // load all highlight.js languages import {lowlight} from 'lowlight' @@ -58,6 +58,9 @@ import type {ITask} from '@/modelTypes/ITask' import type {IAttachment} from '@/modelTypes/IAttachment' import AttachmentModel from '@/models/attachment' import AttachmentService from '@/services/attachment' +import {useI18n} from 'vue-i18n' + +const {t} = useI18n() // const CustomDocument = Document.extend({ // content: 'taskList', @@ -204,7 +207,7 @@ const editor = useEditor({ // }).configure({ lowlight }), Commands.configure({ - suggestion, + suggestion: suggestionSetup(t), }), ], onUpdate: () => { diff --git a/src/components/input/editor/suggestion.ts b/src/components/input/editor/suggestion.ts index 64c8dc3e1..cf47d10f2 100644 --- a/src/components/input/editor/suggestion.ts +++ b/src/components/input/editor/suggestion.ts @@ -3,112 +3,212 @@ import tippy from 'tippy.js' import CommandsList from './CommandsList.vue' -export default { - items: ({query}: { query: string }) => { - return [ - { - title: 'H1', - command: ({editor, range}) => { - editor - .chain() - .focus() - .deleteRange(range) - .setNode('heading', {level: 1}) - .run() +export default function suggestionSetup(t) { + return { + items: ({query}: { query: string }) => { + return [ + { + title: t('input.editor.text'), + description: t('input.editor.textTooltip'), + icon: 'fa-font', + command: ({editor, range}) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode('paragraph', {level: 1}) + .run() + }, }, - }, - { - title: 'H2', - description: 'Lorem ipsum', - command: ({editor, range}) => { - editor - .chain() - .focus() - .deleteRange(range) - .setNode('heading', {level: 2}) - .run() + { + title: t('input.editor.heading1'), + description: t('input.editor.heading1Tooltip'), + icon: 'fa-header', + command: ({editor, range}) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode('heading', {level: 1}) + .run() + }, }, - }, - { - title: 'bold', - command: ({editor, range}) => { - editor - .chain() - .focus() - .deleteRange(range) - .setMark('bold') - .run() + { + title: t('input.editor.heading2'), + description: t('input.editor.heading2Tooltip'), + icon: 'fa-header', + command: ({editor, range}) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode('heading', {level: 2}) + .run() + }, }, - }, - { - title: 'italic', - command: ({editor, range}) => { - editor - .chain() - .focus() - .deleteRange(range) - .setMark('italic') - .run() + { + title: t('input.editor.heading3'), + description: t('input.editor.heading3Tooltip'), + icon: 'fa-header', + command: ({editor, range}) => { + editor + .chain() + .focus() + .deleteRange(range) + .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: () => { - let component: VueRenderer - let popup + render: () => { + let component: VueRenderer + let popup - return { - onStart: props => { - component = new VueRenderer(CommandsList, { - // using vue 2: - // parent: this, - // propsData: props, - props, - editor: props.editor, - }) + return { + onStart: props => { + component = new VueRenderer(CommandsList, { + // using vue 2: + // parent: this, + // propsData: props, + props, + editor: props.editor, + }) - if (!props.clientRect) { - return - } + if (!props.clientRect) { + return + } - popup = tippy('body', { - getReferenceClientRect: props.clientRect, - appendTo: () => document.body, - content: component.element, - showOnCreate: true, - interactive: true, - trigger: 'manual', - placement: 'bottom-start', - }) - }, + popup = tippy('body', { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: 'manual', + placement: 'bottom-start', + }) + }, - onUpdate(props) { - component.updateProps(props) + onUpdate(props) { + component.updateProps(props) - if (!props.clientRect) { - return - } + if (!props.clientRect) { + return + } - popup[0].setProps({ - getReferenceClientRect: props.clientRect, - }) - }, + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }) + }, - onKeyDown(props) { - if (props.event.key === 'Escape') { - popup[0].hide() + onKeyDown(props) { + if (props.event.key === 'Escape') { + popup[0].hide() - return true - } + return true + } - return component.ref?.onKeyDown(props) - }, + return component.ref?.onKeyDown(props) + }, - onExit() { - popup[0].destroy() - component.destroy() - }, - } - }, + onExit() { + popup[0].destroy() + component.destroy() + }, + } + }, + } } \ No newline at end of file diff --git a/src/components/misc/Icon.ts b/src/components/misc/Icon.ts index 5300d07a2..cc8aed567 100644 --- a/src/components/misc/Icon.ts +++ b/src/components/misc/Icon.ts @@ -73,7 +73,7 @@ import { faUnlink, faParagraph, faTable, - faX, faArrowTurnDown, faListCheck, faXmark, faXmarksLines, + faX, faArrowTurnDown, faListCheck, faXmark, faXmarksLines, faFont, faRulerHorizontal, } from '@fortawesome/free-solid-svg-icons' import { faBellSlash, @@ -183,6 +183,8 @@ library.add(faArrowTurnDown) library.add(faListCheck) library.add(faXmark) library.add(faXmarksLines) +library.add(faFont) +library.add(faRulerHorizontal) // overwriting the wrong types export default FontAwesomeIcon as unknown as FontAwesomeIconFixedTypes \ No newline at end of file diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index e15670dd1..9cd8fafbd 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -514,24 +514,37 @@ "edit": "Edit", "done": "Done", "heading1": "Heading 1", + "heading1Tooltip": "Big section heading.", "heading2": "Heading 2", + "heading2Tooltip": "Medium section heading.", "heading3": "Heading 3", + "heading3Tooltip": "Smaller section header.", "headingSmaller": "Heading Smaller", "headingBigger": "Heading Bigger", "bold": "Bold", "italic": "Italic", "strikethrough": "Strikethrough", "code": "Code", + "codeTooltip": "Capture a code snippet.", "quote": "Quote", + "quoteTooltip": "Capture a quote.", + "bulletList": "Bullet list", + "bulletListTooltip": "Create a simple bullet list.", "unorderedList": "Unordered List", "orderedList": "Ordered List", + "orderedListTooltip": "Create a list with numbering.", "cleanBlock": "Clean Block", "link": "Link", "image": "Image", "table": "Table", "horizontalRule": "Horizontal Rule", + "horizontalRuleTooltip": "Divide a section.", "sideBySide": "Side By Side", "guide": "Guide", + "text": "Text", + "textTooltip": "Just start typing with plain text.", + "taskList": "Task list", + "taskListTooltip": "Track tasks with a to-do list.", "table": { "insert": "Insert table", "addColumnBefore": "Add column before",