Barazo default frontend barazo.forum
at main 78 lines 2.6 kB view raw
1/** 2 * ReplyThread - Displays a threaded tree of replies. 3 * Reconstructs tree from flat API response, assigns depth-first post numbers. 4 * Post numbers start at 2 (post #1 is the topic itself). 5 * Uses viewport-aware indent steps for responsive nesting. 6 * @see specs/prd-web.md Section 4 (Topic Components) 7 */ 8 9'use client' 10 11import { useMemo } from 'react' 12import type { Reply } from '@/lib/api/types' 13import { cn } from '@/lib/utils' 14import { buildReplyTree, flattenReplyTree } from '@/lib/build-reply-tree' 15import { useThreadIndent } from '@/hooks/use-thread-indent' 16import { ThreadHoverProvider } from '@/context/thread-hover-context' 17import { ReplyBranch } from './reply-branch' 18 19interface ReplyThreadProps { 20 replies: Reply[] 21 topicUri: string 22 onReply?: (target: { uri: string; cid: string; authorHandle: string; snippet: string }) => void 23 onDeleteReply?: () => void 24 currentUserDid?: string 25 className?: string 26} 27 28export function ReplyThread({ 29 replies, 30 topicUri, 31 onReply, 32 onDeleteReply, 33 currentUserDid, 34 className, 35}: ReplyThreadProps) { 36 const replyCount = replies.length 37 const heading = 38 replyCount === 0 ? 'Replies' : replyCount === 1 ? '1 Reply' : `${replyCount} Replies` 39 40 const { indentStep, showChevron } = useThreadIndent() 41 42 const { tree, postNumberMap, allReplies } = useMemo(() => { 43 const builtTree = buildReplyTree(replies, topicUri) 44 const flat = flattenReplyTree(builtTree) 45 const map = new Map<string, number>() 46 flat.forEach((reply, index) => { 47 map.set(reply.uri, index + 2) 48 }) 49 const replyMap = new Map(replies.map((r) => [r.uri, r])) 50 return { tree: builtTree, postNumberMap: map, allReplies: replyMap } 51 }, [replies, topicUri]) 52 53 return ( 54 <section className={cn('space-y-4', className)} aria-label="Replies"> 55 <h2 className="text-lg font-semibold text-foreground">{heading}</h2> 56 57 {replyCount === 0 ? ( 58 <div className="rounded-lg border border-border bg-card p-6 text-center"> 59 <p className="text-muted-foreground">No replies yet. Be the first to respond!</p> 60 </div> 61 ) : ( 62 <ThreadHoverProvider> 63 <ReplyBranch 64 nodes={tree} 65 postNumberMap={postNumberMap} 66 topicUri={topicUri} 67 allReplies={allReplies} 68 indentStep={indentStep} 69 showChevron={showChevron} 70 onReply={onReply} 71 onDeleteReply={onDeleteReply} 72 currentUserDid={currentUserDid} 73 /> 74 </ThreadHoverProvider> 75 )} 76 </section> 77 ) 78}