From 178c0704c8f38084f91b40f67b04a0df8f904c78 Mon Sep 17 00:00:00 2001 From: Hilary Liu <2788370451@qq.com> Date: Fri, 1 Sep 2023 10:30:12 +0800 Subject: [PATCH] feat: add support for saving post by shortcut keys (#4510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /area editor /area console #### What this PR does / why we need it: 1. mac: 在编辑器中添加command+s保存文章 2. windows: 在编辑器中添加ctrl+s保存文章 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4340 #### Does this PR introduce a user-facing change? ```release-note Console 端支持通过快捷键保存文章 ``` --- .../src/components/button/SubmitButton.vue | 3 +-- .../src/composables/use-save-keybinding.ts | 21 +++++++++++++++++++ console/src/layouts/BasicLayout.vue | 3 +-- .../contents/pages/SinglePageEditor.vue | 3 +++ .../src/modules/contents/posts/PostEditor.vue | 3 +++ console/src/utils/device.ts | 1 + 6 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 console/src/composables/use-save-keybinding.ts create mode 100644 console/src/utils/device.ts diff --git a/console/src/components/button/SubmitButton.vue b/console/src/components/button/SubmitButton.vue index dc3d36e9f..597dbd588 100644 --- a/console/src/components/button/SubmitButton.vue +++ b/console/src/components/button/SubmitButton.vue @@ -1,4 +1,5 @@ <script lang="ts" setup> +import { isMac } from "@/utils/device"; import { VButton } from "@halo-dev/components"; import { useMagicKeys } from "@vueuse/core"; import { computed, useAttrs, watchEffect } from "vue"; @@ -19,8 +20,6 @@ const emit = defineEmits<{ (event: "submit"): void; }>(); -const isMac = /macintosh|mac os x/i.test(navigator.userAgent); - const attrs = useAttrs(); const buttonText = computed(() => { diff --git a/console/src/composables/use-save-keybinding.ts b/console/src/composables/use-save-keybinding.ts new file mode 100644 index 000000000..cdfb7686c --- /dev/null +++ b/console/src/composables/use-save-keybinding.ts @@ -0,0 +1,21 @@ +import { isMac } from "@/utils/device"; +import { useEventListener } from "@vueuse/core"; +import { useDebounceFn } from "@vueuse/shared"; +import { nextTick } from "vue"; + +export function useSaveKeybinding(fn: () => void) { + const debouncedFn = useDebounceFn(() => { + fn(); + }, 300); + + useEventListener(window, "keydown", (e: KeyboardEvent) => { + if (isMac ? e.metaKey : e.ctrlKey) { + if (e.key === "s") { + e.preventDefault(); + nextTick(() => { + debouncedFn(); + }); + } + } + }); +} diff --git a/console/src/layouts/BasicLayout.vue b/console/src/layouts/BasicLayout.vue index 486c20d13..4aa16ffb0 100644 --- a/console/src/layouts/BasicLayout.vue +++ b/console/src/layouts/BasicLayout.vue @@ -34,6 +34,7 @@ import { useOverlayScrollbars, type UseOverlayScrollbarsParams, } from "overlayscrollbars-vue"; +import { isMac } from "@/utils/device"; const route = useRoute(); const router = useRouter(); @@ -70,8 +71,6 @@ const handleLogout = () => { // Global Search const globalSearchVisible = ref(false); -const isMac = /macintosh|mac os x/i.test(navigator.userAgent); - const handleGlobalSearchKeybinding = (e: KeyboardEvent) => { const { key, ctrlKey, metaKey } = e; if (key === "k" && ((ctrlKey && !isMac) || metaKey)) { diff --git a/console/src/modules/contents/pages/SinglePageEditor.vue b/console/src/modules/contents/pages/SinglePageEditor.vue index 77e03cc11..7d733f972 100644 --- a/console/src/modules/contents/pages/SinglePageEditor.vue +++ b/console/src/modules/contents/pages/SinglePageEditor.vue @@ -38,6 +38,7 @@ import { contentAnnotations } from "@/constants/annotations"; import { usePageUpdateMutate } from "./composables/use-page-update-mutate"; import { useAutoSaveContent } from "@/composables/use-auto-save-content"; import { useContentSnapshot } from "@/composables/use-content-snapshot"; +import { useSaveKeybinding } from "@/composables/use-save-keybinding"; const router = useRouter(); const { t } = useI18n(); @@ -365,6 +366,8 @@ const handlePreview = async () => { previewModal.value = true; previewPending.value = false; }; + +useSaveKeybinding(handleSave); </script> <template> diff --git a/console/src/modules/contents/posts/PostEditor.vue b/console/src/modules/contents/posts/PostEditor.vue index 5f0824c3f..e56c94512 100644 --- a/console/src/modules/contents/posts/PostEditor.vue +++ b/console/src/modules/contents/posts/PostEditor.vue @@ -38,6 +38,7 @@ import { usePostUpdateMutate } from "./composables/use-post-update-mutate"; import { contentAnnotations } from "@/constants/annotations"; import { useAutoSaveContent } from "@/composables/use-auto-save-content"; import { useContentSnapshot } from "@/composables/use-content-snapshot"; +import { useSaveKeybinding } from "@/composables/use-save-keybinding"; const router = useRouter(); const { t } = useI18n(); @@ -381,6 +382,8 @@ const handlePreview = async () => { previewModal.value = true; previewPending.value = false; }; + +useSaveKeybinding(handleSave); </script> <template> diff --git a/console/src/utils/device.ts b/console/src/utils/device.ts new file mode 100644 index 000000000..57a34be8b --- /dev/null +++ b/console/src/utils/device.ts @@ -0,0 +1 @@ +export const isMac = /macintosh|mac os x/i.test(navigator.userAgent);