11<script setup lang="ts">
2- import { ClipboardPasteIcon , Contact2Icon , CopyIcon , Redo2Icon , TableIcon , Undo2Icon , UploadCloudIcon } from ' lucide-vue-next'
2+ import type { EditorView } from ' @codemirror/view'
3+ import { altSign , ctrlSign , shiftSign } from ' @md/shared/configs'
4+ import { redoAction , undoAction } from ' @md/shared/editor'
5+ import {
6+ ClipboardPaste ,
7+ Copy ,
8+ Redo2 ,
9+ Replace ,
10+ Search ,
11+ Undo2 ,
12+ WandSparkles ,
13+ } from ' lucide-vue-next'
314import { useEditorStore } from ' @/stores/editor'
15+ import { usePostStore } from ' @/stores/post'
416import { useUIStore } from ' @/stores/ui'
517import { copyPlain } from ' @/utils/clipboard'
618
@@ -13,9 +25,18 @@ const props = withDefaults(defineProps<{
1325const { asSub } = toRefs (props )
1426
1527const editorStore = useEditorStore ()
28+ const postStore = usePostStore ()
1629const uiStore = useUIStore ()
1730
18- const { toggleShowInsertFormDialog, toggleShowUploadImgDialog, toggleShowInsertMpCardDialog } = uiStore
31+ const { editor } = storeToRefs (editorStore )
32+
33+ // Format content function
34+ async function formatContent() {
35+ const doc = await editorStore .formatContent ()
36+ if (doc && postStore .currentPost ) {
37+ postStore .updatePostContent (postStore .currentPostId , doc )
38+ }
39+ }
1940
2041// Clipboard operations
2142async function copyToClipboard() {
@@ -33,13 +54,56 @@ async function pasteFromClipboard() {
3354 }
3455}
3556
36- // Undo/Redo (handled by keyboard shortcuts)
57+ // Undo/Redo
3758function undo() {
38- console .log (` Undo should be handled by keyboard shortcuts ` )
59+ if (! editor .value )
60+ return
61+
62+ try {
63+ const editorView = toRaw (editor .value ) as EditorView
64+ undoAction (editorView )
65+ editorView .focus ()
66+ }
67+ catch (error ) {
68+ console .error (' Undo failed:' , error )
69+ }
3970}
4071
4172function redo() {
42- console .log (` Redo should be handled by keyboard shortcuts ` )
73+ if (! editor .value )
74+ return
75+
76+ try {
77+ const editorView = toRaw (editor .value ) as EditorView
78+ redoAction (editorView )
79+ editorView .focus ()
80+ }
81+ catch (error ) {
82+ console .error (' Redo failed:' , error )
83+ }
84+ }
85+
86+ // Search/Replace - 使用项目已有的 SearchTab 组件
87+ function openSearch() {
88+ // 触发打开搜索面板
89+ if (editor .value ) {
90+ const selection = editor .value .state .selection .main
91+ const selected = editor .value .state .doc .sliceString (selection .from , selection .to ).trim ()
92+
93+ // 使用 UI store 来触发搜索面板的打开
94+ uiStore .openSearchTab (selected )
95+ }
96+ }
97+
98+ function openReplace() {
99+ // 打开搜索面板并展开替换功能
100+ if (editor .value ) {
101+ const selection = editor .value .state .selection .main
102+ const selected = editor .value .state .doc .sliceString (selection .from , selection .to ).trim ()
103+
104+ // 使用 UI store 来触发搜索面板的打开,并显示替换选项
105+ uiStore .openSearchTab (selected , true )
106+ }
43107}
44108 </script >
45109
@@ -49,51 +113,76 @@ function redo() {
49113 <MenubarSubTrigger >
50114 编辑
51115 </MenubarSubTrigger >
52- <MenubarSubContent >
116+ <MenubarSubContent class = " w-60 " >
53117 <!-- 历史操作 -->
54118 <MenubarItem @click =" undo()" >
55- <Undo2Icon class =" mr-2 h-4 w-4" />
119+ <Undo2 class =" mr-2 h-4 w-4" />
56120 撤销
121+ <MenubarShortcut >
122+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
123+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >Z</kbd >
124+ </MenubarShortcut >
57125 </MenubarItem >
58126 <MenubarItem @click =" redo()" >
59- <Redo2Icon class =" mr-2 h-4 w-4" />
127+ <Redo2 class =" mr-2 h-4 w-4" />
60128 重做
129+ <MenubarShortcut >
130+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
131+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >Y</kbd >
132+ </MenubarShortcut >
61133 </MenubarItem >
62134
63135 <MenubarSeparator />
64136
65- <!-- 插入操作子菜单 -->
66- <MenubarSub >
67- <MenubarSubTrigger >
68- <TableIcon class =" mr-2 h-4 w-4" />
69- 插入
70- </MenubarSubTrigger >
71- <MenubarSubContent >
72- <MenubarItem @click =" toggleShowUploadImgDialog()" >
73- <UploadCloudIcon class =" mr-2 h-4 w-4" />
74- 插入图片
75- </MenubarItem >
76- <MenubarItem @click =" toggleShowInsertFormDialog()" >
77- <TableIcon class =" mr-2 h-4 w-4" />
78- 插入表格
79- </MenubarItem >
80- <MenubarItem @click =" toggleShowInsertMpCardDialog()" >
81- <Contact2Icon class =" mr-2 h-4 w-4" />
82- 插入公众号名片
83- </MenubarItem >
84- </MenubarSubContent >
85- </MenubarSub >
86-
87- <MenubarSeparator />
88-
89137 <!-- 剪贴板操作 -->
90138 <MenubarItem @click =" copyToClipboard()" >
91- <CopyIcon class =" mr-2 h-4 w-4" />
139+ <Copy class =" mr-2 h-4 w-4" />
92140 复制
141+ <MenubarShortcut >
142+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
143+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >C</kbd >
144+ </MenubarShortcut >
93145 </MenubarItem >
94146 <MenubarItem @click =" pasteFromClipboard()" >
95- <ClipboardPasteIcon class =" mr-2 h-4 w-4" />
147+ <ClipboardPaste class =" mr-2 h-4 w-4" />
96148 粘贴
149+ <MenubarShortcut >
150+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
151+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >V</kbd >
152+ </MenubarShortcut >
153+ </MenubarItem >
154+
155+ <MenubarSeparator />
156+
157+ <!-- 格式化文档 -->
158+ <MenubarItem @click =" formatContent()" >
159+ <WandSparkles class =" mr-2 h-4 w-4" />
160+ 格式化文档
161+ <MenubarShortcut >
162+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ altSign }}</kbd >
163+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ shiftSign }}</kbd >
164+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >F</kbd >
165+ </MenubarShortcut >
166+ </MenubarItem >
167+
168+ <MenubarSeparator />
169+
170+ <!-- 查找替换 -->
171+ <MenubarItem @click =" openSearch()" >
172+ <Search class =" mr-2 h-4 w-4" />
173+ 查找
174+ <MenubarShortcut >
175+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
176+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >F</kbd >
177+ </MenubarShortcut >
178+ </MenubarItem >
179+ <MenubarItem @click =" openReplace()" >
180+ <Replace class =" mr-2 h-4 w-4" />
181+ 替换
182+ <MenubarShortcut >
183+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
184+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >H</kbd >
185+ </MenubarShortcut >
97186 </MenubarItem >
98187 </MenubarSubContent >
99188 </MenubarSub >
@@ -103,51 +192,76 @@ function redo() {
103192 <MenubarTrigger >
104193 编辑
105194 </MenubarTrigger >
106- <MenubarContent align =" start" >
195+ <MenubarContent class = " w-60 " align =" start" >
107196 <!-- 历史操作 -->
108197 <MenubarItem @click =" undo()" >
109- <Undo2Icon class =" mr-2 h-4 w-4" />
198+ <Undo2 class =" mr-2 h-4 w-4" />
110199 撤销
200+ <MenubarShortcut >
201+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
202+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >Z</kbd >
203+ </MenubarShortcut >
111204 </MenubarItem >
112205 <MenubarItem @click =" redo()" >
113- <Redo2Icon class =" mr-2 h-4 w-4" />
206+ <Redo2 class =" mr-2 h-4 w-4" />
114207 重做
208+ <MenubarShortcut >
209+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
210+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >Y</kbd >
211+ </MenubarShortcut >
115212 </MenubarItem >
116213
117214 <MenubarSeparator />
118215
119- <!-- 插入操作子菜单 -->
120- <MenubarSub >
121- <MenubarSubTrigger >
122- <TableIcon class =" mr-2 h-4 w-4" />
123- 插入
124- </MenubarSubTrigger >
125- <MenubarSubContent >
126- <MenubarItem @click =" toggleShowUploadImgDialog()" >
127- <UploadCloudIcon class =" mr-2 h-4 w-4" />
128- 插入图片
129- </MenubarItem >
130- <MenubarItem @click =" toggleShowInsertFormDialog()" >
131- <TableIcon class =" mr-2 h-4 w-4" />
132- 插入表格
133- </MenubarItem >
134- <MenubarItem @click =" toggleShowInsertMpCardDialog()" >
135- <Contact2Icon class =" mr-2 h-4 w-4" />
136- 插入公众号名片
137- </MenubarItem >
138- </MenubarSubContent >
139- </MenubarSub >
140-
141- <MenubarSeparator />
142-
143216 <!-- 剪贴板操作 -->
144217 <MenubarItem @click =" copyToClipboard()" >
145- <CopyIcon class =" mr-2 h-4 w-4" />
218+ <Copy class =" mr-2 h-4 w-4" />
146219 复制
220+ <MenubarShortcut >
221+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
222+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >C</kbd >
223+ </MenubarShortcut >
147224 </MenubarItem >
148225 <MenubarItem @click =" pasteFromClipboard()" >
149- <ClipboardPasteIcon class =" mr-2 h-4 w-4" />
226+ <ClipboardPaste class =" mr-2 h-4 w-4" />
150227 粘贴
228+ <MenubarShortcut >
229+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
230+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >V</kbd >
231+ </MenubarShortcut >
232+ </MenubarItem >
233+
234+ <MenubarSeparator />
235+
236+ <!-- 格式化文档 -->
237+ <MenubarItem @click =" formatContent()" >
238+ <WandSparkles class =" mr-2 h-4 w-4" />
239+ 格式化文档
240+ <MenubarShortcut >
241+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ altSign }}</kbd >
242+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ shiftSign }}</kbd >
243+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >F</kbd >
244+ </MenubarShortcut >
245+ </MenubarItem >
246+
247+ <MenubarSeparator />
248+
249+ <!-- 查找替换 -->
250+ <MenubarItem @click =" openSearch()" >
251+ <Search class =" mr-2 h-4 w-4" />
252+ 查找
253+ <MenubarShortcut >
254+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
255+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >F</kbd >
256+ </MenubarShortcut >
257+ </MenubarItem >
258+ <MenubarItem @click =" openReplace()" >
259+ <Replace class =" mr-2 h-4 w-4" />
260+ 替换
261+ <MenubarShortcut >
262+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >{{ ctrlSign }}</kbd >
263+ <kbd class =" mx-1 bg-gray-2 dark:bg-stone-9" >H</kbd >
264+ </MenubarShortcut >
151265 </MenubarItem >
152266 </MenubarContent >
153267 </MenubarMenu >
0 commit comments