diff --git a/packages/client/src/components/icons/IconCallout.tsx b/packages/client/src/components/icons/IconCallout.tsx new file mode 100644 index 0000000..3191a66 --- /dev/null +++ b/packages/client/src/components/icons/IconCallout.tsx @@ -0,0 +1,14 @@ +import { Icon } from '@douyinfe/semi-ui'; + +export const IconCallout: 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 9595f25..2596cf1 100644 --- a/packages/client/src/components/icons/index.tsx +++ b/packages/client/src/components/icons/index.tsx @@ -50,3 +50,4 @@ export * from './IconSup'; export * from './IconGlobe'; export * from './IconCountdown'; export * from './IconDrawBoard'; +export * from './IconCallout'; diff --git a/packages/client/src/tiptap/extensions/banner.ts b/packages/client/src/tiptap/extensions/callout.ts similarity index 69% rename from packages/client/src/tiptap/extensions/banner.ts rename to packages/client/src/tiptap/extensions/callout.ts index bb84ce9..5df2fd3 100644 --- a/packages/client/src/tiptap/extensions/banner.ts +++ b/packages/client/src/tiptap/extensions/callout.ts @@ -1,18 +1,18 @@ import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core'; import { ReactNodeViewRenderer } from '@tiptap/react'; -import { BannerWrapper } from '../wrappers/banner'; +import { CalloutWrapper } from '../wrappers/callout'; import { getDatasetAttribute } from '../utils/dataset'; declare module '@tiptap/core' { interface Commands { banner: { - setBanner: (attrs) => ReturnType; + setCallout: () => ReturnType; }; } } -export const Banner = Node.create({ - name: 'banner', +export const Callout = Node.create({ + name: 'callout', content: 'paragraph+', group: 'block', defining: true, @@ -20,17 +20,6 @@ export const Banner = Node.create({ addAttributes() { return { - type: { - default: 'info', - rendered: false, - parseHTML: getDatasetAttribute('type'), - renderHTML: (attributes) => { - return { - 'data-type': attributes.type, - 'class': `banner banner-${attributes.type}`, - }; - }, - }, emoji: { default: '✅', }, @@ -49,7 +38,7 @@ export const Banner = Node.create({ addOptions() { return { HTMLAttributes: { - class: 'banner', + class: 'callout', }, }; }, @@ -68,14 +57,14 @@ export const Banner = Node.create({ addCommands() { return { - setBanner: - (attributes) => + setCallout: + () => ({ commands, editor }) => { const { type = null } = editor.getAttributes(this.name); if (type) { commands.lift(this.name); } else { - return commands.toggleWrap(this.name, attributes); + return commands.toggleWrap(this.name); } }, }; @@ -94,6 +83,6 @@ export const Banner = Node.create({ }, addNodeView() { - return ReactNodeViewRenderer(BannerWrapper); + return ReactNodeViewRenderer(CalloutWrapper); }, }); diff --git a/packages/client/src/tiptap/extensions/paste.ts b/packages/client/src/tiptap/extensions/paste.ts index c65d01a..b8edc9e 100644 --- a/packages/client/src/tiptap/extensions/paste.ts +++ b/packages/client/src/tiptap/extensions/paste.ts @@ -115,19 +115,19 @@ export const Paste = Extension.create({ return false; }, - // clipboardTextSerializer: (slice) => { - // const doc = slice.content; + clipboardTextSerializer: (slice) => { + const doc = slice.content; - // if (!doc) { - // return ''; - // } + if (!doc) { + return ''; + } - // const content = prosemirrorToMarkdown({ - // content: doc, - // }); + const content = prosemirrorToMarkdown({ + content: doc, + }); - // return content; - // }, + return content; + }, }, }), ]; diff --git a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/banner.ts b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/callout.ts similarity index 59% rename from packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/banner.ts rename to packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/callout.ts index edaf1f0..a921f8c 100644 --- a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/banner.ts +++ b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/nodes/callout.ts @@ -1,9 +1,9 @@ import { Node } from './node'; -export class Banner extends Node { - type = 'banner'; +export class Callout extends Node { + type = 'callout'; matching() { - return this.DOMNode.nodeName === 'DIV' && this.DOMNode.classList.contains('banner'); + return this.DOMNode.nodeName === 'DIV' && this.DOMNode.classList.contains('callout'); } } diff --git a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/renderer.ts b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/renderer.ts index a3ba1ab..74af89f 100644 --- a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/renderer.ts +++ b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/html-to-prosemirror/renderer.ts @@ -1,7 +1,7 @@ // 自定义节点 import { Iframe } from './nodes/iframe'; import { Attachment } from './nodes/attachment'; -import { Banner } from './nodes/banner'; +import { Callout } from './nodes/callout'; import { Status } from './nodes/status'; import { DocumentReference } from './nodes/document-reference'; import { DocumentChildren } from './nodes/document-children'; @@ -55,7 +55,7 @@ export class Renderer { this.nodes = [ Attachment, Countdown, - Banner, + Callout, Iframe, Status, Mention, diff --git a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/index.ts b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/index.ts index c19105e..13c946d 100644 --- a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/index.ts +++ b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/index.ts @@ -8,7 +8,7 @@ import katex from './markdownKatex'; import tasklist from './markdownTaskList'; import splitMixedLists from './markedownSplitMixedList'; import markdownUnderline from './markdownUnderline'; -import markdownBanner from './markdownBanner'; +import markdownCallout from './markdownCallout'; import { markdownItTable } from './markdownTable'; import { createMarkdownContainer } from './markdownItContainer'; @@ -33,7 +33,7 @@ const markdown = markdownit('commonmark') .use(emoji) .use(katex) // 以下为自定义节点 - .use(markdownBanner) + .use(markdownCallout) .use(markdownAttachment) .use(markdownCountdown) .use(markdownIframe) diff --git a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownBanner.ts b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownCallout.ts similarity index 69% rename from packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownBanner.ts rename to packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownCallout.ts index c8949af..d1b6a7d 100644 --- a/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownBanner.ts +++ b/packages/client/src/tiptap/markdown/markdown-to-prosemirror/markdown-to-html/markdownCallout.ts @@ -1,13 +1,12 @@ import container from 'markdown-it-container'; -export const typesAvailable = ['info', 'warning', 'danger', 'success']; +const typesAvailable = ['callout']; const buildRender = (type) => (tokens, idx, options, env, slf) => { const tag = tokens[idx]; if (tag.nesting === 1) { - tag.attrSet('data-type', type); - tag.attrJoin('class', `banner banner-${type}`); + tag.attrJoin('class', `callout`); } return slf.renderToken(tokens, idx, options, env, slf); @@ -16,7 +15,7 @@ const buildRender = (type) => (tokens, idx, options, env, slf) => { /** * @param {object} md Markdown object */ -export default function markdownBanner(md) { +export default function markdownCallout(md) { // create a custom container to each callout type typesAvailable.forEach((type) => { md.use(container, type, { diff --git a/packages/client/src/tiptap/markdown/prosemirror-to-markdown/index.ts b/packages/client/src/tiptap/markdown/prosemirror-to-markdown/index.ts index 4dec775..5901762 100644 --- a/packages/client/src/tiptap/markdown/prosemirror-to-markdown/index.ts +++ b/packages/client/src/tiptap/markdown/prosemirror-to-markdown/index.ts @@ -1,8 +1,8 @@ import { MarkdownSerializer as ProseMirrorMarkdownSerializer, defaultMarkdownSerializer } from 'prosemirror-markdown'; import { Attachment } from '../../extensions/attachment'; -import { Banner } from '../../extensions/banner'; import { Bold } from '../../extensions/bold'; import { BulletList } from '../../extensions/bullet-list'; +import { Callout } from '../../extensions/callout'; import { Code } from '../../extensions/code'; import { CodeBlock } from '../../extensions/code-block'; import { Countdown } from '../../extensions/countdown'; @@ -92,14 +92,6 @@ const SerializerConfig = { nodes: { [Attachment.name]: renderCustomContainer('attachment'), - [Banner.name]: (state, node) => { - state.write(`:::${node.attrs.type || 'info'}\n`); - state.ensureNewLine(); - state.renderContent(node); - state.ensureNewLine(); - state.write(':::'); - state.closeBlock(node); - }, blockquote: (state, node) => { if (node.attrs.multiline) { state.write('>>>'); @@ -113,6 +105,14 @@ const SerializerConfig = { } }, [BulletList.name]: defaultMarkdownSerializer.nodes.bullet_list, + [Callout.name]: (state, node) => { + state.write(`:::callout\n`); + state.ensureNewLine(); + state.renderContent(node); + state.ensureNewLine(); + state.write(':::'); + state.closeBlock(node); + }, [CodeBlock.name]: (state, node) => { state.write(`\`\`\`${node.attrs.language || ''}\n`); state.text(node.textContent, false); diff --git a/packages/client/src/tiptap/menubar.tsx b/packages/client/src/tiptap/menubar.tsx index ef0300d..eb19240 100644 --- a/packages/client/src/tiptap/menubar.tsx +++ b/packages/client/src/tiptap/menubar.tsx @@ -32,7 +32,7 @@ import { Blockquote } from './menus/blockquote'; import { HorizontalRule } from './menus/horizontal-rule'; import { Search } from './menus/search'; -import { Banner } from './menus/banner'; +import { Callout } from './menus/callout'; import { Countdonw } from './menus/countdown'; import { DocumentReference } from './menus/document-reference'; import { Image } from './menus/image'; @@ -88,7 +88,7 @@ export const MenuBar: React.FC<{ editor: any }> = ({ editor }) => { - + diff --git a/packages/client/src/tiptap/menus/banner/index.tsx b/packages/client/src/tiptap/menus/banner/index.tsx deleted file mode 100644 index 57e077a..0000000 --- a/packages/client/src/tiptap/menus/banner/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { Editor } from '@tiptap/core'; -import { BannerBubbleMenu } from './bubble'; - -export const Banner: React.FC<{ editor: Editor }> = ({ editor }) => { - if (!editor) { - return null; - } - - return ( - <> - - - ); -}; diff --git a/packages/client/src/tiptap/menus/banner/bubble.module.scss b/packages/client/src/tiptap/menus/callout/bubble.module.scss similarity index 100% rename from packages/client/src/tiptap/menus/banner/bubble.module.scss rename to packages/client/src/tiptap/menus/callout/bubble.module.scss diff --git a/packages/client/src/tiptap/menus/banner/bubble.tsx b/packages/client/src/tiptap/menus/callout/bubble.tsx similarity index 88% rename from packages/client/src/tiptap/menus/banner/bubble.tsx rename to packages/client/src/tiptap/menus/callout/bubble.tsx index 0859847..43506d2 100644 --- a/packages/client/src/tiptap/menus/banner/bubble.tsx +++ b/packages/client/src/tiptap/menus/callout/bubble.tsx @@ -5,7 +5,7 @@ import { Tooltip } from 'components/tooltip'; import { IconDrawBoard } from 'components/icons'; import { BubbleMenu } from '../../views/bubble-menu'; import { Divider } from '../../divider'; -import { Banner } from '../../extensions/banner'; +import { Callout } from '../../extensions/callout'; import { deleteNode } from '../../utils/delete-node'; import styles from './bubble.module.scss'; import { useCallback } from 'react'; @@ -16,13 +16,13 @@ const TEXT_COLORS = ['#d83931', '#de7802', '#dc9b04', '#2ea121', '#245bdb', '#64 const BORDER_COLORS = ['#fbbfbc', '#fed4a4', '#fff67a', '#b7edb1', '#bacefd', '#cdb2fa', '#dee0e3']; const BACKGROUND_COLORS = ['#fef1f1', '#feead2', '#ffc', '#d9f5d6', '#e1eaff', '#ece2fe', '#f2f3f5']; -export const BannerBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => { +export const CalloutBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => { const setColor = useCallback( (key, color) => { return () => { editor .chain() - .updateAttributes(Banner.name, { + .updateAttributes(Callout.name, { [key]: color, }) .focus() @@ -37,18 +37,17 @@ export const BannerBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => { className={'bubble-menu'} editor={editor} pluginKey="banner-bubble-menu" - shouldShow={() => editor.isActive(Banner.name)} + shouldShow={() => editor.isActive(Callout.name)} matchRenderContainer={(node) => node && node.id === 'js-bannber-container'} >
- 字体颜色 + 字体颜色
{TEXT_COLORS.map((color) => (
@@ -58,7 +57,7 @@ export const BannerBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => {
- 边框颜色 + 边框颜色
{BORDER_COLORS.map((color) => ( @@ -71,7 +70,7 @@ export const BannerBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => {
- 背景颜色 + 背景颜色
{BACKGROUND_COLORS.map((color) => (
= ({ editor }) => { + if (!editor) { + return null; + } + + return ( + <> + + + ); +}; diff --git a/packages/client/src/tiptap/menus/insert/index.tsx b/packages/client/src/tiptap/menus/insert/index.tsx index 782360a..47612cc 100644 --- a/packages/client/src/tiptap/menus/insert/index.tsx +++ b/packages/client/src/tiptap/menus/insert/index.tsx @@ -15,6 +15,7 @@ import { IconAttachment, IconMath, IconCountdown, + IconCallout, } from 'components/icons'; import { GridSelect } from 'components/grid-select'; import { isTitleActive } from '../../utils/is-active'; @@ -90,8 +91,8 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => { 状态 - editor.chain().focus().setBanner({ type: 'info' }).run()}> - 信息框 + editor.chain().focus().setCallout().run()}> + 高亮块 diff --git a/packages/client/src/tiptap/menus/quick-insert.tsx b/packages/client/src/tiptap/menus/quick-insert.tsx index c22c0b0..1d18040 100644 --- a/packages/client/src/tiptap/menus/quick-insert.tsx +++ b/packages/client/src/tiptap/menus/quick-insert.tsx @@ -19,6 +19,7 @@ import { IconAttachment, IconMath, IconCountdown, + IconCallout, } from 'components/icons'; import { createCountdown } from './countdown/service'; import { createOrToggleLink } from './link/service'; @@ -237,14 +238,14 @@ export const QUICK_INSERT_ITEMS = [ }, { - key: '信息框', + key: '高亮块', label: ( - - 信息框 + + 高亮块 ), - command: (editor: Editor) => editor.chain().focus().setBanner({ type: 'info' }).run(), + command: (editor: Editor) => editor.chain().focus().setCallout().run(), }, { diff --git a/packages/client/src/tiptap/start-kit.tsx b/packages/client/src/tiptap/start-kit.tsx index 3e36653..599db37 100644 --- a/packages/client/src/tiptap/start-kit.tsx +++ b/packages/client/src/tiptap/start-kit.tsx @@ -1,9 +1,9 @@ import { Attachment } from './extensions/attachment'; import { BackgroundColor } from './extensions/background-color'; -import { Banner } from './extensions/banner'; import { Blockquote } from './extensions/blockquote'; import { Bold } from './extensions/bold'; import { BulletList } from './extensions/bullet-list'; +import { Callout } from './extensions/callout'; import { Code } from './extensions/code'; import { CodeBlock } from './extensions/code-block'; import { Color } from './extensions/color'; @@ -57,10 +57,10 @@ import { Paste } from './extensions/paste'; export const BaseKit = [ Attachment, BackgroundColor, - Banner, Blockquote, Bold, BulletList, + Callout, Code, CodeBlock, Color, diff --git a/packages/client/src/tiptap/wrappers/banner/index.module.scss b/packages/client/src/tiptap/wrappers/callout/index.module.scss similarity index 93% rename from packages/client/src/tiptap/wrappers/banner/index.module.scss rename to packages/client/src/tiptap/wrappers/callout/index.module.scss index 8ddefd4..28a271e 100644 --- a/packages/client/src/tiptap/wrappers/banner/index.module.scss +++ b/packages/client/src/tiptap/wrappers/callout/index.module.scss @@ -1,5 +1,6 @@ .wrap { line-height: 0; + margin-top: 0.75em; .innerWrap { display: flex; @@ -28,7 +29,7 @@ } p { - margin-top: .25em; + margin-top: 0.25em; } p:first-child { diff --git a/packages/client/src/tiptap/wrappers/banner/index.tsx b/packages/client/src/tiptap/wrappers/callout/index.tsx similarity index 80% rename from packages/client/src/tiptap/wrappers/banner/index.tsx rename to packages/client/src/tiptap/wrappers/callout/index.tsx index 65b093f..a30a63a 100644 --- a/packages/client/src/tiptap/wrappers/banner/index.tsx +++ b/packages/client/src/tiptap/wrappers/callout/index.tsx @@ -1,12 +1,10 @@ +import { useCallback } from 'react'; import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'; -import { Popover } from '@douyinfe/semi-ui'; import cls from 'classnames'; -import { useToggle } from 'hooks/use-toggle'; import { EmojiPicker } from 'components/emoji-picker'; import styles from './index.module.scss'; -import { useCallback, useEffect, useMemo } from 'react'; -export const BannerWrapper = ({ node, updateAttributes }) => { +export const CalloutWrapper = ({ node, updateAttributes }) => { const { emoji, textColor, borderColor, backgroundColor } = node.attrs; const onSelectEmoji = useCallback((emoji) => {