import { useInView } from "react-intersection-observer"; import ProfileImage from "@/Element/User/ProfileImage"; import { FormattedMessage } from "react-intl"; import Icon from "@/Icons/Icon"; import { NostrLink, TaggedNostrEvent } from "@snort/system"; import { ReactNode } from "react"; import { TimelineFragment } from "@/Element/Feed/TimelineFragment"; import { transformTextCached } from "@/Hooks/useTextTransformCache"; import useImgProxy from "@/Hooks/useImgProxy"; import { Link } from "react-router-dom"; import { DisplayAs } from "@/Element/Feed/DisplayAsSelector"; export interface TimelineRendererProps { frags: Array; related: Array; /** * List of pubkeys who have posted recently */ latest: Array; showLatest: (toTop: boolean) => void; noteRenderer?: (ev: TaggedNostrEvent) => ReactNode; noteOnClick?: (ev: TaggedNostrEvent) => void; noteContext?: (ev: TaggedNostrEvent) => ReactNode; displayAs?: DisplayAs; } export function TimelineRenderer(props: TimelineRendererProps) { const { ref, inView } = useInView(); const { proxy } = useImgProxy(); const renderNotes = () => { return props.frags.map(frag => ( )); }; const renderGrid = () => { // TODO Hide images from notes with a content warning, unless otherwise configured const noteImageRenderer = (e: TaggedNostrEvent) => { const parsed = transformTextCached(e.id, e.content, e.tags); const media = parsed.filter( a => a.type === "media" && (a.mimeType?.startsWith("image/") || a.mimeType?.startsWith("video/")), ); if (media.length === 0) return null; const isVideo = media[0].mimeType?.startsWith("video/"); const noteId = NostrLink.fromEvent(e).encode(CONFIG.eventLinkPrefix); const onClick = (clickEvent: React.MouseEvent) => { if (props.noteOnClick) { props.noteOnClick(e); clickEvent.preventDefault(); } }; return ( Note Media {isVideo && } ); }; const noteRenderer = props.noteRenderer || noteImageRenderer; return props.frags.map(frag => (
{frag.events.map(event => noteRenderer(event))}
)); }; return ( <> {props.latest.length > 0 && ( <>
props.showLatest(false)} ref={ref}> {props.latest.slice(0, 3).map(p => { return ; })}
{!inView && (
props.showLatest(true)}> {props.latest.slice(0, 3).map(p => { return ( ); })}
)} )} {props.displayAs === "grid" ? renderGrid() : renderNotes()} ); }