11<template >
2- <div class =" rich-text-editor" >
2+ <div class =" rich-text-editor" :class = " { 'is-fullscreen': isFullscreen } " >
33 <div v-if =" editor" class =" editor-toolbar" >
4- <button
5- @click =" editor.chain().focus().toggleBold().run()"
6- :class =" { 'is-active': editor.isActive('bold') }"
7- >
8- <i class =" ri-bold" ></i >
9- </button >
10- <button
11- @click =" editor.chain().focus().toggleItalic().run()"
12- :class =" { 'is-active': editor.isActive('italic') }"
13- >
14- <i class =" ri-italic" ></i >
15- </button >
16- <button
17- @click =" editor.chain().focus().toggleStrike().run()"
18- :class =" { 'is-active': editor.isActive('strike') }"
19- >
20- <i class =" ri-strikethrough" ></i >
21- </button >
22- <button
23- @click =" editor.chain().focus().toggleCode().run()"
24- :class =" { 'is-active': editor.isActive('code') }"
25- >
26- <i class =" ri-code-line" ></i >
27- </button >
28- <div class =" divider" ></div >
29- <button
30- @click =" editor.chain().focus().toggleHeading({ level: 1 }).run()"
31- :class =" { 'is-active': editor.isActive('heading', { level: 1 }) }"
32- >
33- H1
34- </button >
35- <button
36- @click =" editor.chain().focus().toggleHeading({ level: 2 }).run()"
37- :class =" { 'is-active': editor.isActive('heading', { level: 2 }) }"
38- >
39- H2
40- </button >
41- <button
42- @click =" editor.chain().focus().toggleBulletList().run()"
43- :class =" { 'is-active': editor.isActive('bulletList') }"
44- >
45- <i class =" ri-list-unordered" ></i >
46- </button >
47- <button
48- @click =" editor.chain().focus().toggleOrderedList().run()"
49- :class =" { 'is-active': editor.isActive('orderedList') }"
50- >
51- <i class =" ri-list-ordered" ></i >
52- </button >
53- <button
54- @click =" editor.chain().focus().toggleBlockquote().run()"
55- :class =" { 'is-active': editor.isActive('blockquote') }"
56- >
57- <i class =" ri-double-quotes-l" ></i >
58- </button >
4+ <div class =" toolbar-left" >
5+ <button
6+ @click =" editor.chain().focus().toggleBold().run()"
7+ :class =" { 'is-active': editor.isActive('bold') }"
8+ >
9+ <i class =" ri-bold" ></i >
10+ </button >
11+ <button
12+ @click =" editor.chain().focus().toggleItalic().run()"
13+ :class =" { 'is-active': editor.isActive('italic') }"
14+ >
15+ <i class =" ri-italic" ></i >
16+ </button >
17+ <button
18+ @click =" editor.chain().focus().toggleStrike().run()"
19+ :class =" { 'is-active': editor.isActive('strike') }"
20+ >
21+ <i class =" ri-strikethrough" ></i >
22+ </button >
23+ <button
24+ @click =" editor.chain().focus().toggleCode().run()"
25+ :class =" { 'is-active': editor.isActive('code') }"
26+ >
27+ <i class =" ri-code-line" ></i >
28+ </button >
29+ <div class =" divider" ></div >
30+ <button
31+ @click =" editor.chain().focus().toggleHeading({ level: 1 }).run()"
32+ :class =" { 'is-active': editor.isActive('heading', { level: 1 }) }"
33+ >
34+ H1
35+ </button >
36+ <button
37+ @click =" editor.chain().focus().toggleHeading({ level: 2 }).run()"
38+ :class =" { 'is-active': editor.isActive('heading', { level: 2 }) }"
39+ >
40+ H2
41+ </button >
42+ <button
43+ @click =" editor.chain().focus().toggleBulletList().run()"
44+ :class =" { 'is-active': editor.isActive('bulletList') }"
45+ >
46+ <i class =" ri-list-unordered" ></i >
47+ </button >
48+ <button
49+ @click =" editor.chain().focus().toggleOrderedList().run()"
50+ :class =" { 'is-active': editor.isActive('orderedList') }"
51+ >
52+ <i class =" ri-list-ordered" ></i >
53+ </button >
54+ <button
55+ @click =" editor.chain().focus().toggleBlockquote().run()"
56+ :class =" { 'is-active': editor.isActive('blockquote') }"
57+ >
58+ <i class =" ri-double-quotes-l" ></i >
59+ </button >
60+ </div >
61+ <div class =" toolbar-right" >
62+ <button
63+ @click =" toggleFullscreen"
64+ class =" fullscreen-btn"
65+ :title =" isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'"
66+ >
67+ <i :class =" isFullscreen ? 'ri-fullscreen-exit-line' : 'ri-fullscreen-line'" ></i >
68+ </button >
69+ </div >
5970 </div >
6071 <editor-content :editor =" editor" class =" editor-content" />
6172 </div >
@@ -66,6 +77,7 @@ import { useEditor, EditorContent } from '@tiptap/vue-3'
6677import StarterKit from ' @tiptap/starter-kit'
6778import Placeholder from ' @tiptap/extension-placeholder'
6879import Link from ' @tiptap/extension-link'
80+ import { ref } from ' vue'
6981
7082export default {
7183 name: ' RichTextEditor' ,
@@ -88,6 +100,8 @@ export default {
88100 },
89101 emits: [' update:modelValue' , ' blur' ],
90102 setup (props , { emit }) {
103+ const isFullscreen = ref (false )
104+
91105 const editor = useEditor ({
92106 content: props .modelValue ,
93107 extensions: [
@@ -108,8 +122,14 @@ export default {
108122 },
109123 })
110124
125+ const toggleFullscreen = () => {
126+ isFullscreen .value = ! isFullscreen .value
127+ }
128+
111129 return {
112130 editor,
131+ isFullscreen,
132+ toggleFullscreen,
113133 }
114134 },
115135 watch: {
@@ -138,17 +158,56 @@ export default {
138158 border-radius : 4px ;
139159 overflow : hidden ;
140160 background-color : var (--el-bg-color );
161+ position : relative ;
162+ transition : all 0.3s ease ;
163+ }
164+
165+ .rich-text-editor.is-fullscreen {
166+ position : fixed !important ;
167+ top : 56px !important ;
168+ left : 0 !important ;
169+ right : 0 !important ;
170+ bottom : 0 !important ;
171+ width : 100vw !important ;
172+ height : calc (100vh - 56px ) !important ;
173+ z-index : 2999 !important ;
174+ border-radius : 0 ;
175+ margin : 0 ;
176+ }
177+
178+ .is-fullscreen .editor-toolbar {
179+ position : sticky ;
180+ top : 0 ;
181+ z-index : 3000 !important ;
182+ background-color : var (--el-fill-color-light );
183+ box-shadow : 0 2px 8px rgba (0 , 0 , 0 , 0.1 );
141184}
142185
143186.editor-toolbar {
144187 display : flex ;
188+ justify-content : space-between ;
189+ align-items : center ;
145190 flex-wrap : wrap ;
146191 gap : 4px ;
147192 padding : 8px ;
148193 border-bottom : 1px solid var (--el-border-color-lighter );
149194 background-color : var (--el-fill-color-light );
150195}
151196
197+ .toolbar-left {
198+ display : flex ;
199+ flex-wrap : wrap ;
200+ gap : 4px ;
201+ align-items : center ;
202+ }
203+
204+ .toolbar-right {
205+ display : flex ;
206+ gap : 4px ;
207+ align-items : center ;
208+ margin-left : auto ;
209+ }
210+
152211.editor-toolbar button {
153212 border : none ;
154213 background : transparent ;
@@ -157,6 +216,7 @@ export default {
157216 cursor : pointer ;
158217 color : var (--el-text-color-regular );
159218 font-size : 14px ;
219+ transition : all 0.2s ;
160220}
161221
162222.editor-toolbar button :hover {
@@ -168,22 +228,45 @@ export default {
168228 color : var (--el-color-primary );
169229}
170230
231+ .fullscreen-btn {
232+ padding : 6px 10px !important ;
233+ }
234+
235+ .fullscreen-btn i {
236+ font-size : 16px ;
237+ }
238+
171239.divider {
172240 width : 1px ;
173241 background-color : var (--el-border-color );
174242 margin : 0 4px ;
243+ height : 20px ;
175244}
176245
177246.editor-content {
178247 padding : 12px ;
179248 min-height : 150px ;
249+ overflow-y : auto ;
250+ transition : all 0.3s ease ;
251+ }
252+
253+ .is-fullscreen .editor-content {
254+ min-height : calc (100vh - 116px );
255+ max-height : calc (100vh - 116px );
256+ padding : 24px ;
180257}
181258
182259:deep(.ProseMirror ) {
183260 outline : none ;
184261 min-height : 150px ;
185262}
186263
264+ .is-fullscreen :deep(.ProseMirror ) {
265+ min-height : calc (100vh - 156px );
266+ max-width : 900px ;
267+ margin : 0 auto ;
268+ }
269+
187270:deep(.ProseMirror p .is-editor-empty :first-child ::before ) {
188271 color : #adb5bd ;
189272 content : attr (data-placeholder );
0 commit comments