"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import { Modal } from "../Modal"; import { ToggleGroup } from "../ToggleGroup"; import { SpeedyLink } from "../SpeedyLink"; import { DotLoader } from "../utils/DotLoader"; import { DocumentProvider } from "contexts/DocumentContext"; import { LeafletContentProvider } from "contexts/LeafletContentContext"; import { CommentsDrawerContent } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/Interactions/Comments"; import { DiscussionDrawerContent } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/Interactions/Quotes"; import { type DrawerThread, DrawerThreadContext, } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/Interactions/drawerThreadContext"; import { ThreadView } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/ThreadPage"; import { StandardSitePostDrawerView } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/Interactions/StandardSitePostDrawerView"; import { RecommendsList } from "./RecommendsList"; import { decodeQuotePosition } from "src/utils/quotePosition"; import { useDocumentDiscussionData } from "app/(app)/(published)/lish/[did]/[publication]/[rkey]/Interactions/useDocumentDiscussionData"; import { GoToArrow } from "../Icons/GoToArrow"; import { GoBackTiny } from "../Icons/GoBackTiny"; import { DoubleArrowRightTiny } from "../Icons/DoubleArrowRightTiny"; import { ButtonPrimary } from "../Buttons"; import { StandardSitePostItem } from "../Blocks/StandardSitePostBlock/StandardSitePostItem"; // A post's comments and Bluesky mentions with a toggle between them, fetching // everything it needs from get_document_interactions and providing the // Document/LeafletContent contexts the shared drawer content expects. Wrapped // in a modal/sheet by DiscussionModal below (post listings, page-link blocks); // the reader's post viewer renders it directly inside its own box instead, so // opening discussions there swaps the box's content with no layout shift. export function DiscussionContent(props: { open: boolean; document_uri: string; postUrl: string; title?: string; commentsCount: number; quotesCount: number; showComments: boolean; showMentions: boolean; pageId?: string; bgColor?: string; // Replaces the header's link to the post, for surfaces that already have it // on screen (the reader's post viewer) and need their own control instead. postLinkButton?: React.ReactNode; }) { const commentsAvailable = props.showComments && props.commentsCount > 0; const mentionsAvailable = props.showMentions && props.quotesCount > 0; const bothAvailable = commentsAvailable && mentionsAvailable; const [tab, setTab] = useState<"comments" | "quotes">( commentsAvailable ? "comments" : "quotes", ); useEffect(() => { if (props.open) setTab(commentsAvailable ? "comments" : "quotes"); }, [props.open]); const { isLoading, data, did, pages, documentContextValue, comments } = useDocumentDiscussionData(props.document_uri, props.open); const [threadStack, setThreadStack] = useState([]); const drawerNav = useMemo( () => ({ push: (thread: DrawerThread) => setThreadStack((s) => { const top = s[s.length - 1]; if (top && top.type === thread.type && top.uri === thread.uri) return s; return [...s, thread]; }), }), [], ); const activeThread = threadStack[threadStack.length - 1]; const topRef = useRef(null); useEffect(() => { topRef.current?.scrollIntoView({ block: "nearest" }); }, [threadStack.length]); const quotesAndMentions = (data?.quotesAndMentions ?? []).filter((q) => { if (!q.link) return !props.pageId; const url = new URL(q.link); const quoteParam = url.pathname.split("/l-quote/")[1]; if (!quoteParam) return !props.pageId; const quotePosition = decodeQuotePosition(quoteParam); return quotePosition?.pageId === props.pageId; }); return ( <>
{/* bg matches the surface it scrolls over: plain bg-page in the mobile sheet, the bg-light tint in the desktop modal (sm: aligns with the useIsMobile breakpoint). */}
{activeThread ? (
{threadStack.length >= 2 && ( )}
) : bothAvailable ? ( setTab(value)} options={[ { value: "comments", label: props.commentsCount > 0 ? `Comments (${props.commentsCount})` : "Comments", }, { value: "quotes", label: (
Bluesky Mentions{" "} {props.quotesCount > 0 && `(${props.quotesCount})`}
), }, ]} /> ) : (
{commentsAvailable ? `Comments (${props.commentsCount})` : `Bluesky Mentions (${props.quotesCount})`}
)}{" "} {props.postLinkButton ?? ( Full Post )}

{!data && isLoading ? (
loading
) : documentContextValue ? ( {activeThread?.type === "recommends" ? ( ) : activeThread?.type === "standardSitePost" ? ( ) : activeThread ? ( ) : tab === "comments" ? ( ) : ( )} ) : null}
); } export function DiscussionModal( props: React.ComponentProps & { onOpenChange: (open: boolean) => void; }, ) { return (
); }