diff --git a/web/src/components/ChatBox/ChatMessageList/Item.tsx b/web/src/components/ChatBox/ChatMessageList/Item.tsx index 64b5d60a..1befdfbb 100644 --- a/web/src/components/ChatBox/ChatMessageList/Item.tsx +++ b/web/src/components/ChatBox/ChatMessageList/Item.tsx @@ -23,6 +23,7 @@ import { useChatMessageItemAction } from './useChatMessageItemAction'; import { useChatMessageReaction } from './useChatMessageReaction'; import { DevContainer } from '@/components/DevContainer'; import { TcPopover } from '@/components/TcPopover'; +import { useMessageReactions } from './useMessageReactions'; /** * 消息引用 @@ -62,6 +63,8 @@ const NormalMessage: React.FC = React.memo((props) => { const userInfo = useCachedUserInfo(payload.author ?? ''); const [isActionBtnActive, setIsActionBtnActive] = useState(false); + const reactions = useMessageReactions(payload); + const emojiAction = useChatMessageReaction(payload); const moreActions = useChatMessageItemAction(payload); @@ -102,6 +105,8 @@ const NormalMessage: React.FC = React.memo((props) => { {/* 解释器按钮 */} {useRenderPluginMessageInterpreter(payload.content)} + + {reactions} {/* 操作 */} diff --git a/web/src/components/ChatBox/ChatMessageList/item.less b/web/src/components/ChatBox/ChatMessageList/item.less index b2daa581..a2210651 100644 --- a/web/src/components/ChatBox/ChatMessageList/item.less +++ b/web/src/components/ChatBox/ChatMessageList/item.less @@ -4,6 +4,13 @@ max-height: 60px !important; } } + + .chat-message-reactions { + .emoji-mart-emoji { + display: flex; + align-items: center; + } + } } .chat-message-item_action-popover { diff --git a/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx b/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx index 3d3be66f..92d11a43 100644 --- a/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx +++ b/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx @@ -1,4 +1,4 @@ -import { EmojiPanel } from '@/components/EmojiPanel'; +import { EmojiPanel } from '@/components/Emoji'; import { useTcPopoverContext } from '@/components/TcPopover'; import type { RenderFunction } from 'antd/lib/_util/getRenderPropValue'; import React, { useMemo } from 'react'; diff --git a/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx b/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx new file mode 100644 index 00000000..5267a2f6 --- /dev/null +++ b/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx @@ -0,0 +1,42 @@ +import type { ChatMessage } from 'tailchat-shared'; +import _groupBy from 'lodash/groupBy'; +import _uniqBy from 'lodash/uniqBy'; +import { useMemo } from 'react'; +import { Emoji } from '@/components/Emoji'; +import React from 'react'; +import { Tooltip } from 'antd'; + +/** + * 消息反应表情渲染 + */ +export function useMessageReactions(payload: ChatMessage) { + const reactions = payload.reactions ?? []; + + const groupedReactions = useMemo(() => { + const groups = _groupBy(reactions, 'name'); + + return Object.keys(groups).map((name) => { + const reactions = _uniqBy(groups[name], 'author'); + return { + name, + length: reactions.length, + users: reactions.map((r) => r.author), + }; + }); + }, [reactions]); + + return ( +
+ {groupedReactions.map((reaction) => ( +
+ + + {reaction.length > 1 && {reaction.length}} +
+ ))} +
+ ); +} diff --git a/web/src/components/Emoji/Emoji.tsx b/web/src/components/Emoji/Emoji.tsx new file mode 100644 index 00000000..c7d6f5ed --- /dev/null +++ b/web/src/components/Emoji/Emoji.tsx @@ -0,0 +1,12 @@ +import { Emoji as OriginEmoji, EmojiProps } from 'emoji-mart'; +import React from 'react'; + +interface Props extends Omit { + size?: number; +} +const Emoji: React.FC = React.memo((props) => { + return ; +}); +Emoji.displayName = 'Emoji'; + +export default Emoji; diff --git a/web/src/components/EmojiPanel/Picker.less b/web/src/components/Emoji/Picker.less similarity index 100% rename from web/src/components/EmojiPanel/Picker.less rename to web/src/components/Emoji/Picker.less diff --git a/web/src/components/EmojiPanel/Picker.tsx b/web/src/components/Emoji/Picker.tsx similarity index 100% rename from web/src/components/EmojiPanel/Picker.tsx rename to web/src/components/Emoji/Picker.tsx diff --git a/web/src/components/EmojiPanel/const.ts b/web/src/components/Emoji/const.ts similarity index 100% rename from web/src/components/EmojiPanel/const.ts rename to web/src/components/Emoji/const.ts diff --git a/web/src/components/EmojiPanel/index.tsx b/web/src/components/Emoji/index.tsx similarity index 74% rename from web/src/components/EmojiPanel/index.tsx rename to web/src/components/Emoji/index.tsx index 8450e8b1..202bceff 100644 --- a/web/src/components/EmojiPanel/index.tsx +++ b/web/src/components/Emoji/index.tsx @@ -1,6 +1,13 @@ import React from 'react'; import { Loadable } from '../Loadable'; +const Emoji = Loadable( + () => + import( + /* webpackChunkName: 'emoji' */ /* webpackPrefetch: true */ './Emoji' + ) +); + const EmojiPicker = Loadable( () => import( @@ -8,6 +15,8 @@ const EmojiPicker = Loadable( ) ); +export { Emoji }; + /** * emoji表情面板 */