feat(editor): edit mode
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
kolaente 2023-10-22 12:08:27 +02:00
parent 632e3c5a0b
commit d7503dc4a2
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
3 changed files with 55 additions and 10 deletions

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="tiptap"> <div class="tiptap">
<EditorToolbar <EditorToolbar
v-if="editor && isEditEnabled" v-if="editor && isEditing"
:editor="editor" :editor="editor"
:upload-callback="uploadCallback" :upload-callback="uploadCallback"
/> />
<BubbleMenu <BubbleMenu
v-if="editor && isEditEnabled" v-if="editor && isEditing"
:editor="editor" :editor="editor"
class="editor-bubble__wrapper" class="editor-bubble__wrapper"
> >
@ -62,12 +62,12 @@
<editor-content <editor-content
class="tiptap__editor" class="tiptap__editor"
:class="{'tiptap__editor-is-empty': isEmpty, 'tiptap__editor-is-edit-enabled': isEditEnabled}" :class="{'tiptap__editor-is-empty': isEmpty, 'tiptap__editor-is-edit-enabled': isEditing}"
:editor="editor" :editor="editor"
/> />
<input <input
v-if="isEditEnabled" v-if="isEditing"
type="file" type="file"
id="tiptap__image-upload" id="tiptap__image-upload"
class="is-hidden" class="is-hidden"
@ -75,20 +75,36 @@
@change="addImage" @change="addImage"
/> />
<ul class="tiptap__editor-actions d-print-none" v-if="bottomActions.length === 0 && !isEditing">
<li>
<BaseButton
@click="setEdit"
class="done-edit">
{{ $t('input.editor.edit') }}
</BaseButton>
</li>
</ul>
<ul class="tiptap__editor-actions d-print-none" v-if="bottomActions.length > 0"> <ul class="tiptap__editor-actions d-print-none" v-if="bottomActions.length > 0">
<li v-if="isEditEnabled && showSave"> <li v-if="isEditing && showSave">
<BaseButton <BaseButton
@click="bubbleSave" @click="bubbleSave"
class="done-edit"> class="done-edit">
{{ $t('misc.save') }} {{ $t('misc.save') }}
</BaseButton> </BaseButton>
</li> </li>
<li v-if="!isEditing">
<BaseButton
@click="setEdit"
class="done-edit">
{{ $t('input.editor.edit') }}
</BaseButton>
</li>
<li v-for="(action, k) in bottomActions" :key="k"> <li v-for="(action, k) in bottomActions" :key="k">
<BaseButton @click="action.action">{{ action.title }}</BaseButton> <BaseButton @click="action.action">{{ action.title }}</BaseButton>
</li> </li>
</ul> </ul>
<x-button <x-button
v-else-if="isEditEnabled && showSave" v-else-if="isEditing && showSave"
class="mt-4" class="mt-4"
@click="bubbleSave" @click="bubbleSave"
variant="secondary" variant="secondary"
@ -130,7 +146,6 @@ import {Blockquote} from '@tiptap/extension-blockquote'
import {Bold} from '@tiptap/extension-bold' import {Bold} from '@tiptap/extension-bold'
import {BulletList} from '@tiptap/extension-bullet-list' import {BulletList} from '@tiptap/extension-bullet-list'
import {Code} from '@tiptap/extension-code' import {Code} from '@tiptap/extension-code'
import {CodeBlock} from '@tiptap/extension-code-block'
import {Document} from '@tiptap/extension-document' import {Document} from '@tiptap/extension-document'
import {Dropcursor} from '@tiptap/extension-dropcursor' import {Dropcursor} from '@tiptap/extension-dropcursor'
import {Gapcursor} from '@tiptap/extension-gapcursor' import {Gapcursor} from '@tiptap/extension-gapcursor'
@ -187,6 +202,7 @@ const CustomTableCell = TableCell.extend({
}, },
}) })
type Mode = 'edit' | 'preview'
const { const {
modelValue, modelValue,
@ -196,6 +212,7 @@ const {
showSave = false, showSave = false,
placeholder = '', placeholder = '',
editShortcut = '', editShortcut = '',
initialMode = 'edit',
} = defineProps<{ } = defineProps<{
modelValue: string, modelValue: string,
uploadCallback?: UploadCallback, uploadCallback?: UploadCallback,
@ -204,6 +221,7 @@ const {
showSave?: boolean, showSave?: boolean,
placeholder?: string, placeholder?: string,
editShortcut?: string, editShortcut?: string,
initialMode?: Mode,
}>() }>()
const baseStore = useBaseStore() const baseStore = useBaseStore()
@ -233,6 +251,13 @@ watch(
) )
const isEmpty = computed(() => inputHTML.value === '') const isEmpty = computed(() => inputHTML.value === '')
const internalMode = ref<Mode>(initialMode)
const isEditing = computed(() => internalMode.value === 'edit' && isEditEnabled)
function setEdit() {
internalMode.value = 'edit'
editor.value?.commands.focus()
}
function onImageAdded() { function onImageAdded() {
bubbleSave() bubbleSave()
@ -282,11 +307,14 @@ function bubbleNow() {
function bubbleSave() { function bubbleSave() {
bubbleNow() bubbleNow()
emit('save', TIPTAP_TEXT_VALUE_PREFIX + inputHTML.value) emit('save', TIPTAP_TEXT_VALUE_PREFIX + inputHTML.value)
if (initialMode === 'preview' && isEditing.value) {
internalMode.value = 'preview'
}
} }
const editor = useEditor({ const editor = useEditor({
content: inputHTML.value, content: inputHTML.value,
editable: isEditEnabled, editable: isEditing.value,
extensions: [ extensions: [
// Starterkit: // Starterkit:
Blockquote, Blockquote,
@ -320,7 +348,7 @@ const editor = useEditor({
Placeholder.configure({ Placeholder.configure({
placeholder: ({editor}) => { placeholder: ({editor}) => {
if (!isEditEnabled) { if (!isEditing) {
return '' return ''
} }
@ -374,6 +402,13 @@ const editor = useEditor({
}, },
}) })
watch(
() => isEditing.value,
() => {
editor.value?.setEditable(isEditing.value)
}
)
watch(inputHTML, (value) => { watch(inputHTML, (value) => {
if (!editor.value) return if (!editor.value) return
// HTML // HTML
@ -459,6 +494,7 @@ function setLink() {
} }
onMounted(() => { onMounted(() => {
internalMode.value = initialMode
document.addEventListener('paste', handleImagePaste) document.addEventListener('paste', handleImagePaste)
if (editShortcut !== '') { if (editShortcut !== '') {
document.addEventListener('keydown', setFocusToEditor) document.addEventListener('keydown', setFocusToEditor)
@ -488,13 +524,20 @@ function setFocusToEditor(event) {
if (hotkeyString !== editShortcut || baseStore.editorFocused) return if (hotkeyString !== editShortcut || baseStore.editorFocused) return
event.preventDefault() event.preventDefault()
if (initialMode === 'preview' && isEditEnabled && !isEditing.value) {
internalMode.value = 'edit'
}
editor.value?.commands.focus() editor.value?.commands.focus()
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.tiptap__editor { .tiptap__editor {
min-height: 10rem; &.tiptap__editor-is-edit-enabled {
min-height: 10rem;
}
transition: box-shadow $transition; transition: box-shadow $transition;
border-radius: $radius; border-radius: $radius;

View File

@ -82,6 +82,7 @@
}" }"
:bottom-actions="actions[c.id]" :bottom-actions="actions[c.id]"
:show-save="true" :show-save="true"
initial-mode="preview"
/> />
</div> </div>
</div> </div>

View File

@ -25,6 +25,7 @@
v-model="task.description" v-model="task.description"
@update:model-value="saveWithDelay" @update:model-value="saveWithDelay"
@save="save" @save="save"
:initial-mode="task.description === '' ? 'edit' : 'preview'"
/> />
</div> </div>
</template> </template>