From 8d6db59aee1fa7cf0f86fdc1d639302247675253 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Tue, 31 May 2022 18:58:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com.msgbyte.bbcode/src/bbcode/serialize.ts | 14 ++++++++++---- web/plugins/com.msgbyte.bbcode/src/index.tsx | 5 +++++ .../ChatMessageList/useChatMessageItemAction.tsx | 16 +++++++++++++++- web/src/plugin/common/reg.ts | 1 + 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/web/plugins/com.msgbyte.bbcode/src/bbcode/serialize.ts b/web/plugins/com.msgbyte.bbcode/src/bbcode/serialize.ts index 0ece6e87..cc501733 100644 --- a/web/plugins/com.msgbyte.bbcode/src/bbcode/serialize.ts +++ b/web/plugins/com.msgbyte.bbcode/src/bbcode/serialize.ts @@ -12,11 +12,17 @@ function bbcodeNodeToPlainText(node: AstNode): string { } else { if (node.tag === 'img') { return '[图片]'; - } else { - return (node.content ?? []) - .map((sub) => bbcodeNodeToPlainText(sub)) - .join(''); } + if (node.tag === 'emoji') { + return `:${node.content.join('')}:`; + } + if (node.tag === 'at') { + return `@${node.content.join('')}`; + } + + return (node.content ?? []) + .map((sub) => bbcodeNodeToPlainText(sub)) + .join(''); } } diff --git a/web/plugins/com.msgbyte.bbcode/src/index.tsx b/web/plugins/com.msgbyte.bbcode/src/index.tsx index e5cda518..1bff6efb 100644 --- a/web/plugins/com.msgbyte.bbcode/src/index.tsx +++ b/web/plugins/com.msgbyte.bbcode/src/index.tsx @@ -6,6 +6,10 @@ import { } from '@capital/common'; const BBCode = Loadable(() => import('./render')); +let serialize: (bbcode: string) => string; +import('./bbcode/serialize').then((module) => { + serialize = module.bbcodeToPlainText; +}); regMessageRender((message) => { return ; @@ -22,6 +26,7 @@ regMessageTextDecorators(() => ({ }, mention: (userId, userName) => `[at=${userId}]${userName}[/at]`, emoji: (emojiCode) => `[emoji]${stripColons(emojiCode)}[/emoji]`, + serialize: (plain: string) => (serialize ? serialize(plain) : plain), })); /** diff --git a/web/src/components/ChatBox/ChatMessageList/useChatMessageItemAction.tsx b/web/src/components/ChatBox/ChatMessageList/useChatMessageItemAction.tsx index af76af54..cf400f46 100644 --- a/web/src/components/ChatBox/ChatMessageList/useChatMessageItemAction.tsx +++ b/web/src/components/ChatBox/ChatMessageList/useChatMessageItemAction.tsx @@ -1,6 +1,6 @@ import { Icon } from '@/components/Icon'; import { Menu } from 'antd'; -import React from 'react'; +import React, { useCallback } from 'react'; import { ChatMessage, deleteMessage, @@ -13,6 +13,8 @@ import { useUserInfo, } from 'tailchat-shared'; import { openReconfirmModalP } from '@/components/Modal'; +import copy from 'copy-to-clipboard'; +import { getMessageTextDecorators } from '@/plugin/common'; /** * 消息的会话操作 @@ -25,6 +27,10 @@ export function useChatMessageItemAction( const groupInfo = useGroupInfoContext(); const userInfo = useUserInfo(); + const handleCopy = useCallback(() => { + copy(getMessageTextDecorators().serialize(payload.content)); + }, [payload.content]); + const [, handleRecallMessage] = useAsyncRequest(async () => { if (await openReconfirmModalP()) { await recallMessage(payload._id); @@ -42,6 +48,14 @@ export function useChatMessageItemAction( return ( + } + onClick={handleCopy} + > + {t('复制')} + + {context.hasContext && ( ) => plain, mention: (userId: string, userName: string) => `@${userName}`, emoji: (emojiCode: string) => emojiCode, + serialize: (plain: string) => plain, }; const [_getMessageTextDecorators, regMessageTextDecorators] = buildRegFn< () => Partial