refactor: 🎨

This commit is contained in:
codytseng
2025-12-24 10:55:05 +08:00
parent 96abe5f24f
commit 49eca495f5
3 changed files with 57 additions and 22 deletions

View File

@@ -1,12 +1,14 @@
import { useSecondaryPage } from '@/PageManager'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/ui/skeleton'
import { isMentioningMutedUsers } from '@/lib/event'
import { getEventKey, isMentioningMutedUsers } from '@/lib/event'
import { toNote } from '@/lib/link'
import { cn } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useMuteList } from '@/providers/MuteListProvider'
import { useReply } from '@/providers/ReplyProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
import { Event } from 'nostr-tools'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -40,7 +42,9 @@ export default function ReplyNote({
const { isSmallScreen } = useScreenSize()
const { push } = useSecondaryPage()
const { mutePubkeySet } = useMuteList()
const { hideUntrustedInteractions, isUserTrusted } = useUserTrust()
const { hideContentMentioningMutedUsers } = useContentPolicy()
const { repliesMap } = useReply()
const [showMuted, setShowMuted] = useState(false)
const show = useMemo(() => {
if (showMuted) {
@@ -54,16 +58,37 @@ export default function ReplyNote({
}
return true
}, [showMuted, mutePubkeySet, event, hideContentMentioningMutedUsers])
const hasReplies = useMemo(() => {
const key = getEventKey(event)
const replies = repliesMap.get(key)?.events
if (!replies || replies.length === 0) {
return false
}
for (const reply of replies) {
if (hideUntrustedInteractions && !isUserTrusted(reply.pubkey)) {
continue
}
if (mutePubkeySet.has(reply.pubkey)) {
continue
}
if (hideContentMentioningMutedUsers && isMentioningMutedUsers(reply, mutePubkeySet)) {
continue
}
return true
}
}, [event, repliesMap])
return (
<div
className={cn(
'pb-3 transition-colors duration-500 clickable',
'relative pb-3 transition-colors duration-500 clickable',
highlight ? 'bg-primary/40' : '',
className
)}
onClick={() => push(toNote(event))}
>
{hasReplies && <div className="absolute left-[34px] top-14 bottom-0 border-l" />}
<Collapsible>
<div className="flex space-x-2 items-start px-4 pt-3">
<UserAvatar userId={event.pubkey} size="medium" className="shrink-0 mt-0.5" />

View File

@@ -81,7 +81,7 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
}, 1500)
}, [])
if (replies.length === 0) return <div className="border-b w-full" />
if (replies.length === 0) return null
return (
<div>
@@ -91,11 +91,16 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
e.stopPropagation()
setIsExpanded(!isExpanded)
}}
className={cn(
'w-full flex items-center gap-1.5 pl-14 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors clickable',
!isExpanded && 'border-b'
)}
className="relative w-full flex items-center gap-1.5 pl-14 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors clickable"
>
<div
className={cn('absolute left-[34px] top-0 bottom-0 w-px text-border')}
style={{
background: isExpanded
? 'currentColor'
: 'repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 7px)'
}}
/>
{isExpanded ? (
<>
<ChevronUp className="size-3.5" />
@@ -125,14 +130,14 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
<div
ref={(el) => (replyRefs.current[currentReplyKey] = el)}
key={currentReplyKey}
className="scroll-mt-12 flex"
className="scroll-mt-12 flex relative"
>
<div className="w-3 flex-shrink-0 bg-border" />
<div className="absolute left-[34px] top-0 h-8 w-4 rounded-bl-lg border-l border-b" />
{index < replies.length - 1 && (
<div className="absolute left-[34px] top-0 bottom-0 border-l" />
)}
<ReplyNote
className={cn(
'border-l flex-1 w-0 border-t',
index === replies.length - 1 && 'border-b'
)}
className="flex-1 w-0 pl-10"
event={reply}
parentEventId={_parentKey !== parentKey ? _parentEventId : undefined}
onClickParent={() => {

View File

@@ -272,15 +272,9 @@ export default function ReplyNoteList({
</div>
)}
<div>
{replies.slice(0, showCount).map((reply) => {
const key = getEventKey(reply)
return (
<div key={key}>
<ReplyNote event={reply} />
<SubReplies parentKey={key} />
</div>
)
})}
{replies.slice(0, showCount).map((reply) => (
<Item key={reply.id} reply={reply} />
))}
</div>
{!loading && (
<div className="text-sm mt-2 mb-3 text-center text-muted-foreground">
@@ -292,3 +286,14 @@ export default function ReplyNoteList({
</div>
)
}
function Item({ reply }: { reply: NEvent }) {
const key = useMemo(() => getEventKey(reply), [reply])
return (
<div className="relative border-b">
<ReplyNote event={reply} />
<SubReplies parentKey={key} />
</div>
)
}