diff --git a/package.json b/package.json index 3c19f0cd..d62e56d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocechat-web", - "version": "0.9.44", + "version": "0.9.45", "homepage": "https://voce.chat", "dependencies": { "@metamask/onboarding": "^1.0.1", diff --git a/src/components/Message/Reply.tsx b/src/components/Message/Reply.tsx index 8382d33e..eb0fccf7 100644 --- a/src/components/Message/Reply.tsx +++ b/src/components/Message/Reply.tsx @@ -102,6 +102,13 @@ const Reply: FC = ({ mid, interactive = true, context, to = 0 }) => msgEle.classList.remove(_class1); msgEle.classList.remove(_class2); }, 3000); + } else { + // 消息不在DOM中,触发自定义事件让虚拟列表滚动 + const feedId = `VOCECHAT_FEED_${context}_${to}`; + const feedEle = document.getElementById(feedId); + if (feedEle) { + feedEle.dispatchEvent(new CustomEvent('scrollToMessage', { detail: { mid: Number(mid) } })); + } } }; const defaultClass = `w-fit flex items-start flex-col md:flex-row p-2 bg-gray-100 dark:bg-gray-900 rounded-lg gap-2 mb-1`; diff --git a/src/components/Message/index.tsx b/src/components/Message/index.tsx index 0ac1bcbf..d2fe7a96 100644 --- a/src/components/Message/index.tsx +++ b/src/components/Message/index.tsx @@ -53,6 +53,12 @@ const Message: FC = ({ const currUser = useAppSelector((store) => store.users.byId[message?.from_uid || 0], shallowEqual); // 只订阅当前消息的reaction,而不是整个reactionMessageData const reactions = useAppSelector((store) => store.reactionMessage[mid], shallowEqual); + // 获取pinInfo中需要的用户信息 + const pinInfo = getPinInfo(mid); + const pinCreatorName = useAppSelector((store) => + pinInfo?.created_by ? store.users.byId[pinInfo.created_by]?.name : undefined, + shallowEqual + ); const toggleEditMessage = () => { setEdit((prev) => !prev); @@ -85,13 +91,6 @@ const Message: FC = ({ expires_in = 0, failed = false, } = message; - - // 获取pinInfo中需要的用户信息 - const pinInfo = getPinInfo(mid); - const pinCreatorName = useAppSelector((store) => - pinInfo?.created_by ? store.users.byId[pinInfo.created_by]?.name : undefined, - shallowEqual - ); // if (!message) return null; let timePrefix = null; diff --git a/src/routes/chat/Layout/VirtualMessageFeed/index.tsx b/src/routes/chat/Layout/VirtualMessageFeed/index.tsx index 825f90b3..208c3577 100644 --- a/src/routes/chat/Layout/VirtualMessageFeed/index.tsx +++ b/src/routes/chat/Layout/VirtualMessageFeed/index.tsx @@ -69,6 +69,58 @@ const VirtualMessageFeed = forwardRef(({ contex }, 500); }, [id]); + useEffect(() => { + const feedId = `VOCECHAT_FEED_${context}_${id}`; + const feedEle = document.getElementById(feedId); + + const handleScrollToMessage = (evt: CustomEvent) => { + const { mid } = evt.detail; + const index = mids.findIndex((m) => m === mid); + if (index !== -1 && vList.current) { + vList.current.scrollToIndex({ index, align: "center", behavior: "smooth" }); + setTimeout(() => { + const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); + if (msgEle) { + const _class1 = `md:dark:bg-gray-800`; + const _class2 = `md:bg-gray-100`; + msgEle.classList.add(_class1); + msgEle.classList.add(_class2); + setTimeout(() => { + msgEle.classList.remove(_class1); + msgEle.classList.remove(_class2); + }, 3000); + } + }, 500); + } else if (allMids.includes(mid)) { + setVisibleCount(allMids.length); + setTimeout(() => { + const idx = allMids.findIndex((m) => m === mid); + if (idx !== -1 && vList.current) { + vList.current.scrollToIndex({ index: idx, align: "center", behavior: "smooth" }); + setTimeout(() => { + const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); + if (msgEle) { + const _class1 = `md:dark:bg-gray-800`; + const _class2 = `md:bg-gray-100`; + msgEle.classList.add(_class1); + msgEle.classList.add(_class2); + setTimeout(() => { + msgEle.classList.remove(_class1); + msgEle.classList.remove(_class2); + }, 3000); + } + }, 500); + } + }, 100); + } + }; + + feedEle?.addEventListener('scrollToMessage', handleScrollToMessage as EventListener); + return () => { + feedEle?.removeEventListener('scrollToMessage', handleScrollToMessage as EventListener); + }; + }, [context, id, mids, allMids]); + useEffect(() => { if (isSuccess && historyData) { if (historyData.length == 0) {