forked from devsam/core
feat(WIP): 새 에디터
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
import "@scss/dipcenter.scss";
|
||||
import "@scss/common_legacy.scss";
|
||||
import TipTap from "./components/TipTap.vue";
|
||||
import { defineComponent, reactive, ref } from "vue";
|
||||
import { defineComponent } from "vue";
|
||||
import { sammoAPI } from "./util/sammoAPI";
|
||||
import { isString } from "lodash";
|
||||
declare const editable: boolean;
|
||||
|
||||
+113
-17
@@ -1,33 +1,75 @@
|
||||
<template>
|
||||
<b-button-toolbar key-nav v-if="editable && editor" class="bg-dark">
|
||||
<!-- 뒤로, 앞으로 -->
|
||||
<b-button-group class="mx-1">
|
||||
<b-button
|
||||
@click="editor.commands.undo()"
|
||||
v-b-tooltip.hover
|
||||
title="되돌리기"
|
||||
><i class="bi bi-arrow-90deg-left"></i
|
||||
></b-button>
|
||||
<b-button @click="editor.commands.redo()" v-b-tooltip.hover title="재실행"
|
||||
><i class="bi bi-arrow-90deg-right"></i
|
||||
></b-button>
|
||||
</b-button-group>
|
||||
<b-button-group class="mx-1">
|
||||
<b-button
|
||||
@click="editor.chain().focus().toggleBold().run()"
|
||||
:class="{ 'is-active': editor.isActive('bold') }"
|
||||
><i class="bi bi-type-bold" v-b-tooltip.hover title="진하게"></i
|
||||
v-b-tooltip.hover
|
||||
title="진하게"
|
||||
><i class="bi bi-type-bold"></i
|
||||
></b-button>
|
||||
<b-button
|
||||
@click="editor.chain().focus().toggleItalic().run()"
|
||||
:class="{ 'is-active': editor.isActive('italic') }"
|
||||
><i class="bi bi-type-italic" v-b-tooltip.hover title="기울이기"></i
|
||||
v-b-tooltip.hover
|
||||
title="기울이기"
|
||||
><i class="bi bi-type-italic"></i
|
||||
></b-button>
|
||||
<!-- 밑줄, 효과 지우기 -->
|
||||
<b-button
|
||||
@click="editor.chain().focus().toggleUnderline().run()"
|
||||
:class="{ 'is-active': editor.isActive('underline') }"
|
||||
v-b-tooltip.hover
|
||||
title="밑줄"
|
||||
><i class="bi bi-type-underline"></i
|
||||
></b-button>
|
||||
<!-- 효과 지우기 -->
|
||||
</b-button-group>
|
||||
|
||||
<b-button-group class="mx-1">
|
||||
<!-- 글꼴, 크기 -->
|
||||
<b-dropdown>
|
||||
<template #button-content> 크기 </template>
|
||||
<b-dropdown-item @click="editor.chain().focus().unsetFontSize().run()"
|
||||
><span>기본</span></b-dropdown-item
|
||||
>
|
||||
<b-dropdown-divider />
|
||||
<b-dropdown-item
|
||||
v-for="sizeItem in fontSize"
|
||||
:key="sizeItem"
|
||||
@click="editor.chain().focus().setFontSize(sizeItem).run()"
|
||||
><span
|
||||
:style="{
|
||||
'font-size': sizeItem,
|
||||
'text-decoration': editor.isActive('textStyle', {
|
||||
fontSize: sizeItem,
|
||||
})
|
||||
? 'underline'
|
||||
: undefined,
|
||||
}"
|
||||
>{{ sizeItem }}</span
|
||||
></b-dropdown-item
|
||||
>
|
||||
</b-dropdown>
|
||||
<!-- 글꼴 -->
|
||||
</b-button-group>
|
||||
|
||||
<b-button-group class="mx-1">
|
||||
<b-button
|
||||
@click="editor.chain().focus().toggleStrike().run()"
|
||||
:class="{ 'is-active': editor.isActive('strike') }"
|
||||
><i
|
||||
class="bi bi-type-strikethrough"
|
||||
v-b-tooltip.hover
|
||||
title="가로선"
|
||||
></i
|
||||
v-b-tooltip.hover
|
||||
title="가로선"
|
||||
><i class="bi bi-type-strikethrough"></i
|
||||
></b-button>
|
||||
<!-- 윗첨자, 아랫첨자 -->
|
||||
</b-button-group>
|
||||
@@ -45,19 +87,37 @@
|
||||
<!-- 구분선 삽입 -->
|
||||
</b-button-group>
|
||||
|
||||
|
||||
<b-button-group class="mx-1">
|
||||
<!-- 글머리 기호 -->
|
||||
<!-- 번호 매기기 -->
|
||||
<b-button
|
||||
@click="editor.chain().focus().setTextAlign('left').run()"
|
||||
:class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }"
|
||||
v-b-tooltip.hover
|
||||
title="왼쪽 정렬"
|
||||
><i class="bi bi-text-left"></i
|
||||
></b-button>
|
||||
<b-button
|
||||
@click="editor.chain().focus().setTextAlign('center').run()"
|
||||
:class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }"
|
||||
v-b-tooltip.hover
|
||||
title="가운데 정렬"
|
||||
><i class="bi bi-text-center"></i
|
||||
></b-button>
|
||||
<b-button
|
||||
@click="editor.chain().focus().setTextAlign('right').run()"
|
||||
:class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }"
|
||||
v-b-tooltip.hover
|
||||
title="오른쪽 정렬"
|
||||
><i class="bi bi-text-right"></i
|
||||
></b-button>
|
||||
<!-- 문단정렬(왼, 가, 오, 양)(내어, 들여) -->
|
||||
</b-button-group>
|
||||
|
||||
|
||||
<b-button-group class="mx-1">
|
||||
<!-- 줄간격 (1.0, 1.2, 1.4, 1.5, 1.6, 1.8, 2.0, 3.0) -->
|
||||
</b-button-group>
|
||||
|
||||
|
||||
<b-button-group class="mx-1">
|
||||
<!-- 원본 코드 -->
|
||||
</b-button-group>
|
||||
@@ -69,8 +129,19 @@
|
||||
//import "@scss/common/bootstrap5.scss";
|
||||
import { defineComponent } from "vue";
|
||||
import { Editor, EditorContent } from "@tiptap/vue-3";
|
||||
import { FontSize } from "@/tiptap-ext/FontSize";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import {BButtonGroup, BButtonToolbar, BButton} from "bootstrap-vue-3";
|
||||
import Underline from "@tiptap/extension-underline";
|
||||
import TextStyle from "@tiptap/extension-text-style";
|
||||
import TextAlign from "@tiptap/extension-text-align";
|
||||
import {
|
||||
BButtonGroup,
|
||||
BButtonToolbar,
|
||||
BButton,
|
||||
BDropdown,
|
||||
BDropdownItem,
|
||||
BDropdownDivider,
|
||||
} from "bootstrap-vue-3";
|
||||
|
||||
const compoment = defineComponent({
|
||||
components: {
|
||||
@@ -78,6 +149,9 @@ const compoment = defineComponent({
|
||||
BButtonGroup,
|
||||
BButtonToolbar,
|
||||
BButton,
|
||||
BDropdown,
|
||||
BDropdownItem,
|
||||
BDropdownDivider,
|
||||
},
|
||||
|
||||
props: {
|
||||
@@ -93,6 +167,19 @@ const compoment = defineComponent({
|
||||
data() {
|
||||
return {
|
||||
editor: null as unknown as InstanceType<typeof Editor>,
|
||||
fontList: ["Pretendard", "맑은 고딕", "궁서", "돋움"],
|
||||
fontSize: [
|
||||
"8px",
|
||||
"10px",
|
||||
"12px",
|
||||
"14px",
|
||||
"18px",
|
||||
"22px",
|
||||
"28px",
|
||||
"36px",
|
||||
"48px",
|
||||
"72px",
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
@@ -108,21 +195,30 @@ const compoment = defineComponent({
|
||||
},
|
||||
editable(value: boolean) {
|
||||
this.editor.options.editable = value;
|
||||
if(value == true){
|
||||
if (value == true) {
|
||||
this.editor.commands.focus();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [StarterKit],
|
||||
const editor = new Editor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Underline,
|
||||
FontSize,
|
||||
TextStyle,
|
||||
TextAlign.configure({
|
||||
types: ["heading", "paragraph"],
|
||||
}),
|
||||
],
|
||||
editable: this.editable,
|
||||
content: this.modelValue,
|
||||
onUpdate: () => {
|
||||
this.$emit("update:modelValue", this.editor.getHTML());
|
||||
},
|
||||
});
|
||||
this.editor = editor;
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { Extension } from '@tiptap/core';
|
||||
import '@tiptap/extension-text-style';
|
||||
|
||||
type FontSizeOptions = {
|
||||
types: string[],
|
||||
}
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands<ReturnType> {
|
||||
fontSize: {
|
||||
/**
|
||||
* Set the font size attribute
|
||||
*/
|
||||
setFontSize: (size: string) => ReturnType,
|
||||
/**
|
||||
* Unset the font size attribute
|
||||
*/
|
||||
unsetFontSize: () => ReturnType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const FontSize = Extension.create<FontSizeOptions>({
|
||||
name: 'fontSize',
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
types: ['textStyle'],
|
||||
}
|
||||
},
|
||||
addGlobalAttributes() {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
fontSize: {
|
||||
default: null,
|
||||
parseHTML: element => element.style.fontSize.replace(/['"]+/g, ''),
|
||||
renderHTML: attributes => {
|
||||
if (!attributes.fontSize) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
style: `font-size: ${attributes.fontSize}`,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setFontSize: fontSize => ({ chain }) => {
|
||||
return chain()
|
||||
.setMark('textStyle', { fontSize })
|
||||
.run()
|
||||
},
|
||||
unsetFontSize: () => ({ chain }) => {
|
||||
return chain()
|
||||
.setMark('textStyle', { fontSize: null })
|
||||
.removeEmptyTextStyle()
|
||||
.run()
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
import 'bootstrap';
|
||||
import PartialDipcenter from '@/PartialDipcenter.vue';
|
||||
import BootstrapVue3 from 'bootstrap-vue-3';
|
||||
import { htmlReady } from './util/htmlReady';
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"dependencies": {
|
||||
"@tiptap/extension-image": "^2.0.0-beta.24",
|
||||
"@tiptap/extension-link": "^2.0.0-beta.33",
|
||||
"@tiptap/extension-text-align": "^2.0.0-beta.29",
|
||||
"@tiptap/extension-text-style": "^2.0.0-beta.23",
|
||||
"@tiptap/extension-underline": "^2.0.0-beta.22",
|
||||
"@tiptap/starter-kit": "^2.0.0-beta.156",
|
||||
"@tiptap/vue-3": "^2.0.0-beta.83",
|
||||
"@types/bootstrap": "^5.1.6",
|
||||
|
||||
Reference in New Issue
Block a user