feat(WIP): tiptap 에디터 기능 구현
This commit is contained in:
@@ -75,8 +75,32 @@
|
|||||||
</b-button-group>
|
</b-button-group>
|
||||||
|
|
||||||
<b-button-group class="mx-1">
|
<b-button-group class="mx-1">
|
||||||
<!-- 마지막으로 사용한 색 -->
|
<b-button
|
||||||
<!-- 배경색, 글자색 -->
|
@click="editor.chain().focus().unsetColor().unsetBackgroundColor().run()"
|
||||||
|
v-b-tooltip.hover
|
||||||
|
title="색상 취소"
|
||||||
|
><i class="bi bi-droplet"></i
|
||||||
|
></b-button>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
class="form-control form-control-color"
|
||||||
|
:value="
|
||||||
|
colorConvert(editor.getAttributes('textStyle').color, '#ffffff')
|
||||||
|
"
|
||||||
|
@input="editor.chain().focus().setColor($event.target.value).run()"
|
||||||
|
v-b-tooltip.hover
|
||||||
|
title="글자색"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
class="form-control form-control-color"
|
||||||
|
:value="
|
||||||
|
colorConvert(editor.getAttributes('textStyle').backgroundColor, '#000000')
|
||||||
|
"
|
||||||
|
@input="editor.chain().focus().setBackgroundColor($event.target.value).run()"
|
||||||
|
v-b-tooltip.hover
|
||||||
|
title="배경색"
|
||||||
|
/>
|
||||||
</b-button-group>
|
</b-button-group>
|
||||||
|
|
||||||
<b-button-group class="mx-1">
|
<b-button-group class="mx-1">
|
||||||
@@ -85,6 +109,12 @@
|
|||||||
<!-- 영상링크 -->
|
<!-- 영상링크 -->
|
||||||
<!-- 표 -->
|
<!-- 표 -->
|
||||||
<!-- 구분선 삽입 -->
|
<!-- 구분선 삽입 -->
|
||||||
|
<b-button
|
||||||
|
@click="editor.chain().focus().setHorizontalRule().run()"
|
||||||
|
v-b-tooltip.hover
|
||||||
|
title="구분선"
|
||||||
|
><i class="bi bi-hr"></i
|
||||||
|
></b-button>
|
||||||
</b-button-group>
|
</b-button-group>
|
||||||
|
|
||||||
<b-button-group class="mx-1">
|
<b-button-group class="mx-1">
|
||||||
@@ -114,6 +144,9 @@
|
|||||||
<!-- 문단정렬(왼, 가, 오, 양)(내어, 들여) -->
|
<!-- 문단정렬(왼, 가, 오, 양)(내어, 들여) -->
|
||||||
</b-button-group>
|
</b-button-group>
|
||||||
|
|
||||||
|
<b-button-group class="mx-1">
|
||||||
|
</b-button-group>
|
||||||
|
|
||||||
<b-button-group class="mx-1">
|
<b-button-group class="mx-1">
|
||||||
<!-- 줄간격 (1.0, 1.2, 1.4, 1.5, 1.6, 1.8, 2.0, 3.0) -->
|
<!-- 줄간격 (1.0, 1.2, 1.4, 1.5, 1.6, 1.8, 2.0, 3.0) -->
|
||||||
</b-button-group>
|
</b-button-group>
|
||||||
@@ -134,6 +167,8 @@ import StarterKit from "@tiptap/starter-kit";
|
|||||||
import Underline from "@tiptap/extension-underline";
|
import Underline from "@tiptap/extension-underline";
|
||||||
import TextStyle from "@tiptap/extension-text-style";
|
import TextStyle from "@tiptap/extension-text-style";
|
||||||
import TextAlign from "@tiptap/extension-text-align";
|
import TextAlign from "@tiptap/extension-text-align";
|
||||||
|
import Color from "@tiptap/extension-color";
|
||||||
|
import { BackgroundColor } from "@/tiptap-ext/BackgroundColor";
|
||||||
import {
|
import {
|
||||||
BButtonGroup,
|
BButtonGroup,
|
||||||
BButtonToolbar,
|
BButtonToolbar,
|
||||||
@@ -153,6 +188,26 @@ const compoment = defineComponent({
|
|||||||
BDropdownItem,
|
BDropdownItem,
|
||||||
BDropdownDivider,
|
BDropdownDivider,
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
colorConvert(val: string | undefined, defaultVal: string) {
|
||||||
|
if (!val) {
|
||||||
|
return defaultVal;
|
||||||
|
}
|
||||||
|
if (val.startsWith("rgb")) {
|
||||||
|
const rgb = val.split("(")[1].split(")")[0].split(",");
|
||||||
|
const vals: string[] = [];
|
||||||
|
for (const subColor of rgb) {
|
||||||
|
const hexSubColor = parseInt(subColor).toString(16);
|
||||||
|
if (hexSubColor.length == 1) {
|
||||||
|
vals.push("0");
|
||||||
|
}
|
||||||
|
vals.push(hexSubColor);
|
||||||
|
}
|
||||||
|
return `#${vals.join("")}`;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
@@ -211,6 +266,12 @@ const compoment = defineComponent({
|
|||||||
TextAlign.configure({
|
TextAlign.configure({
|
||||||
types: ["heading", "paragraph"],
|
types: ["heading", "paragraph"],
|
||||||
}),
|
}),
|
||||||
|
Color.configure({
|
||||||
|
types: ["textStyle"],
|
||||||
|
}),
|
||||||
|
BackgroundColor.configure({
|
||||||
|
types: ["textStyle"],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
editable: this.editable,
|
editable: this.editable,
|
||||||
content: this.modelValue,
|
content: this.modelValue,
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Extension } from '@tiptap/core'
|
||||||
|
import '@tiptap/extension-text-style'
|
||||||
|
|
||||||
|
export type BackgroundColorOptions = {
|
||||||
|
types: string[],
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@tiptap/core' {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
backgroundColor: {
|
||||||
|
/**
|
||||||
|
* Set the text color
|
||||||
|
*/
|
||||||
|
setBackgroundColor: (color: string) => ReturnType,
|
||||||
|
/**
|
||||||
|
* Unset the text color
|
||||||
|
*/
|
||||||
|
unsetBackgroundColor: () => ReturnType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BackgroundColor = Extension.create<BackgroundColorOptions>({
|
||||||
|
name: 'backgroundColor',
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
types: ['textStyle'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addGlobalAttributes() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
types: this.options.types,
|
||||||
|
attributes: {
|
||||||
|
backgroundColor: {
|
||||||
|
default: null,
|
||||||
|
parseHTML: element => element.style.backgroundColor.replace(/['"]+/g, ''),
|
||||||
|
renderHTML: attributes => {
|
||||||
|
if (!attributes.backgroundColor) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
style: `background-color: ${attributes.backgroundColor}`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
setBackgroundColor: backgroundColor => ({ chain }) => {
|
||||||
|
return chain()
|
||||||
|
.setMark('textStyle', { backgroundColor })
|
||||||
|
.run()
|
||||||
|
},
|
||||||
|
unsetBackgroundColor: () => ({ chain }) => {
|
||||||
|
return chain()
|
||||||
|
.setMark('textStyle', { backgroundColor: null })
|
||||||
|
.removeEmptyTextStyle()
|
||||||
|
.run()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tiptap/extension-color": "^2.0.0-beta.9",
|
||||||
"@tiptap/extension-image": "^2.0.0-beta.24",
|
"@tiptap/extension-image": "^2.0.0-beta.24",
|
||||||
"@tiptap/extension-link": "^2.0.0-beta.33",
|
"@tiptap/extension-link": "^2.0.0-beta.33",
|
||||||
"@tiptap/extension-text-align": "^2.0.0-beta.29",
|
"@tiptap/extension-text-align": "^2.0.0-beta.29",
|
||||||
|
|||||||
Reference in New Issue
Block a user