From a45da47927ae57d6ea0207aeca3ff552e7e444d6 Mon Sep 17 00:00:00 2001 From: tabzzz Date: Tue, 4 Feb 2025 15:09:15 +0800 Subject: [PATCH 1/4] =?UTF-8?q?perf(mini-markdown-editor):=20=E4=B8=BA?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=8C=BA=E6=8C=81=E4=B9=85=E5=8C=96=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E9=98=B2=E6=8A=96=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/hooks/use-persist-editor-content.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts b/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts index 085c12d..280b942 100644 --- a/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts +++ b/packages/mini-markdown-editor/src/hooks/use-persist-editor-content.ts @@ -1,6 +1,7 @@ import { EDITOR_CONTENT_KEY } from "@/common"; import { ConfigContext } from "@/components/providers/config-provider"; import { safeLocalStorage } from "@/utils/storage"; +import { useDebounceFn } from "ahooks"; import { useContext } from "react"; export const usePersistEditorContent = () => { @@ -8,11 +9,14 @@ export const usePersistEditorContent = () => { const { local } = useContext(ConfigContext); // 保存内容 - const saveContent = (content: string) => { - if (local) { - localStorage.setItem(EDITOR_CONTENT_KEY, content); - } - }; + const { run: saveContent } = useDebounceFn( + (content: string) => { + if (local) { + localStorage.setItem(EDITOR_CONTENT_KEY, content); + } + }, + { wait: 300 }, + ); // 获取内容 const getContent = (): string => { -- Gitee From 8197f22e0233151e6deeccd7ba6bd479b68c3502 Mon Sep 17 00:00:00 2001 From: tabzzz Date: Tue, 4 Feb 2025 16:00:33 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat(mini-markdown-editor):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=BC=96=E8=BE=91=E5=8C=BA=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=8D=A2=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mini-markdown-editor/src/config/global.ts | 2 +- .../mini-markdown-editor/src/extensions/codemirror/index.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/mini-markdown-editor/src/config/global.ts b/packages/mini-markdown-editor/src/config/global.ts index 3238590..bd5deb2 100644 --- a/packages/mini-markdown-editor/src/config/global.ts +++ b/packages/mini-markdown-editor/src/config/global.ts @@ -4,5 +4,5 @@ import { GlobalConfig } from "@/types/global-config"; export const defaultGlobalConfig: GlobalConfig = { status: true, theme: "light", // 主题 - local: false, // 是否开启本地存储 + local: true, // 是否开启本地存储 }; diff --git a/packages/mini-markdown-editor/src/extensions/codemirror/index.ts b/packages/mini-markdown-editor/src/extensions/codemirror/index.ts index 3679869..1247396 100644 --- a/packages/mini-markdown-editor/src/extensions/codemirror/index.ts +++ b/packages/mini-markdown-editor/src/extensions/codemirror/index.ts @@ -22,5 +22,7 @@ export const createEditorExtensions = (options: ExtensionOptions = {}): Extensio createMarkdownExtension(), createEventExtension({ scrollWrapper, eventExt }), history(), + //? 自动换行,可以考虑添加配置项 + EditorView.lineWrapping, ]; }; -- Gitee From 1885fce2c0f714ec8d4c682bf1eb32df3677e4fb Mon Sep 17 00:00:00 2001 From: tabzzz Date: Tue, 4 Feb 2025 22:08:27 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(mini-markdown-editor):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0emoji=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mini-markdown-editor/package.json | 2 ++ .../src/assets/images/emoji.svg | 1 + .../src/components/Toolbar/Emoji.tsx | 33 +++++++++++++++++++ .../src/components/Toolbar/ToolbarItem.tsx | 10 +++--- .../src/components/Toolbar/index.tsx | 1 + .../src/components/base/DropDownMenu.tsx | 25 +++++++++++--- .../src/config/toolbar/base.tsx | 13 +++++--- .../src/config/toolbar/event.ts | 6 ++++ .../src/extensions/codemirror/hotkeys.ts | 10 +----- .../mini-markdown-editor/src/types/toolbar.ts | 3 +- .../src/utils/insert-content.ts | 22 +++++++++++++ 11 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 packages/mini-markdown-editor/src/assets/images/emoji.svg create mode 100644 packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx diff --git a/packages/mini-markdown-editor/package.json b/packages/mini-markdown-editor/package.json index df7c623..c01d863 100644 --- a/packages/mini-markdown-editor/package.json +++ b/packages/mini-markdown-editor/package.json @@ -14,6 +14,8 @@ "@codemirror/commands": "^6.8.0", "@codemirror/lang-markdown": "^6.3.2", "@codemirror/language-data": "^6.5.1", + "@emoji-mart/data": "^1.2.1", + "@emoji-mart/react": "^1.1.1", "@mini-markdown/material": "workspace:^1.0.0", "@uiw/codemirror-extensions-events": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", diff --git a/packages/mini-markdown-editor/src/assets/images/emoji.svg b/packages/mini-markdown-editor/src/assets/images/emoji.svg new file mode 100644 index 0000000..07c77a6 --- /dev/null +++ b/packages/mini-markdown-editor/src/assets/images/emoji.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx b/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx new file mode 100644 index 0000000..817aacf --- /dev/null +++ b/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx @@ -0,0 +1,33 @@ +import data from "@emoji-mart/data"; +import Picker from "@emoji-mart/react"; +import EmojiIcon from "@/assets/images/emoji.svg?raw"; +import { DropDownMenu } from "../base/DropDownMenu"; +import { FC, useContext, useMemo } from "react"; +import { InsertEmojiEvent } from "@/config/toolbar/event"; +import { ConfigContext } from "@/components/providers/config-provider"; + +export const Emoji: FC = () => { + const { theme } = useContext(ConfigContext); + + // Emoji 选择器 + const EmojiPickerComponent = useMemo( + () => ( + InsertEmojiEvent(emoji)} + locale="zh" + theme={theme === "dark" ? "dark" : "light"} + previewPosition="none" + searchPosition="top" + // skinTonePosition="none" + /> + ), + [theme], + ); + + return ( + EmojiPickerComponent}> + {EmojiIcon &&
} + + ); +}; diff --git a/packages/mini-markdown-editor/src/components/Toolbar/ToolbarItem.tsx b/packages/mini-markdown-editor/src/components/Toolbar/ToolbarItem.tsx index e41d9ae..32ee71b 100644 --- a/packages/mini-markdown-editor/src/components/Toolbar/ToolbarItem.tsx +++ b/packages/mini-markdown-editor/src/components/Toolbar/ToolbarItem.tsx @@ -51,12 +51,10 @@ const ToolbarItemRender: FC = ({ if (list && list.length > 0) { return ( <> - - - {/* {title} */} - {icon &&
} -
-
+ + {/* {title} */} + {icon &&
} +
); } else if (component) { diff --git a/packages/mini-markdown-editor/src/components/Toolbar/index.tsx b/packages/mini-markdown-editor/src/components/Toolbar/index.tsx index 2ac2bad..3d0284f 100644 --- a/packages/mini-markdown-editor/src/components/Toolbar/index.tsx +++ b/packages/mini-markdown-editor/src/components/Toolbar/index.tsx @@ -53,6 +53,7 @@ const Toolbar: FC = () => { ), )} + diff --git a/packages/mini-markdown-editor/src/components/base/DropDownMenu.tsx b/packages/mini-markdown-editor/src/components/base/DropDownMenu.tsx index b323ced..a82bb2d 100644 --- a/packages/mini-markdown-editor/src/components/base/DropDownMenu.tsx +++ b/packages/mini-markdown-editor/src/components/base/DropDownMenu.tsx @@ -6,11 +6,15 @@ import { render, renderKey } from "@/config/toolbar/base"; interface DropDownMenuProps { children: React.ReactNode; - list: ToolbarItemListItem[]; + list?: ToolbarItemListItem[]; + dropdownRender?: () => React.ReactNode; } -export const DropDownMenu = memo(({ children, list }: DropDownMenuProps) => { +export const DropDownMenu = memo(({ children, list, dropdownRender }: DropDownMenuProps) => { + // list const items: MenuProps["items"] = useMemo(() => { + if (!list) return undefined; + const renderKeys = Object.keys(render) as renderKey[]; return list.map((item) => { return { @@ -21,15 +25,26 @@ export const DropDownMenu = memo(({ children, list }: DropDownMenuProps) => { }; }); }, [list]); - + // 处理 list 的点击事件 const handleMenuClick: MenuProps["onClick"] = (e) => { + if (!list) return; + const key = e.key; - const item = list.filter((item) => item.title === key)[0]; - if (item && item.onClick) { + const item = list.find((item) => item.title === key); + if (item?.onClick) { item.onClick(); } }; + // 如果提供了自定义渲染函数(组件) + if (dropdownRender) { + return ( + + {children} + + ); + } + return ( InsertTextEvent("table"), }, + { + type: "emoji", + component: , + }, { type: "line", }, { type: "undo", - icon: Undo, + icon: UndoIcon, title: "撤销", description: Hotkey.UNDO.readableCommand, onClick: () => UndoEvent(), }, { type: "redo", - icon: Redo, + icon: RedoIcon, title: "重做", description: Hotkey.REDO.readableCommand, onClick: () => RedoEvent(), diff --git a/packages/mini-markdown-editor/src/config/toolbar/event.ts b/packages/mini-markdown-editor/src/config/toolbar/event.ts index 59e36a3..dafb4ce 100644 --- a/packages/mini-markdown-editor/src/config/toolbar/event.ts +++ b/packages/mini-markdown-editor/src/config/toolbar/event.ts @@ -28,4 +28,10 @@ export const RedoEvent = () => { insertContent.redo(); }; +// Emoji +export const InsertEmojiEvent = (emoji: any) => { + insertContent.insertTextAtCursor(emoji.native); + console.log(emoji); +}; + // 导出为PDF diff --git a/packages/mini-markdown-editor/src/extensions/codemirror/hotkeys.ts b/packages/mini-markdown-editor/src/extensions/codemirror/hotkeys.ts index 65f40b6..5b675df 100644 --- a/packages/mini-markdown-editor/src/extensions/codemirror/hotkeys.ts +++ b/packages/mini-markdown-editor/src/extensions/codemirror/hotkeys.ts @@ -6,7 +6,7 @@ import { ToolbarType } from "@/types/toolbar"; // 定义默认快捷键支持 const KEYMAP = { - // Headings + // Text [Hotkey.TITLE.FIRST.codeMirrorCommand]: { run: () => { Hotkey.TITLE.FIRST.handle?.(); @@ -55,8 +55,6 @@ const KEYMAP = { }, preventDefault: true, }, - - // Text [Hotkey.BOLD.codeMirrorCommand]: { run: () => { Hotkey.BOLD.handle?.(); @@ -89,8 +87,6 @@ const KEYMAP = { }, preventDefault: true, }, - - // Block elements [Hotkey.BLOCKQUOTE.codeMirrorCommand]: { run: () => { Hotkey.BLOCKQUOTE.handle?.(); @@ -115,8 +111,6 @@ const KEYMAP = { }, preventDefault: true, }, - - // Code [Hotkey.INLINE_CODE.codeMirrorCommand]: { run: () => { Hotkey.INLINE_CODE.handle?.(); @@ -133,8 +127,6 @@ const KEYMAP = { }, preventDefault: true, }, - - // Other elements [Hotkey.LINK.codeMirrorCommand]: { run: () => { Hotkey.LINK.handle?.(); diff --git a/packages/mini-markdown-editor/src/types/toolbar.ts b/packages/mini-markdown-editor/src/types/toolbar.ts index b8ed662..7f2ca1e 100644 --- a/packages/mini-markdown-editor/src/types/toolbar.ts +++ b/packages/mini-markdown-editor/src/types/toolbar.ts @@ -54,4 +54,5 @@ export type ToolbarType = | "preview" | "contents" | "help" - | "output"; + | "output" + | "emoji"; diff --git a/packages/mini-markdown-editor/src/utils/insert-content.ts b/packages/mini-markdown-editor/src/utils/insert-content.ts index 6a23240..ce74506 100644 --- a/packages/mini-markdown-editor/src/utils/insert-content.ts +++ b/packages/mini-markdown-editor/src/utils/insert-content.ts @@ -37,6 +37,28 @@ class InsertContent { }); } + public insertTextAtCursor(content: string) { + const view = this.editorView; + if (!view) return; + + view.focus(); + const range = view.state.selection.ranges[0]; + + // 插入内容,光标位置在内容末尾 + view.dispatch({ + changes: { + from: range.from, + to: range.to, + insert: content, + }, + // 将光标移动到插入内容的末尾 + selection: { + anchor: range.from + content.length, + head: range.from + content.length, + }, + }); + } + // 撤销 public undo() { const view = this.editorView; -- Gitee From b3c4486861d5be5bbd411475955811daa13262fc Mon Sep 17 00:00:00 2001 From: tabzzz Date: Tue, 4 Feb 2025 22:16:26 +0800 Subject: [PATCH 4/4] =?UTF-8?q?refactor(mini-markdown-editor):=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9Emoji=E7=BB=84=E4=BB=B6=E5=AF=BC=E5=87=BA=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mini-markdown-editor/src/components/Toolbar/Emoji.tsx | 4 +++- packages/mini-markdown-editor/src/config/toolbar/base.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx b/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx index 817aacf..98d7f4c 100644 --- a/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx +++ b/packages/mini-markdown-editor/src/components/Toolbar/Emoji.tsx @@ -6,7 +6,7 @@ import { FC, useContext, useMemo } from "react"; import { InsertEmojiEvent } from "@/config/toolbar/event"; import { ConfigContext } from "@/components/providers/config-provider"; -export const Emoji: FC = () => { +const Emoji: FC = () => { const { theme } = useContext(ConfigContext); // Emoji 选择器 @@ -31,3 +31,5 @@ export const Emoji: FC = () => { ); }; + +export default Emoji; diff --git a/packages/mini-markdown-editor/src/config/toolbar/base.tsx b/packages/mini-markdown-editor/src/config/toolbar/base.tsx index 4ee8e73..5c2e3ec 100644 --- a/packages/mini-markdown-editor/src/config/toolbar/base.tsx +++ b/packages/mini-markdown-editor/src/config/toolbar/base.tsx @@ -20,7 +20,7 @@ import { ToolbarItem } from "@/types/toolbar"; import Upload from "@/components/Toolbar/Upload"; import FullScreen from "@/components/Toolbar/FullScreen"; import { Contents, Read, Write, Help, Output } from "@/components/Toolbar/ShowLayout"; -import { Emoji } from "@/components/Toolbar/Emoji"; +import Emoji from "@/components/Toolbar/Emoji"; // 快捷键描述 import { Hotkey } from "@/common/hotkeys"; -- Gitee