import { Client, simpleFetchHandler } from "@atcute/client"; import { ActorIdentifier } from "@atcute/lexicons"; import { createSignal, Show } from "solid-js"; import { getPDS } from "../../utils/api"; import { JSONValue } from "../json"; import HoverCard from "./base"; interface RecordHoverCardProps { uri: string; newTab?: boolean; class?: string; labelClass?: string; trigger?: any; hoverDelay?: number; } const recordCache = new Map(); const parseAtUri = (uri: string) => { const match = uri.match(/^at:\/\/([^/]+)\/([^/]+)\/(.+)$/); if (!match) return null; return { repo: match[1], collection: match[2], rkey: match[3] }; }; const prefetchRecord = async (uri: string) => { if (recordCache.has(uri)) return; const parsed = parseAtUri(uri); if (!parsed) return; recordCache.set(uri, { value: null, loading: true }); try { const pds = await getPDS(parsed.repo); const rpc = new Client({ handler: simpleFetchHandler({ service: pds }) }); const res = await rpc.get("com.atproto.repo.getRecord", { params: { repo: parsed.repo as ActorIdentifier, collection: parsed.collection as `${string}.${string}.${string}`, rkey: parsed.rkey, }, }); if (!res.ok) { recordCache.set(uri, { value: null, loading: false, error: res.data.error }); return; } recordCache.set(uri, { value: res.data.value, loading: false }); } catch (err: any) { recordCache.set(uri, { value: null, loading: false, error: err.message || "Failed to fetch" }); } }; const RecordHoverCard = (props: RecordHoverCardProps) => { const [record, setRecord] = createSignal<{ value: unknown; loading: boolean; error?: string; } | null>(null); const parsed = () => parseAtUri(props.uri); const handlePrefetch = () => { prefetchRecord(props.uri); // Start polling for cache updates const cached = recordCache.get(props.uri); setRecord(cached || { value: null, loading: true }); if (!cached || cached.loading) { const pollInterval = setInterval(() => { const updated = recordCache.get(props.uri); if (updated && !updated.loading) { setRecord(updated); clearInterval(pollInterval); } }, 100); setTimeout(() => clearInterval(pollInterval), 10000); } }; return (
Loading...
{record()?.error}
); }; export default RecordHoverCard;