integrate tiptap text editor
This commit is contained in:
		
							
								
								
									
										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