From 04dd682e0dd0ef86b35b10da52575ba5a14a4d6e Mon Sep 17 00:00:00 2001 From: codytseng Date: Tue, 17 Dec 2024 15:11:35 +0800 Subject: [PATCH] feat: improve reply experience --- .../src/components/ReplyNoteList/index.tsx | 53 ++++++++++++++----- src/renderer/src/services/client.service.ts | 7 ++- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/renderer/src/components/ReplyNoteList/index.tsx b/src/renderer/src/components/ReplyNoteList/index.tsx index 10669fb..1231d06 100644 --- a/src/renderer/src/components/ReplyNoteList/index.tsx +++ b/src/renderer/src/components/ReplyNoteList/index.tsx @@ -6,27 +6,45 @@ import { useNostr } from '@renderer/providers/NostrProvider' import { useNoteStats } from '@renderer/providers/NoteStatsProvider' import client from '@renderer/services/client.service' import dayjs from 'dayjs' -import { Event, kinds } from 'nostr-tools' +import { Event as NEvent, kinds } from 'nostr-tools' import { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import ReplyNote from '../ReplyNote' const LIMIT = 100 -export default function ReplyNoteList({ event, className }: { event: Event; className?: string }) { +export default function ReplyNoteList({ event, className }: { event: NEvent; className?: string }) { const { t } = useTranslation() const { isReady, pubkey } = useNostr() const [timelineKey, setTimelineKey] = useState(undefined) const [until, setUntil] = useState(() => dayjs().unix()) - const [replies, setReplies] = useState([]) + const [replies, setReplies] = useState([]) const [replyMap, setReplyMap] = useState< - Record + Record >({}) const [loading, setLoading] = useState(false) const [highlightReplyId, setHighlightReplyId] = useState(undefined) const { updateNoteReplyCount } = useNoteStats() const replyRefs = useRef>({}) + useEffect(() => { + const handleEventPublished = (data: Event) => { + const customEvent = data as CustomEvent + const evt = customEvent.detail + if ( + isReplyNoteEvent(evt) && + evt.tags.some(([tagName, tagValue]) => tagName === 'e' && tagValue === event.id) + ) { + onNewReply(evt) + } + } + + client.addEventListener('eventPublished', handleEventPublished) + return () => { + client.removeEventListener('eventPublished', handleEventPublished) + } + }, []) + useEffect(() => { if (!isReady || loading) return @@ -53,11 +71,7 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas }, onNew: (evt) => { if (!isReplyNoteEvent(evt)) return - - setReplies((pre) => [...pre, evt]) - if (evt.pubkey === pubkey) { - highlightReply(evt.id) - } + onNewReply(evt) } } ) @@ -78,7 +92,8 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas useEffect(() => { updateNoteReplyCount(event.id, replies.length) - const replyMap: Record = {} + const replyMap: Record = + {} for (const reply of replies) { const parentReplyTag = reply.tags.find(isReplyETag) if (parentReplyTag) { @@ -95,7 +110,7 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas } let level = 0 - let parent: Event | undefined + let parent: NEvent | undefined for (const [tagName, tagValue] of reply.tags) { if (tagName === 'e') { const info = replyMap[tagValue] @@ -123,10 +138,20 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas setLoading(false) } + const onNewReply = (evt: NEvent) => { + if (replies.some((reply) => reply.id === evt.id)) return + setReplies((pre) => [...pre, evt]) + if (evt.pubkey === pubkey) { + setTimeout(() => { + highlightReply(evt.id) + }, 100) + } + } + const highlightReply = (eventId: string) => { const ref = replyRefs.current[eventId] if (ref) { - ref.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) + ref.scrollIntoView({ behavior: 'smooth', block: 'center' }) } setHighlightReplyId(eventId) setTimeout(() => { @@ -144,10 +169,10 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas {replies.length > 0 && (loading || until) && }
- {replies.map((reply, index) => { + {replies.map((reply) => { const info = replyMap[reply.id] return ( -
(replyRefs.current[reply.id] = el)} key={index}> +
(replyRefs.current[reply.id] = el)} key={reply.id}> {