diff --git a/packages/client/src/tiptap/menus/insert/index.tsx b/packages/client/src/tiptap/menus/insert/index.tsx
index 47612cc0..d8c3bc76 100644
--- a/packages/client/src/tiptap/menus/insert/index.tsx
+++ b/packages/client/src/tiptap/menus/insert/index.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Editor } from '@tiptap/core';
import { Button, Dropdown, Popover } from '@douyinfe/semi-ui';
import { IconPlus } from '@douyinfe/semi-icons';
@@ -11,17 +11,149 @@ import {
IconCodeBlock,
IconLink,
IconStatus,
- IconInfo,
IconAttachment,
IconMath,
IconCountdown,
IconCallout,
} from 'components/icons';
import { GridSelect } from 'components/grid-select';
+import { useToggle } from 'hooks/use-toggle';
+import { createKeysLocalStorageLRUCache } from 'helpers/lru-cache';
import { isTitleActive } from '../../utils/is-active';
import { createCountdown } from '../countdown/service';
+const insertMenuLRUCache = createKeysLocalStorageLRUCache('TIPTAP_INSERT_MENU', 3);
+
+const COMMANDS = [
+ {
+ title: '通用',
+ },
+ {
+ icon: ,
+ label: '表格',
+ custom: (editor, runCommand) => (
+
+ {
+ return runCommand({
+ label: '表格',
+ action: () => editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run(),
+ })();
+ }}
+ />
+
+ }
+ >
+
+
+ 表格
+
+
+ ),
+ },
+ {
+ icon: ,
+ label: '代码块',
+ action: (editor) => editor.chain().focus().toggleCodeBlock().run(),
+ },
+ {
+ icon: ,
+ label: '图片',
+ action: (editor) => editor.chain().focus().setEmptyImage().run(),
+ },
+ {
+ icon: ,
+ label: '附件',
+ action: (editor) => editor.chain().focus().setAttachment().run(),
+ },
+ {
+ icon: ,
+ label: '倒计时',
+ action: (editor) => createCountdown(editor),
+ },
+ {
+ icon: ,
+ label: '外链',
+ action: (editor) => editor.chain().focus().setIframe({ url: '' }).run(),
+ },
+ {
+ title: '卡片',
+ },
+ {
+ icon: ,
+ label: '思维导图',
+ action: (editor) => editor.chain().focus().setMind().run(),
+ },
+ {
+ icon: ,
+ label: '数学公式',
+ action: (editor) => editor.chain().focus().setKatex({ defaultShowPicker: true }).run(),
+ },
+ {
+ icon: ,
+ label: '状态',
+ action: (editor) => editor.chain().focus().setStatus({ defaultShowPicker: true }).run(),
+ },
+ {
+ icon: ,
+ label: '高亮块',
+ action: (editor) => editor.chain().focus().setCallout().run(),
+ },
+ {
+ title: '内容引用',
+ },
+ {
+ icon: ,
+ label: '文档',
+ action: (editor) => editor.chain().focus().setDocumentReference().run(),
+ },
+ {
+ icon: ,
+ label: '子文档',
+ action: (editor) => editor.chain().focus().setDocumentChildren().run(),
+ },
+];
+
export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
+ const [recentUsed, setRecentUsed] = useState([]);
+ const [visible, toggleVisible] = useToggle(false);
+
+ const renderedCommands = useMemo(
+ () => (recentUsed.length ? [{ title: '最近使用' }, ...recentUsed, ...COMMANDS] : COMMANDS),
+ [recentUsed]
+ );
+
+ const transformToCommands = useCallback((data: string[]) => {
+ return data
+ .map((label) => {
+ return COMMANDS.find((command) => command.label && command.label === label);
+ })
+ .filter(Boolean);
+ }, []);
+
+ const runCommand = useCallback(
+ (command) => {
+ return () => {
+ insertMenuLRUCache.put(command.label);
+ setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
+ command.action(editor);
+ toggleVisible(false);
+ };
+ },
+ [editor, toggleVisible]
+ );
+
+ useEffect(() => {
+ if (!visible) return;
+ insertMenuLRUCache.syncFromStorage();
+ setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
+ }, [visible]);
+
if (!editor) {
return null;
}
@@ -31,80 +163,27 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
zIndex={10000}
trigger="click"
position="bottomLeft"
+ visible={visible}
+ onVisibleChange={toggleVisible}
+ style={{
+ minWidth: 132,
+ maxHeight: 'calc(90vh - 120px)',
+ overflowY: 'auto',
+ }}
render={
- 通用
-
-
- {
- return editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
- }}
- />
-
- }
- >
-
- 表格
-
-
-
- editor.chain().focus().toggleCodeBlock().run()}>
- 代码块
-
-
- editor.chain().focus().setEmptyImage().run()}>
-
- 图片
-
-
- editor.chain().focus().setAttachment().run()}>
-
- 附件
-
-
- createCountdown(editor)}>
- 倒计时
-
-
- editor.chain().focus().setIframe({ url: '' }).run()}>
- 外链
-
-
- editor.chain().focus().setMind().run()}>
- 思维导图
-
-
- editor.chain().focus().setKatex({ defaultShowPicker: true }).run()}>
- 数学公式
-
-
-
- 卡片
-
- editor.chain().focus().setStatus({ defaultShowPicker: true }).run()}>
- 状态
-
-
- editor.chain().focus().setCallout().run()}>
- 高亮块
-
-
-
- 文档
-
- editor.chain().focus().setDocumentReference().run()}>
- 文档
-
-
- editor.chain().focus().setDocumentChildren().run()}>
- 子文档
-
+ {renderedCommands.map((command) => {
+ return command.title ? (
+ {command.title}
+ ) : command.custom ? (
+ command.custom(editor, runCommand)
+ ) : (
+
+ {command.icon}
+ {command.label}
+
+ );
+ })}
}
>