genadmin/src/components/TiptapEditor.vue

212 lines
4.8 KiB
Vue
Raw Normal View History

2022-01-10 10:40:05 +00:00
<template>
<div>
<bubble-menu
class="bubble-menu"
:tippy-options="{ duration: 100 }"
:editor="editor"
v-if="editor"
>
<button
@click="editor.chain().focus().toggleBold().run()"
:class="{ 'is-active': editor.isActive('bold') }"
>Bold</button>
<button
@click="editor.chain().focus().toggleItalic().run()"
:class="{ 'is-active': editor.isActive('italic') }"
>Italic</button>
<button
@click="editor.chain().focus().toggleStrike().run()"
:class="{ 'is-active': editor.isActive('strike') }"
>Strike</button>
</bubble-menu>
<floating-menu
class="floating-menu"
:tippy-options="{ duration: 100 }"
:editor="editor"
v-if="editor"
>
<button
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
>H1</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
>H2</button>
<button
@click="editor.chain().focus().toggleBulletList().run()"
:class="{ 'is-active': editor.isActive('bulletList') }"
>Bullet List</button>
</floating-menu>
<editor-content :editor="editor" />
</div>
</template>
<script setup lang="ts">
import {
Editor, EditorContent,
FloatingMenu,
BubbleMenu
} from '@tiptap/vue-3'
import { PropType } from 'vue'
import Link from '@tiptap/extension-link'
import StarterKit from '@tiptap/starter-kit'
import TextStyle from '@tiptap/extension-text-style'
import { HtmlAttrsType } from '~/typs/cv'
// import { auth_data } from '~/hooks/utils'
import useState from '~/hooks/useState'
const props = defineProps({
data: {
type: String,
default: '',
required: true,
},
src: {
type: String,
default: '',
required: true,
},
field: {
type: [String, Number],
default: '',
required: true,
},
idx: {
type: Number,
default: -1,
required: true,
},
editable: {
type: Boolean,
default: false,
required: true,
},
htmlattrs: {
type: Object as PropType<HtmlAttrsType>,
default: useState().htmlAttrs,
required: false,
},
})
const emit = defineEmits(['onEditorBlur'])
const editor = new Editor({
extensions: [
StarterKit.configure({
// history: false,
bold: {
HTMLAttributes: {
class: props.htmlattrs.bold ? props.htmlattrs.bold : useState().htmlAttrs.bold,
},
},
listItem: {
HTMLAttributes: {
class: props.htmlattrs.list ? props.htmlattrs.list : useState().htmlAttrs.list,
},
},
}),
TextStyle.configure({
HTMLAttributes: {
class: props.htmlattrs.text ? props.htmlattrs.text : useState().htmlAttrs.text,
},
}),
Link.configure({
openOnClick: false,
HTMLAttributes: {
class: props.htmlattrs.link ? props.htmlattrs.link : useState().htmlAttrs.link,
},
}),
],
content: props.data,
editorProps: {
attributes: {
class: 'focus:p-2 focus:dark:bg-gray-700 focus:bg-gray-100 focus:border-gray-500 focus:border-1 prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none',
},
transformPastedText(text) {
return text.toUpperCase()
}
},
// '<p>Im running Tiptap with Vue.js. 🎉</p>',
onBeforeCreate({ editor }) {
// Before the view is created.
},
onCreate({ editor }) {
// The editor is ready.
//editor.commands.setContent(data)
// console.log('debugger create '+editor.state)
},
onUpdate({ editor }) {
// The content has changed.
},
onBlur({ editor, event }) {
const data = editor.getHTML()
emit('onEditorBlur', { src: props.src, field: props.field, idx: props.idx, data, ev: event })
},
injectCSS: true,
editable: props.editable,
})
onBeforeMount(async () => {
// const d = useState()
// console.log('Editor: ' + props.data)
})
onBeforeUnmount(async () => {
editor.destroy()
// console.log('Editor: destroy')
})
</script>
<style scoped>
/* Basic editor styles */
/* .ProseMirror {
> * + * {
margin-top: 0.75em;
}
ul,
ol {
padding: 0 1rem;
}
blockquote {
padding-left: 1rem;
border-left: 2px solid rgba(#0D0D0D, 0.1);
}
} */
.bubble-menu {
display: flex;
background-color: #0D0D0D;
padding: 0.2rem;
border-radius: 0.5rem;
}
.bubble-menu button {
border: none;
background: none;
color: #FFF;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
opacity: 0.6;
}
.bubble-menu button:hover,
.bubble-menu button.is-active {
opacity: 1;
}
.floating-menu {
display: flex;
background-color: #0D0D0D10;
padding: 0.2rem;
border-radius: 0.5rem;
}
.dark .floating-menu { background-color: #0D0D0D;}
.floating-menu button {
border: none;
background: none;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
border-left: #7c7c7c 1px solid;
opacity: 0.6;
}
.floating-menu button:hover,
.floating-menu button.is-active {
opacity: 1;
}
</style>