From e0eb661c8ff12399a9398894157eaf3cd8a5df78 Mon Sep 17 00:00:00 2001
From: liji <896126514@qq.com>
Date: Thu, 26 Sep 2024 14:40:01 +0800
Subject: [PATCH] feat: printer
---
examples/App.vue | 2 +
package.json | 1 +
pnpm-lock.yaml | 9 ++-
src/components/EchoEditor.vue | 2 +
src/components/Menubars.vue | 21 +-----
src/components/Printer.vue | 73 +++++++++++++++++++
.../FindAndReplace/FindAndReplace.ts | 4 +-
src/extensions/Printer/Printer.ts | 25 +++++++
src/extensions/Printer/index.ts | 1 +
src/extensions/index.ts | 3 +
src/hooks/index.ts | 1 +
src/hooks/useHotkeys.ts | 28 +++++++
src/hooks/useStore.ts | 7 ++
src/locales/locales/en.ts | 1 +
src/locales/locales/zh.ts | 1 +
15 files changed, 157 insertions(+), 22 deletions(-)
create mode 100644 src/components/Printer.vue
create mode 100644 src/extensions/Printer/Printer.ts
create mode 100644 src/extensions/Printer/index.ts
create mode 100644 src/hooks/useHotkeys.ts
diff --git a/examples/App.vue b/examples/App.vue
index 0a92f55..f906845 100644
--- a/examples/App.vue
+++ b/examples/App.vue
@@ -118,6 +118,7 @@ import {
Code,
AI,
Preview,
+ Printer,
} from 'echo-editor'
import { ExportWord } from './extensions/ExportWord'
import OpenAI from 'openai'
@@ -324,6 +325,7 @@ const extensions = [
upload: handleFileUpload,
}),
FindAndReplace.configure({ spacer: true }),
+ Printer,
Preview,
]
async function handleFileUpload(files: File[]) {
diff --git a/package.json b/package.json
index 89d0858..e481faa 100644
--- a/package.json
+++ b/package.json
@@ -114,6 +114,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"echo-drag-handle-plugin": "^0.0.2",
+ "hotkeys-js": "^3.13.7",
"tippy.js": "^6.3.7"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bb9edd9..7b05c7e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -152,6 +152,9 @@ importers:
echo-drag-handle-plugin:
specifier: ^0.0.2
version: 0.0.2(@tiptap/core@2.6.6)(@tiptap/pm@2.6.6)(y-prosemirror@1.2.5)
+ hotkeys-js:
+ specifier: ^3.13.7
+ version: 3.13.7
tippy.js:
specifier: ^6.3.7
version: 6.3.7
@@ -1908,7 +1911,7 @@ packages:
/@types/node-fetch@2.6.11:
resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
dependencies:
- '@types/node': 18.19.33
+ '@types/node': 20.12.12
form-data: 4.0.0
dev: false
@@ -4212,6 +4215,10 @@ packages:
parse-passwd: 1.0.0
dev: true
+ /hotkeys-js@3.13.7:
+ resolution: {integrity: sha512-ygFIdTqqwG4fFP7kkiYlvayZppeIQX2aPpirsngkv1xM1lP0piDY5QEh68nQnIKvz64hfocxhBaD/uK3sSK1yQ==}
+ dev: false
+
/http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
diff --git a/src/components/EchoEditor.vue b/src/components/EchoEditor.vue
index 32d4920..5c9409f 100644
--- a/src/components/EchoEditor.vue
+++ b/src/components/EchoEditor.vue
@@ -16,6 +16,7 @@ import AIMenu from './menus/AIMenu.vue'
import Menubars from './Menubars.vue'
import Toolbar from './Toolbar.vue'
import Preview from './Preview.vue'
+import Printer from './Printer.vue'
import FindAndReplace from './FindAndReplace.vue'
import { EchoEditorOnChange } from '@/type'
import { useDark, useToggle } from '@vueuse/core'
@@ -176,6 +177,7 @@ defineExpose({ editor })
+
([
shortcut: ['mod', 'P'],
action: () => {
// 实现打印
- const content = props.editor.getHTML()
- if (content) {
- const printWindow = window.open('', '', 'width=600,height=600') // 打开新窗口
- if (printWindow) {
- printWindow.document.write(`
-
-
-
-
-
- ${content}
-
-
- `)
- printWindow.document.close() // 关闭文档流
- printWindow.focus() // 聚焦到打印窗口
- printWindow.print() // 调用打印
- printWindow.close() // 打印后关闭窗口
- }
- }
+ store.state.printer = true
},
},
],
diff --git a/src/components/Printer.vue b/src/components/Printer.vue
new file mode 100644
index 0000000..e555114
--- /dev/null
+++ b/src/components/Printer.vue
@@ -0,0 +1,73 @@
+
+
+
+
diff --git a/src/extensions/FindAndReplace/FindAndReplace.ts b/src/extensions/FindAndReplace/FindAndReplace.ts
index c04fb85..74c4a0a 100644
--- a/src/extensions/FindAndReplace/FindAndReplace.ts
+++ b/src/extensions/FindAndReplace/FindAndReplace.ts
@@ -4,6 +4,7 @@ import { Plugin, PluginKey, type EditorState, type Transaction } from '@tiptap/p
import { Node as PMNode } from '@tiptap/pm/model'
import ActionButton from '@/components/ActionButton.vue'
import { useTiptapStore } from '@/hooks'
+import type { GeneralOptions } from '@/type'
const store = useTiptapStore()
declare module '@tiptap/core' {
@@ -198,7 +199,7 @@ const replaceAll = (
export const findAndReplacePluginKey = new PluginKey('findAndReplacePlugin')
-export interface FindAndReplaceOptions {
+export interface FindAndReplaceOptions extends GeneralOptions
{
searchResultClass: string
disableRegex: boolean
}
@@ -218,6 +219,7 @@ export const FindAndReplace = Extension.create ({
diff --git a/src/extensions/Printer/Printer.ts b/src/extensions/Printer/Printer.ts
new file mode 100644
index 0000000..8a3a328
--- /dev/null
+++ b/src/extensions/Printer/Printer.ts
@@ -0,0 +1,25 @@
+import ActionButton from '@/components/ActionButton.vue'
+import { useTiptapStore } from '@/hooks'
+import type { GeneralOptions } from '@/type'
+import { Extension } from '@tiptap/core'
+export interface PrinterOptions extends GeneralOptions {}
+
+const { togglePrinter, state } = useTiptapStore()
+export const Printer = Extension.create({
+ name: 'printer',
+ addOptions() {
+ return {
+ ...this.parent?.(),
+ button: ({ editor, extension, t }) => ({
+ component: ActionButton,
+ componentProps: {
+ tooltip: t('editor.printer.tooltip'),
+ action: () => togglePrinter(),
+ icon: 'Printer',
+ shortcutKeys: ['mod', 'P'],
+ isActive: () => state.printer,
+ },
+ }),
+ }
+ },
+})
diff --git a/src/extensions/Printer/index.ts b/src/extensions/Printer/index.ts
new file mode 100644
index 0000000..26a8973
--- /dev/null
+++ b/src/extensions/Printer/index.ts
@@ -0,0 +1 @@
+export * from './Printer'
diff --git a/src/extensions/index.ts b/src/extensions/index.ts
index fc8bb3a..8d5533d 100644
--- a/src/extensions/index.ts
+++ b/src/extensions/index.ts
@@ -109,3 +109,6 @@ export type { PreviewOptions } from './Preview'
export { Preview } from './Preview'
export { FindAndReplace } from './FindAndReplace'
+
+export { Printer } from './Printer'
+export type { PrinterOptions } from './Printer'
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index c31b401..36dd31b 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,2 +1,3 @@
export { createContext, useContext } from './useContext'
export { useTiptapStore } from './useStore'
+export { useHotkeys } from './useHotkeys'
diff --git a/src/hooks/useHotkeys.ts b/src/hooks/useHotkeys.ts
new file mode 100644
index 0000000..a78a26c
--- /dev/null
+++ b/src/hooks/useHotkeys.ts
@@ -0,0 +1,28 @@
+import hotkeys from 'hotkeys-js'
+import { onBeforeUnmount } from 'vue'
+
+export const useHotkeys = (keys: string, callback: CallableFunction) => {
+ hotkeys.filter = () => true
+
+ // 绑定快捷键
+ const bind = () => {
+ hotkeys(keys, (e: Event) => {
+ e.preventDefault()
+ callback()
+ return false
+ })
+ }
+
+ // 解绑快捷键
+ const unbind = () => {
+ hotkeys.unbind(keys)
+ }
+
+ // 在组件卸载时自动解绑
+ onBeforeUnmount(() => {
+ unbind()
+ })
+
+ // 返回用于手动控制的绑定和解绑函数
+ return { bind, unbind }
+}
diff --git a/src/hooks/useStore.ts b/src/hooks/useStore.ts
index 4aed7ba..36eaf6f 100644
--- a/src/hooks/useStore.ts
+++ b/src/hooks/useStore.ts
@@ -47,6 +47,8 @@ interface Instance {
/** FindAndReplace */
findAndReplace: boolean
+ /** Printer */
+ printer: boolean
}
export const useTiptapStore = createGlobalState(() => {
@@ -62,6 +64,7 @@ export const useTiptapStore = createGlobalState(() => {
showPreview: false,
spellCheck: false,
findAndReplace: false,
+ printer: false,
})
const isFullscreen = computed(() => state.isFullscreen)
@@ -79,6 +82,9 @@ export const useTiptapStore = createGlobalState(() => {
function toggleFindAndReplace() {
state.findAndReplace = !state.findAndReplace
}
+ function togglePrinter() {
+ state.printer = !state.printer
+ }
watchEffect(() => {
state.extensions = _state.extensions
@@ -92,5 +98,6 @@ export const useTiptapStore = createGlobalState(() => {
togglePreview,
toggleSpellCheck,
toggleFindAndReplace,
+ togglePrinter,
}
})
diff --git a/src/locales/locales/en.ts b/src/locales/locales/en.ts
index 77f9400..07251e9 100644
--- a/src/locales/locales/en.ts
+++ b/src/locales/locales/en.ts
@@ -157,6 +157,7 @@ const locale: Record = {
'editor.findAndReplace.replace': 'Replace',
'editor.findAndReplace.replaceAll': 'Replace All',
'editor.findAndReplace.caseSensitive': 'Case Sensitive',
+ 'editor.printer.tooltip': 'Print',
}
export default locale
diff --git a/src/locales/locales/zh.ts b/src/locales/locales/zh.ts
index 493f02a..77c19a5 100644
--- a/src/locales/locales/zh.ts
+++ b/src/locales/locales/zh.ts
@@ -156,6 +156,7 @@ const locale: Record = {
'editor.findAndReplace.replace': '替换',
'editor.findAndReplace.replaceAll': '全部替换',
'editor.findAndReplace.caseSensitive': '区分大小写',
+ 'editor.printer.tooltip': '打印',
}
export default locale