"use client"; /** * ScrollFeed — client body for /u/[handle]/posts (public scroll feed). * * Split out from page.tsx so the page itself can be a server component * exporting `generateMetadata` for the OG card. The layout owns the * ProfileHeader + tabs + outer container (and 404s for unknown handles); * this component only renders the inner scroll column. * * Anchor-first + keyset infinite scroll via usePostScrollFeed: arriving with * `#post-` (from a grid thumbnail or a shared link) fetches that post * directly so it lands at the top instantly — even for very old posts — then * pages older posts beneath it as you scroll. */ import { use } from "react"; import { Loader2 } from "lucide-react"; import { profile, type Post } from "@/lib/social"; import { PostScrollCard } from "@/components/social/post/post-scroll-card"; import { usePostScrollFeed } from "@/components/social/post/use-post-scroll-feed"; export function ScrollFeed({ params, }: { params: Promise<{ handle: string }>; }) { const { handle } = use(params); const { feed, setFeed, loading, hasMore, sentinelRef } = usePostScrollFeed( (before, limit) => profile.feed(handle, { limit, before: before ?? undefined }), ); // When the owner views their own profile here and hides a post, drop it // from the feed immediately (it moves to their Hidden tab). No-op for // other viewers, who never see the Hide control. function onHiddenChange(id: string, hidden: boolean) { if (hidden) setFeed((rows: Post[]) => rows.filter((p) => p.id !== id)); } return (
{loading && feed.length === 0 ? (

Loading…

) : feed.length === 0 ? (

No posts yet.

) : ( feed.map((p) => ( )) )} {hasMore && feed.length > 0 ? (
) : null}
); }