import type { Video, VideoStatus } from "../lib/api"; import { FEED_VIEW_SPEC, type FeedView } from "../lib/feedView"; import VideoCard from "./VideoCard"; import VirtualGrid from "./VirtualGrid"; // Estimated row heights before measurement; real heights are measured per-row so these only affect // the very first paint and the scrollbar's initial guess. Taken from measuring each mode in the // browser rather than guessed — a bad estimate makes the scrollbar jump as you scroll in. // RE-MEASURE these when a mode's layout changes: they have gone stale twice already, most recently // when the bare row became a single line and halved (82 -> 46). The card figures are the roughest // of the set by nature — a card's height follows its column width (measured ~307 at 3 columns, // ~301 at 4, taller still at 2), so no single constant is right for every window. const ROW_EST: Record = { cards: 340, cardsSmall: 257, rows: 115, rowsCompact: 46, tiles: 132, }; export interface VirtualFeedProps { items: Video[]; view: FeedView; onState: (id: string, status: VideoStatus) => void; onToggleSave: (id: string, saved: boolean) => void; onResetState: (id: string) => void; onOpen: (v: Video, startAt?: number | null) => void; hasNextPage: boolean; isFetchingNextPage: boolean; fetchNextPage: () => void; } // The feed's videos on the shared VirtualGrid engine — this wrapper only maps a FeedView to the // grid's layout spec and renders a VideoCard per item. All the virtualization mechanics (measure, // chunk, place, infinite-scroll) live in VirtualGrid. export default function VirtualFeed({ items, view, onState, onToggleSave, onResetState, onOpen, hasNextPage, isFetchingNextPage, fetchNextPage, }: VirtualFeedProps) { const { minCol, maxCol, thumb } = FEED_VIEW_SPEC[view]; return ( v.id} minCol={minCol} maxCol={maxCol} rowEst={ROW_EST[view]} hasNextPage={hasNextPage} isFetchingNextPage={isFetchingNextPage} fetchNextPage={fetchNextPage} renderItem={(v, itemWidth) => ( )} /> ); }