forked from rc/aircox
integrate tiptap text editor
This commit is contained in:
@ -20,6 +20,11 @@
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tiptap/extension-link": "^2.3.0",
|
||||
"@tiptap/extension-underline": "^2.3.0",
|
||||
"@tiptap/pm": "^2.3.0",
|
||||
"@tiptap/starter-kit": "^2.3.0",
|
||||
"@tiptap/vue-3": "^2.3.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"bulma": "^0.9.4",
|
||||
"eslint": "^7.32.0",
|
||||
|
132
assets/src/components/AEditor.vue
Normal file
132
assets/src/components/AEditor.vue
Normal file
@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<input ref="input" type="hidden" :name="name" :value="value"/>
|
||||
<div class="">
|
||||
<template v-for="group, index in menu" :key="index">
|
||||
<div class="button-group d-inline-block mr-3">
|
||||
<template v-for="info, index in group" :key="index">
|
||||
<button type="button" class="button square smaller" :title="info.label" @click="edit(info.action, ...(info.args || []))">
|
||||
<span class="icon"><i :class="info.icon"/></span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<div class="button-group d-inline-block">
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button square smaller">
|
||||
<span class="icon"><i class="fa fa-link"/></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" style="min-width: 20rem; margin-top: -0.2rem;">
|
||||
<div class="dropdown-content p-3">
|
||||
<div class="field">
|
||||
<label class="label">Lien</label>
|
||||
<div class="control">
|
||||
<input ref="link-url" type="text" class="input" placeholder="lien"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="has-text-right">
|
||||
<button type="button" class="button secondary"
|
||||
@click="edit('setLink', {href:$refs['link-url'].value})">
|
||||
Ajouter le lien
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="button square smaller" title="Remove link" @click="edit('unsetLink')">
|
||||
<span class="icon"><i class="fa fa-link-slash"/></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content class="editor" v-if="editor" :editor="editor" />
|
||||
</template>
|
||||
<style>
|
||||
.editor .tiptap {
|
||||
border: 1px black solid;
|
||||
padding: 0.3em;
|
||||
}
|
||||
.editor .tiptap ul, .editor .tiptap ol {
|
||||
margin-left: 1.3em;
|
||||
}
|
||||
|
||||
.editor .tiptap ul { list-style: disc }
|
||||
</style>
|
||||
<script>
|
||||
import { Editor, EditorContent } from '@tiptap/vue-3'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Underline from '@tiptap/extension-underline'
|
||||
import Link from '@tiptap/extension-link'
|
||||
|
||||
export default {
|
||||
components: {EditorContent},
|
||||
props: {
|
||||
config: {type: Object, default: (() => {})},
|
||||
//! Input field name.
|
||||
name: String,
|
||||
//! Initial input value
|
||||
initial: String,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
menu: [
|
||||
[
|
||||
{label: "Bold", icon: "fa fa-bold", action: "toggleBold" },
|
||||
{label: "Italic", icon: "fa fa-italic", action: "toggleItalic" },
|
||||
{label: "Underline", icon: "fa fa-underline", action: "toggleUnderline" },
|
||||
{label: "Strike", icon: "fa fa-strikethrough", action: "toggleStrike" },
|
||||
],[
|
||||
{label: "List", icon: "fa fa-list", action: "toggleBulletList" },
|
||||
{label: "Ordered List", icon: "fa fa-list-ol", action: "toggleOrderedList" },
|
||||
],[
|
||||
{label: "Heading 1", icon: "fa fa-h", action: "setHeading", args: [{level:3}] },
|
||||
{label: "Heading 2", icon: "fa fa-h smaller", action: "toggleHeading", args: [{level:4}] },
|
||||
// {label: "Heading 3", icon: "fa fa-h small", action: "toggleHeading", args: [{level:5}] },
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
value() { return this.editor && this.editor.getHTML() },
|
||||
},
|
||||
|
||||
methods: {
|
||||
chain(action, ...args) {
|
||||
let chain = this.editor.chain().focus()
|
||||
return chain[action](...args)
|
||||
},
|
||||
|
||||
edit(action, ...args) {
|
||||
this.chain(action, ...args).run()
|
||||
},
|
||||
|
||||
setLink() {
|
||||
this.edit("setLink", {href: this.$refs['link-url']})
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
content: this.initial || "",
|
||||
injectCss: false,
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
heading: {
|
||||
levels: [3, 4, 5]
|
||||
}
|
||||
}),
|
||||
Underline,
|
||||
Link.configure({autolink: true}),
|
||||
],
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
beforeUnmount() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
}
|
||||
</script>
|
@ -6,6 +6,7 @@ import AStreamer from './AStreamer.vue'
|
||||
import AFormSet from './AFormSet.vue'
|
||||
import ATrackListEditor from './ATrackListEditor.vue'
|
||||
import ASoundListEditor from './ASoundListEditor.vue'
|
||||
import AEditor from './AEditor.vue'
|
||||
|
||||
import AManyToManyEdit from "./AManyToManyEdit.vue"
|
||||
|
||||
@ -15,7 +16,7 @@ import base from "./index.js"
|
||||
export const admin = {
|
||||
...base,
|
||||
AManyToManyEdit,
|
||||
AFileUpload, ASelectFile,
|
||||
AFileUpload, ASelectFile, AEditor,
|
||||
AFormSet, ATrackListEditor, ASoundListEditor,
|
||||
AStatistics, AStreamer,
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
:root {
|
||||
--title-1-sz: 1.6rem;
|
||||
--title-2-sz: 1.4rem;
|
||||
--title-3-sz: 1.2rem;
|
||||
--title-3-sz: 1.3rem;
|
||||
--title-4-sz: 1.2rem;
|
||||
--subtitle-1-sz: 1.6rem;
|
||||
--subtitle-2-sz: 1.4rem;
|
||||
--subtitle-3-sz: 1.2rem;
|
||||
@ -96,6 +97,14 @@
|
||||
}
|
||||
|
||||
// ---- headings
|
||||
|
||||
.no-reset h1 { font-size: var(--title-1-sz); }
|
||||
.no-reset h2 { font-size: var(--title-2-sz); }
|
||||
.no-reset h3 { font-size: var(--title-3-sz); }
|
||||
.no-reset h3 { font-size: var(--title-3-sz); }
|
||||
.no-reset h4 { font-size: var(--title-4-sz); }
|
||||
.no-reset h5 { font-size: var(--title-5-sz); }
|
||||
|
||||
.title, .header.preview .title {
|
||||
&.is-1 { font-size: var(--title-1-sz); }
|
||||
&.is-2 { font-size: var(--title-2-sz); }
|
||||
@ -215,6 +224,10 @@
|
||||
&:last-child { border-right: 0px; }
|
||||
}
|
||||
}
|
||||
|
||||
.button-group + .button-group {
|
||||
border-left: 1px solid var(--text-color-light);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,6 +138,9 @@
|
||||
.bg-secondary-light { background-color: var(--secondary-color-light); }
|
||||
.bg-transparent { background-color: transparent; }
|
||||
|
||||
.border { border: 1px solid var(--text-color); }
|
||||
.border-main { border: 1px solid var(--main-color); }
|
||||
.border-secondary { border: 1px solid var(--secondary-color); }
|
||||
.border-bottom-main { border-bottom: 1px solid var(--main-color); }
|
||||
.border-bottom-secondary { border-bottom: 1px solid var(--secondary-color); }
|
||||
|
||||
|
Reference in New Issue
Block a user