From ec25b94f2246093dda465aada542471d2747bba5 Mon Sep 17 00:00:00 2001 From: runjuu Date: Tue, 13 Jun 2023 10:33:14 -0700 Subject: [PATCH] Add some basic key bindings for Markdown syntax (#628) --- src/app/dashboard/[subdomain]/editor/page.tsx | 3 ++- src/components/ui/CodeMirror.tsx | 2 ++ src/editor/Bold.tsx | 19 ++++++++++++++++--- src/editor/Italic.tsx | 19 ++++++++++++++++--- src/editor/Link.tsx | 19 ++++++++++++++++--- src/editor/Underline.tsx | 17 +++++++++++++++-- src/editor/index.tsx | 8 +++++++- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/app/dashboard/[subdomain]/editor/page.tsx b/src/app/dashboard/[subdomain]/editor/page.tsx index 598a7b8b..6feb98b1 100644 --- a/src/app/dashboard/[subdomain]/editor/page.tsx +++ b/src/app/dashboard/[subdomain]/editor/page.tsx @@ -34,7 +34,7 @@ import { Modal } from "~/components/ui/Modal" import { Switch } from "~/components/ui/Switch" import { TagInput } from "~/components/ui/TagInput" import { UniLink } from "~/components/ui/UniLink" -import { toolbars } from "~/editor" +import { toolbarShortcuts, toolbars } from "~/editor" import { editorUpload } from "~/editor/Multimedia" import { Values, @@ -619,6 +619,7 @@ export default function SubdomainEditor() { "h-full flex-1", isRendering ? "border-r" : "", )} + shortcuts={toolbarShortcuts} /> )} {!isMobileLayout && ( diff --git a/src/components/ui/CodeMirror.tsx b/src/components/ui/CodeMirror.tsx index 36173c5f..f68f5485 100644 --- a/src/components/ui/CodeMirror.tsx +++ b/src/components/ui/CodeMirror.tsx @@ -47,6 +47,7 @@ interface XLogCodeMirrorEditorProps { onCreateEditor?: (view: EditorView, state: EditorState) => void onMouseEnter?: () => void LoadingComponent?: () => JSX.Element + shortcuts?: KeyBinding[] } export const CodeMirrorEditor = forwardRef< @@ -189,6 +190,7 @@ const LazyCodeMirrorEditor = forwardRef< }), keymap.of([ + ...(props.shortcuts ?? []), ...defaultKeymap, ...historyKeymap, ...markdownKeymap, diff --git a/src/editor/Bold.tsx b/src/editor/Bold.tsx index b4402e5a..12b88808 100644 --- a/src/editor/Bold.tsx +++ b/src/editor/Bold.tsx @@ -1,10 +1,23 @@ -import { ICommand, wrapExecute } from "." +import { type EditorView } from "@codemirror/view" + +import { type ICommand, wrapExecute } from "." + +const action = (view: EditorView) => { + wrapExecute({ view, prepend: "**", append: "**" }) +} export const Bold: ICommand = { name: "bold", label: "Bold", icon: "icon-[mingcute--bold-line]", - execute: ({ view }) => { - wrapExecute({ view, prepend: "**", append: "**" }) + execute({ view }) { + action(view) + }, + shortcut: { + key: "Mod-b", + run(view) { + action(view) + return true + }, }, } diff --git a/src/editor/Italic.tsx b/src/editor/Italic.tsx index 10710f1b..ae5f9052 100644 --- a/src/editor/Italic.tsx +++ b/src/editor/Italic.tsx @@ -1,10 +1,23 @@ -import { ICommand, wrapExecute } from "." +import { type EditorView } from "@codemirror/view" + +import { type ICommand, wrapExecute } from "." + +const action = (view: EditorView) => { + wrapExecute({ view, prepend: "_", append: "_" }) +} export const Italic: ICommand = { name: "italic", label: "Italic", icon: "icon-[mingcute--italic-line]", - execute: ({ view }) => { - wrapExecute({ view, prepend: "_", append: "_" }) + execute({ view }) { + action(view) + }, + shortcut: { + key: "Mod-i", + run(view) { + action(view) + return true + }, }, } diff --git a/src/editor/Link.tsx b/src/editor/Link.tsx index 72fb038e..2290e7c8 100644 --- a/src/editor/Link.tsx +++ b/src/editor/Link.tsx @@ -1,10 +1,23 @@ -import { ICommand, wrapExecute } from "." +import { type EditorView } from "@codemirror/view" + +import { type ICommand, wrapExecute } from "." + +const action = (view: EditorView) => { + wrapExecute({ view, prepend: "[", append: "]()" }) +} export const Link: ICommand = { name: "link", label: "Link", icon: "icon-[mingcute--link-2-line]", - execute: ({ view }) => { - wrapExecute({ view, prepend: "[", append: "]()" }) + execute({ view }) { + action(view) + }, + shortcut: { + key: "Mod-k", + run(view) { + action(view) + return true + }, }, } diff --git a/src/editor/Underline.tsx b/src/editor/Underline.tsx index 17cd90ef..f07d96b7 100644 --- a/src/editor/Underline.tsx +++ b/src/editor/Underline.tsx @@ -1,10 +1,23 @@ -import { ICommand, wrapExecute } from "." +import { type EditorView } from "@codemirror/view" + +import { type ICommand, wrapExecute } from "." + +const action = (view: EditorView) => { + wrapExecute({ view, prepend: "", append: "" }) +} export const Underline: ICommand = { name: "underline", label: "Underline", icon: "icon-[mingcute--underline-line]", execute: ({ view }) => { - wrapExecute({ view, prepend: "", append: "" }) + action(view) + }, + shortcut: { + key: "Mod-u", + run(view) { + action(view) + return true + }, }, } diff --git a/src/editor/index.tsx b/src/editor/index.tsx index 75427579..48d0879e 100644 --- a/src/editor/index.tsx +++ b/src/editor/index.tsx @@ -1,7 +1,7 @@ import { Dispatch, SetStateAction } from "react" import { EditorSelection } from "@codemirror/state" -import { EditorView } from "@codemirror/view" +import { type EditorView, type KeyBinding } from "@codemirror/view" import { AlignCenter } from "./AlignCenter" import { AlignRight } from "./AlignRight" @@ -42,6 +42,8 @@ export type ICommand

= { transferPayload: (payload: P) => void view: EditorView }) => JSX.Element + + shortcut?: KeyBinding } export type IPrependExecute = { @@ -106,5 +108,9 @@ export const toolbars: ICommand[] = [ Help, ] +export const toolbarShortcuts = toolbars + .map((t) => t.shortcut) + .filter((v: T): v is NonNullable => !!v) + export { wrapExecute } from "./helper" export type { IWrapExecute } from "./helper"