refactor: 🎨
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
import { useSecondaryPage } from '@/PageManager'
|
import { useSecondaryPage } from '@/PageManager'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
import { isMentioningMutedUsers } from '@/lib/event'
|
import { getEventKey, isMentioningMutedUsers } from '@/lib/event'
|
||||||
import { toNote } from '@/lib/link'
|
import { toNote } from '@/lib/link'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useMuteList } from '@/providers/MuteListProvider'
|
import { useMuteList } from '@/providers/MuteListProvider'
|
||||||
|
import { useReply } from '@/providers/ReplyProvider'
|
||||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||||
|
import { useUserTrust } from '@/providers/UserTrustProvider'
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -40,7 +42,9 @@ export default function ReplyNote({
|
|||||||
const { isSmallScreen } = useScreenSize()
|
const { isSmallScreen } = useScreenSize()
|
||||||
const { push } = useSecondaryPage()
|
const { push } = useSecondaryPage()
|
||||||
const { mutePubkeySet } = useMuteList()
|
const { mutePubkeySet } = useMuteList()
|
||||||
|
const { hideUntrustedInteractions, isUserTrusted } = useUserTrust()
|
||||||
const { hideContentMentioningMutedUsers } = useContentPolicy()
|
const { hideContentMentioningMutedUsers } = useContentPolicy()
|
||||||
|
const { repliesMap } = useReply()
|
||||||
const [showMuted, setShowMuted] = useState(false)
|
const [showMuted, setShowMuted] = useState(false)
|
||||||
const show = useMemo(() => {
|
const show = useMemo(() => {
|
||||||
if (showMuted) {
|
if (showMuted) {
|
||||||
@@ -54,16 +58,37 @@ export default function ReplyNote({
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}, [showMuted, mutePubkeySet, event, hideContentMentioningMutedUsers])
|
}, [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 (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'pb-3 transition-colors duration-500 clickable',
|
'relative pb-3 transition-colors duration-500 clickable',
|
||||||
highlight ? 'bg-primary/40' : '',
|
highlight ? 'bg-primary/40' : '',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onClick={() => push(toNote(event))}
|
onClick={() => push(toNote(event))}
|
||||||
>
|
>
|
||||||
|
{hasReplies && <div className="absolute left-[34px] top-14 bottom-0 border-l" />}
|
||||||
<Collapsible>
|
<Collapsible>
|
||||||
<div className="flex space-x-2 items-start px-4 pt-3">
|
<div className="flex space-x-2 items-start px-4 pt-3">
|
||||||
<UserAvatar userId={event.pubkey} size="medium" className="shrink-0 mt-0.5" />
|
<UserAvatar userId={event.pubkey} size="medium" className="shrink-0 mt-0.5" />
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
|
|||||||
}, 1500)
|
}, 1500)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (replies.length === 0) return <div className="border-b w-full" />
|
if (replies.length === 0) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -91,11 +91,16 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setIsExpanded(!isExpanded)
|
setIsExpanded(!isExpanded)
|
||||||
}}
|
}}
|
||||||
className={cn(
|
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"
|
||||||
'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'
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
|
<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 ? (
|
{isExpanded ? (
|
||||||
<>
|
<>
|
||||||
<ChevronUp className="size-3.5" />
|
<ChevronUp className="size-3.5" />
|
||||||
@@ -125,14 +130,14 @@ export default function SubReplies({ parentKey }: { parentKey: string }) {
|
|||||||
<div
|
<div
|
||||||
ref={(el) => (replyRefs.current[currentReplyKey] = el)}
|
ref={(el) => (replyRefs.current[currentReplyKey] = el)}
|
||||||
key={currentReplyKey}
|
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
|
<ReplyNote
|
||||||
className={cn(
|
className="flex-1 w-0 pl-10"
|
||||||
'border-l flex-1 w-0 border-t',
|
|
||||||
index === replies.length - 1 && 'border-b'
|
|
||||||
)}
|
|
||||||
event={reply}
|
event={reply}
|
||||||
parentEventId={_parentKey !== parentKey ? _parentEventId : undefined}
|
parentEventId={_parentKey !== parentKey ? _parentEventId : undefined}
|
||||||
onClickParent={() => {
|
onClickParent={() => {
|
||||||
|
|||||||
@@ -272,15 +272,9 @@ export default function ReplyNoteList({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
{replies.slice(0, showCount).map((reply) => {
|
{replies.slice(0, showCount).map((reply) => (
|
||||||
const key = getEventKey(reply)
|
<Item key={reply.id} reply={reply} />
|
||||||
return (
|
))}
|
||||||
<div key={key}>
|
|
||||||
<ReplyNote event={reply} />
|
|
||||||
<SubReplies parentKey={key} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
{!loading && (
|
{!loading && (
|
||||||
<div className="text-sm mt-2 mb-3 text-center text-muted-foreground">
|
<div className="text-sm mt-2 mb-3 text-center text-muted-foreground">
|
||||||
@@ -292,3 +286,14 @@ export default function ReplyNoteList({
|
|||||||
</div>
|
</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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user