From cc30e009847b18d227a0cb87b642793864c67d1b Mon Sep 17 00:00:00 2001 From: fantasticit Date: Sun, 20 Mar 2022 17:46:29 +0800 Subject: [PATCH] feat: improve editor --- packages/client/package.json | 5 + .../components/document/reader/content.tsx | 12 +- .../src/components/document/reader/editor.tsx | 19 +- .../src/components/document/reader/index.tsx | 10 +- .../document/reader/public/index.tsx | 12 +- .../src/components/document/reader/user.tsx | 28 +- .../components/icons/IconSearchReplace.tsx | 21 + .../client/src/components/icons/index.tsx | 1 + .../client/src/components/tiptap/basekit.tsx | 18 +- .../tiptap/components/attachment/index.tsx | 5 +- .../tiptap/components/codeBlock/index.tsx | 5 +- .../tiptap/components/emojiList/emojis.ts | 1858 +++++++++++++++++ .../components/emojiList/index.module.scss | 38 + .../tiptap/components/emojiList/index.tsx | 78 + .../tiptap/components/katex/index.tsx | 4 +- .../tiptap/components/mind/jsmind.jsx | 3 +- .../tiptap/components/status/index.tsx | 2 +- .../components/tiptap/extensions/banner.ts | 61 +- .../tiptap/extensions/blockquote.ts | 2 +- .../tiptap/extensions/bulletList.ts | 7 +- .../src/components/tiptap/extensions/emoji.ts | 100 + .../components/tiptap/extensions/indent.ts | 2 +- .../src/components/tiptap/extensions/katex.ts | 4 +- .../src/components/tiptap/extensions/link.ts | 4 + .../src/components/tiptap/extensions/mind.ts | 14 +- .../tiptap/extensions/orderedList.ts | 2 +- .../tiptap/extensions/pasteMarkdown.ts | 153 +- .../tiptap/extensions/placeholder.ts | 13 +- .../components/tiptap/extensions/search.ts | 362 ++++ .../components/tiptap/extensions/taskItem.ts | 50 +- .../components/tiptap/extensions/taskList.ts | 22 +- .../components/tiptap/extensions/textAlign.ts | 6 +- .../components/tiptap/extensions/title.tsx | 8 +- .../tiptap/extensions/trailingNode.tsx | 27 +- .../src/components/tiptap/menus/align.tsx | 2 +- .../src/components/tiptap/menus/banner.tsx | 17 +- .../tiptap/menus/base-bubble-menu.tsx | 2 + .../components/tiptap/menus/base-insert.tsx | 14 +- .../src/components/tiptap/menus/base-menu.tsx | 15 +- .../src/components/tiptap/menus/color.tsx | 9 +- .../menus/components/emoji/index.module.scss | 4 - .../tiptap/menus/components/emoji/index.tsx | 5 +- .../tiptap/menus/components/font-size.tsx | 2 +- .../tiptap/menus/components/paragraph.tsx | 2 +- .../src/components/tiptap/menus/image.tsx | 13 +- .../src/components/tiptap/menus/link.tsx | 9 +- .../src/components/tiptap/menus/list.tsx | 15 +- .../components/tiptap/menus/media-insert.tsx | 7 +- .../tiptap/menus/search/index.module.scss | 0 .../components/tiptap/menus/search/index.tsx | 85 + .../src/components/tiptap/menus/table.tsx | 21 +- .../services/{delete.tsx => deleteNode.ts} | 0 .../services/{active.ts => isActive.ts} | 0 .../tiptap/services/listInputRule.ts | 21 + .../tiptap/services/markdown/index.ts | 26 + .../services/markdown/markdownBanner.ts | 29 + .../{ => markdown}/markdownSourceMap.ts | 0 .../services/markdown/markdownUnderline.ts | 22 + .../markdown/markedownSplitMixedList.ts | 64 + .../services/{ => markdown}/serializer.ts | 93 +- .../{ => markdown}/serializerHelpers.ts | 1 - .../src/components/tiptap/services/marked.ts | 15 - .../client/src/components/tooltip/index.tsx | 32 + packages/client/src/styles/globals.scss | 15 + packages/client/src/styles/prosemirror.scss | 11 +- pnpm-lock.yaml | 45 +- 66 files changed, 3286 insertions(+), 266 deletions(-) create mode 100644 packages/client/src/components/icons/IconSearchReplace.tsx create mode 100644 packages/client/src/components/tiptap/components/emojiList/emojis.ts create mode 100644 packages/client/src/components/tiptap/components/emojiList/index.module.scss create mode 100644 packages/client/src/components/tiptap/components/emojiList/index.tsx create mode 100644 packages/client/src/components/tiptap/extensions/emoji.ts create mode 100644 packages/client/src/components/tiptap/extensions/search.ts create mode 100644 packages/client/src/components/tiptap/menus/search/index.module.scss create mode 100644 packages/client/src/components/tiptap/menus/search/index.tsx rename packages/client/src/components/tiptap/services/{delete.tsx => deleteNode.ts} (100%) rename packages/client/src/components/tiptap/services/{active.ts => isActive.ts} (100%) create mode 100644 packages/client/src/components/tiptap/services/listInputRule.ts create mode 100644 packages/client/src/components/tiptap/services/markdown/index.ts create mode 100644 packages/client/src/components/tiptap/services/markdown/markdownBanner.ts rename packages/client/src/components/tiptap/services/{ => markdown}/markdownSourceMap.ts (100%) create mode 100644 packages/client/src/components/tiptap/services/markdown/markdownUnderline.ts create mode 100644 packages/client/src/components/tiptap/services/markdown/markedownSplitMixedList.ts rename packages/client/src/components/tiptap/services/{ => markdown}/serializer.ts (67%) rename packages/client/src/components/tiptap/services/{ => markdown}/serializerHelpers.ts (99%) delete mode 100644 packages/client/src/components/tiptap/services/marked.ts create mode 100644 packages/client/src/components/tooltip/index.tsx diff --git a/packages/client/package.json b/packages/client/package.json index 3ec3debc..59538cfb 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -51,6 +51,7 @@ "@tiptap/extension-text-style": "^2.0.0-beta.23", "@tiptap/extension-underline": "^2.0.0-beta.23", "@tiptap/react": "^2.0.0-beta.107", + "@tiptap/suggestion": "^2.0.0-beta.90", "@traptitech/markdown-it-katex": "^3.5.0", "axios": "^0.25.0", "classnames": "^2.3.1", @@ -62,6 +63,8 @@ "lowlight": "^2.5.0", "markdown-it": "^12.3.2", "markdown-it-anchor": "^8.4.1", + "markdown-it-container": "^3.0.0", + "markdown-it-emoji": "^2.0.0", "markdown-it-footnote": "^3.0.3", "markdown-it-sub": "^1.0.0", "markdown-it-sup": "^1.0.0", @@ -69,11 +72,13 @@ "marked": "^4.0.12", "next": "12.0.10", "prosemirror-markdown": "^1.7.0", + "prosemirror-utils": "^0.9.6", "prosemirror-view": "^1.23.6", "react": "17.0.2", "react-dom": "17.0.2", "react-helmet": "^6.1.0", "react-split-pane": "^0.1.92", + "scroll-into-view-if-needed": "^2.2.29", "swr": "^1.2.0", "tippy.js": "^6.3.7" }, diff --git a/packages/client/src/components/document/reader/content.tsx b/packages/client/src/components/document/reader/content.tsx index a8da6abe..a08e101f 100644 --- a/packages/client/src/components/document/reader/content.tsx +++ b/packages/client/src/components/document/reader/content.tsx @@ -13,12 +13,12 @@ export const DocumentContent: React.FC = ({ document }) => { const c = safeJSONParse(document.content); let json = c.default || c; - if (json && json.content) { - json = { - type: 'doc', - content: json.content.slice(1), - }; - } + // if (json && json.content) { + // json = { + // type: 'doc', + // content: json.content.slice(1), + // }; + // } const editor = useEditor({ editable: false, diff --git a/packages/client/src/components/document/reader/editor.tsx b/packages/client/src/components/document/reader/editor.tsx index 6689ab80..6bb915f7 100644 --- a/packages/client/src/components/document/reader/editor.tsx +++ b/packages/client/src/components/document/reader/editor.tsx @@ -1,7 +1,7 @@ -import React, { useMemo, useEffect } from 'react'; +import React, { useMemo, useEffect, useRef } from 'react'; import { useEditor, EditorContent } from '@tiptap/react'; import { Layout } from '@douyinfe/semi-ui'; -import { ILoginUser } from '@think/domains'; +import { IDocument, ILoginUser } from '@think/domains'; import { useToggle } from 'hooks/useToggle'; import { DEFAULT_EXTENSION, @@ -13,6 +13,7 @@ import { } from 'components/tiptap'; import { DataRender } from 'components/data-render'; import { joinUser } from 'components/document/collaboration'; +import { CreateUser } from './user'; import styles from './index.module.scss'; const { Content } = Layout; @@ -20,11 +21,13 @@ const { Content } = Layout; interface IProps { user: ILoginUser; documentId: string; + document: IDocument; } -export const Editor: React.FC = ({ user, documentId }) => { +export const Editor: React.FC = ({ user, documentId, document }) => { if (!user) return null; + const $ref = useRef(); const provider = useMemo(() => { return getProvider({ targetId: documentId, @@ -68,7 +71,15 @@ export const Editor: React.FC = ({ user, documentId }) => { return ( <> - +
+ +
+ + window.document.querySelector('#js-reader-container .ProseMirror .title') + } + />
); diff --git a/packages/client/src/components/document/reader/index.tsx b/packages/client/src/components/document/reader/index.tsx index a6ed5a92..cb30646e 100644 --- a/packages/client/src/components/document/reader/index.tsx +++ b/packages/client/src/components/document/reader/index.tsx @@ -122,10 +122,12 @@ export const DocumentReader: React.FC = ({ documentId }) => { return ( <> - -
- -
+
diff --git a/packages/client/src/components/document/reader/public/index.tsx b/packages/client/src/components/document/reader/public/index.tsx index 714c30ac..e44b40b3 100644 --- a/packages/client/src/components/document/reader/public/index.tsx +++ b/packages/client/src/components/document/reader/public/index.tsx @@ -131,11 +131,15 @@ export const DocumentPublicReader: React.FC = ({ documentId, hideLogo = style={{ fontSize }} id="js-share-document-editor-container" > - {data.title} -
- -
+ + window.document.querySelector( + '#js-share-document-editor-container .ProseMirror .title' + ) + } + /> diff --git a/packages/client/src/components/document/reader/user.tsx b/packages/client/src/components/document/reader/user.tsx index 1cef6d3e..53432c25 100644 --- a/packages/client/src/components/document/reader/user.tsx +++ b/packages/client/src/components/document/reader/user.tsx @@ -1,15 +1,26 @@ +import { createPortal } from 'react-dom'; import { Space, Typography, Avatar } from '@douyinfe/semi-ui'; import { IconUser } from '@douyinfe/semi-icons'; import { IDocument } from '@think/domains'; import { LocaleTime } from 'components/locale-time'; -const { Text } = Typography; - -export const CreateUser: React.FC<{ document: IDocument }> = ({ document }) => { +export const CreateUser: React.FC<{ document: IDocument; container: () => HTMLElement }> = ({ + document, + container = null, +}) => { if (!document.createUser) return null; - return ( - + const content = ( +
@@ -27,6 +38,11 @@ export const CreateUser: React.FC<{ document: IDocument }> = ({ document }) => {

-
+ ); + + const el = container && container(); + + if (!el) return content; + return createPortal(content, el); }; diff --git a/packages/client/src/components/icons/IconSearchReplace.tsx b/packages/client/src/components/icons/IconSearchReplace.tsx new file mode 100644 index 00000000..5be3fabd --- /dev/null +++ b/packages/client/src/components/icons/IconSearchReplace.tsx @@ -0,0 +1,21 @@ +import { Icon } from '@douyinfe/semi-ui'; + +export const IconSearchReplace: React.FC<{ style?: React.CSSProperties }> = ({ style = {} }) => { + return ( + + + + + + + + + + + } + /> + ); +}; diff --git a/packages/client/src/components/icons/index.tsx b/packages/client/src/components/icons/index.tsx index 91f5e7de..88212a14 100644 --- a/packages/client/src/components/icons/index.tsx +++ b/packages/client/src/components/icons/index.tsx @@ -34,3 +34,4 @@ export * from './IconSplitCell'; export * from './IconAttachment'; export * from './IconMath'; export * from './IconSearch'; +export * from './IconSearchReplace'; diff --git a/packages/client/src/components/tiptap/basekit.tsx b/packages/client/src/components/tiptap/basekit.tsx index f6558c42..cdb522b1 100644 --- a/packages/client/src/components/tiptap/basekit.tsx +++ b/packages/client/src/components/tiptap/basekit.tsx @@ -11,6 +11,7 @@ import { ColorHighlighter } from './extensions/colorHighlighter'; import { DocumentChildren } from './extensions/documentChildren'; import { DocumentReference } from './extensions/documentReference'; import { Dropcursor } from './extensions/dropCursor'; +import { Emoji } from './extensions/emoji'; import { FontSize } from './extensions/fontSize'; import { FootnoteDefinition } from './extensions/footnoteDefinition'; import { FootnoteReference } from './extensions/footnoteReference'; @@ -33,6 +34,7 @@ import { Paragraph } from './extensions/paragraph'; import { PasteFile } from './extensions/pasteFile'; import { PasteMarkdown } from './extensions/pasteMarkdown'; import { Placeholder } from './extensions/placeholder'; +import { SearchNReplace } from './extensions/search'; import { Status } from './extensions/status'; import { Strike } from './extensions/strike'; import { Table } from './extensions/table'; @@ -62,6 +64,7 @@ export const BaseKit = [ DocumentChildren, DocumentReference, Dropcursor, + Emoji, FontSize, FootnoteDefinition, FootnoteReference, @@ -83,15 +86,8 @@ export const BaseKit = [ Paragraph, PasteFile, PasteMarkdown, - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === 'title') { - return '请输入标题'; - } - return '请输入内容'; - }, - showOnlyWhenEditable: true, - }), + Placeholder, + SearchNReplace, Status, Strike, Table, @@ -99,9 +95,7 @@ export const BaseKit = [ TableHeader, TableRow, Text, - TextAlign.configure({ - types: ['heading', 'paragraph', 'image'], - }), + TextAlign, TextStyle, TaskItem, TaskList, diff --git a/packages/client/src/components/tiptap/components/attachment/index.tsx b/packages/client/src/components/tiptap/components/attachment/index.tsx index ff6494d0..009bdc5c 100644 --- a/packages/client/src/components/tiptap/components/attachment/index.tsx +++ b/packages/client/src/components/tiptap/components/attachment/index.tsx @@ -1,6 +1,7 @@ import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'; -import { Button, Tooltip } from '@douyinfe/semi-ui'; +import { Button } from '@douyinfe/semi-ui'; import { IconDownload } from '@douyinfe/semi-icons'; +import { Tooltip } from 'components/tooltip'; import { download } from '../../services/download'; import styles from './index.module.scss'; @@ -12,7 +13,7 @@ export const AttachmentWrapper = ({ node }) => {
{name} - + + ))} +
+ + ); +}); diff --git a/packages/client/src/components/tiptap/components/katex/index.tsx b/packages/client/src/components/tiptap/components/katex/index.tsx index 4fb32af8..bf7371b3 100644 --- a/packages/client/src/components/tiptap/components/katex/index.tsx +++ b/packages/client/src/components/tiptap/components/katex/index.tsx @@ -21,7 +21,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => { const content = text ? ( ) : ( - 请输入公式 + 点击输入公式 ); return ( @@ -32,7 +32,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => { content={