import { commands } from "@/commands.gen"; import { replyTime, toLumeEvents } from "@/commons"; import { Note, Spinner, User } from "@/components"; import { Hashtag } from "@/components/note/mentions/hashtag"; import { MentionUser } from "@/components/note/mentions/user"; import { type LumeEvent, LumeWindow } from "@/system"; import { Kind } from "@/types"; import { ArrowRight } from "@phosphor-icons/react"; import * as ScrollArea from "@radix-ui/react-scroll-area"; import { useQuery } from "@tanstack/react-query"; import { createLazyFileRoute } from "@tanstack/react-router"; import { nip19 } from "nostr-tools"; import { type ReactNode, type RefObject, memo, useMemo, useRef } from "react"; import reactStringReplace from "react-string-replace"; import { Virtualizer } from "virtua"; export const Route = createLazyFileRoute("/columns/_layout/stories/$id")({ component: Screen, }); function Screen() { const contacts = Route.useLoaderData(); const ref = useRef(null); return ( } overscan={0} > {!contacts ? (
) : ( contacts.map((contact) => ( )) )}
); } function StoryItem({ contact }: { contact: string }) { const { isLoading, isError, error, data: events, } = useQuery({ queryKey: ["events", "story", contact], queryFn: async () => { const res = await commands.getAllEventsByAuthor(contact, 10); if (res.status === "ok") { const data = toLumeEvents(res.data); return data; } else { throw new Error(res.error); } }, select: (data) => data.filter((ev) => ev.kind === Kind.Text), refetchOnWindowFocus: false, }); const ref = useRef(null); return (
} overscan={0} > {isLoading ? (
) : isError ? (
{error.message}
) : !events?.length ? (
This user didn't have any new notes in the last few days.
) : ( events.map((event) => ) )}
); } const StoryEvent = memo(function StoryEvent({ event }: { event: LumeEvent }) { return (
{replyTime(event.created_at)}
); }); function Content({ text, className }: { text: string; className?: string }) { const content = useMemo(() => { let replacedText: ReactNode[] | string = text.trim(); const nostr = replacedText .split(/\s+/) .filter((w) => w.startsWith("nostr:")); replacedText = reactStringReplace(text, /(https?:\/\/\S+)/g, (match, i) => ( {match} )); replacedText = reactStringReplace(replacedText, /#(\w+)/g, (match, i) => ( )); for (const word of nostr) { const bech32 = word.replace("nostr:", "").replace(/[^\w\s]/gi, ""); try { const data = nip19.decode(bech32); switch (data.type) { case "npub": replacedText = reactStringReplace( replacedText, word, (match, i) => , ); break; case "nprofile": replacedText = reactStringReplace( replacedText, word, (match, i) => ( ), ); break; default: replacedText = reactStringReplace( replacedText, word, (match, i) => ( {match} ), ); break; } } catch { console.log(word); } } return replacedText; }, [text]); return
{content}
; }