From a11d4638bb1bed896b11308e75af55b514e2e7b0 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Jan 2026 18:29:49 +0000 Subject: [PATCH] feat: Enhance ThreadViewer with detail renderer and relay hints Improves root event display and derives better relay hints for comment discovery. **Root Event Display:** - Use DetailKindRenderer instead of KindRenderer + BaseEventContainer - Provides richer, more detailed view of the root event - Consistent with EventDetailViewer presentation **Relay Hints Derivation:** - Extract relays from root event's seen relays (where it was published) - Get author's outbox relays from kind 10002 relay list - Include relay hints from event pointer if available - Stored in _relayHints for future relay targeting enhancement **Technical Details:** - Use eventStore.getReplaceable() for synchronous relay list access - Use getSeenRelays() from applesauce-core/helpers/relays - Use getOutboxes() to extract write relays from NIP-65 relay lists - Relay hints currently unused but prepared for future loader integration **Future Enhancement:** The relay hints infrastructure is ready for integration with createTimelineLoader or explicit relay targeting when querying for comments, which would improve comment discovery for events with sparse relay distribution. This provides a better foundation for discovering comments across the network by knowing where the root author publishes and where the root event was seen. --- src/components/ThreadViewer.tsx | 47 ++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/components/ThreadViewer.tsx b/src/components/ThreadViewer.tsx index f097382..76c0ed0 100644 --- a/src/components/ThreadViewer.tsx +++ b/src/components/ThreadViewer.tsx @@ -1,7 +1,7 @@ import { useMemo, useState } from "react"; import type { EventPointer, AddressPointer } from "nostr-tools/nip19"; import { useNostrEvent } from "@/hooks/useNostrEvent"; -import { KindRenderer } from "./nostr/kinds"; +import { DetailKindRenderer } from "./nostr/kinds"; import { EventErrorBoundary } from "./EventErrorBoundary"; import { EventDetailSkeleton } from "@/components/ui/skeleton"; import type { NostrEvent } from "@/types/nostr"; @@ -16,8 +16,9 @@ import { import { ChevronDown, ChevronRight, MessageCircle } from "lucide-react"; import { UserName } from "./nostr/UserName"; import { RichText } from "./nostr/RichText"; -import { BaseEventContainer } from "./nostr/kinds/BaseEventRenderer"; import { formatDistanceToNow } from "date-fns"; +import { getSeenRelays } from "applesauce-core/helpers/relays"; +import { getOutboxes } from "applesauce-core/helpers"; export interface ThreadViewerProps { pointer: EventPointer | AddressPointer; @@ -209,6 +210,39 @@ function CommentReply({ export function ThreadViewer({ pointer, focusEventId }: ThreadViewerProps) { const rootEvent = useNostrEvent(pointer); + // Derive relay hints from root event and author for better comment discovery + // Prefixed with _ as it's currently unused but kept for future relay targeting enhancement + // @ts-expect-error - Kept for future use with explicit relay targeting + const _relayHints = useMemo(() => { + if (!rootEvent) return []; + + const hints = new Set(); + + // 1. Get relays where root event was seen + const seenRelaysSet = getSeenRelays(rootEvent); + if (seenRelaysSet) { + seenRelaysSet.forEach((r) => hints.add(r)); + } + + // 2. Get author's outbox relays (where they publish) + const authorRelayList = eventStore.getReplaceable( + 10002, + rootEvent.pubkey, + "", + ); + if (authorRelayList) { + const outboxes = getOutboxes(authorRelayList); + outboxes.forEach((r) => hints.add(r)); + } + + // 3. Add relay hints from pointer if available + if ("relays" in pointer && pointer.relays) { + pointer.relays.forEach((r) => hints.add(r)); + } + + return Array.from(hints); + }, [rootEvent, pointer]); + // Build filter for comments on this event const commentsFilter = useMemo(() => { if (!rootEvent) return null; @@ -235,6 +269,9 @@ export function ThreadViewer({ pointer, focusEventId }: ThreadViewerProps) { }, [rootEvent, pointer]); // Fetch comments timeline and subscribe to events + // Note: relayHints are derived above for potential future use with explicit relay targeting + // Currently timeline() uses the global relay pool, but we could enhance this to use + // createTimelineLoader with relay hints for better comment discovery const comments = use$(() => { if (!commentsFilter) return undefined; return eventStore.timeline(commentsFilter); @@ -257,12 +294,10 @@ export function ThreadViewer({ pointer, focusEventId }: ThreadViewerProps) { return (
- {/* Root Event */} + {/* Root Event - Display with detail renderer */}
- - - +