115 lines
3.3 KiB
Vue
115 lines
3.3 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import CKEditor from '@/ckeditor/CKEditor'
|
|
import BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor'
|
|
import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials'
|
|
import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold'
|
|
import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic'
|
|
import UnderlinePlugin from '@ckeditor/ckeditor5-basic-styles/src/underline'
|
|
import StrikethroughPlugin from '@ckeditor/ckeditor5-basic-styles/src/strikethrough'
|
|
import LinkPlugin from '@ckeditor/ckeditor5-link/src/link'
|
|
import HeadingPlugin from '@ckeditor/ckeditor5-heading/src/heading'
|
|
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph'
|
|
import ListPlugin from '@ckeditor/ckeditor5-list/src/list'
|
|
import AutoformatPlugin from '@ckeditor/ckeditor5-autoformat/src/autoformat'
|
|
import ContextedPlugin from '@/ckeditor/ContextedPlugin'
|
|
import { mdToHtml } from '@/utils/markdown'
|
|
import { activeNote, getNoteByTitle } from '@/composables/useNotes'
|
|
import Autocomplete from '@/components/Autocomplete.vue'
|
|
|
|
const props = defineProps<{
|
|
note: Note
|
|
}>()
|
|
|
|
const html = mdToHtml(props.note.content)
|
|
|
|
const editor = BalloonEditor
|
|
const editorData = html
|
|
const editorConfig = {
|
|
plugins: [
|
|
EssentialsPlugin,
|
|
BoldPlugin,
|
|
ItalicPlugin,
|
|
UnderlinePlugin,
|
|
StrikethroughPlugin,
|
|
LinkPlugin,
|
|
HeadingPlugin,
|
|
ParagraphPlugin,
|
|
ListPlugin,
|
|
AutoformatPlugin,
|
|
ContextedPlugin,
|
|
],
|
|
|
|
toolbar: {
|
|
items: [
|
|
'bold',
|
|
'italic',
|
|
'underline',
|
|
'strikethrough',
|
|
'link',
|
|
'undo',
|
|
'redo',
|
|
'heading',
|
|
'bulletedList',
|
|
'numberedList',
|
|
],
|
|
},
|
|
}
|
|
|
|
const editorElement = ref<HTMLInputElement | null>(null)
|
|
|
|
const handleClick = ({ data }: { data: any }) => {
|
|
const noteTitle = data.domTarget.textContent as string
|
|
const note = getNoteByTitle(noteTitle)
|
|
if (note) activeNote.value = note
|
|
}
|
|
|
|
const showAutocomplete = ref(false)
|
|
const autocompleteStyle = ref<any>({})
|
|
const autocompleteText = ref('')
|
|
const handleAutocomplete = (event: any) => {
|
|
const position = event.position
|
|
if (position && editorElement.value) {
|
|
const rect: any = editorElement.value?.getBoundingClientRect()
|
|
const fontSize = parseFloat(
|
|
window.getComputedStyle(editorElement.value, null).getPropertyValue('font-size')
|
|
)
|
|
autocompleteStyle.value = {
|
|
top: `${position.top - rect.top + fontSize}` + 'px',
|
|
left: `${position.left - rect.left}` + 'px',
|
|
}
|
|
}
|
|
autocompleteText.value = event.autocompleteText
|
|
showAutocomplete.value = event.show
|
|
}
|
|
</script>
|
|
<template>
|
|
<div class="relative" ref="editorElement">
|
|
<CKEditor
|
|
class="h-full"
|
|
:editor="editor"
|
|
v-model="editorData"
|
|
:config="editorConfig"
|
|
@click="handleClick"
|
|
@contexted-link-autocomplete="handleAutocomplete"
|
|
></CKEditor>
|
|
<Autocomplete
|
|
v-if="showAutocomplete"
|
|
:autocomplete-text="autocompleteText"
|
|
:style="autocompleteStyle"
|
|
class="absolute mt-1 w-[250px]"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<style>
|
|
.ck-content {
|
|
padding: 0 !important;
|
|
border: 0 !important;
|
|
outline: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
.ck-content a[data-contexted-link='true'] {
|
|
@apply cursor-pointer font-semibold text-primary hover:bg-gray-200;
|
|
}
|
|
</style>
|