import * as TID from "@atcute/tid"; import { A, useLocation } from "@solidjs/router"; import { createResource, createSignal, For, onMount, Show } from "solid-js"; import { getAllBacklinks, getRecordBacklinks, LinksWithRecords } from "../lib/api.js"; import { useRepo } from "../lib/repo-context.jsx"; import { localDateFromTimestamp } from "../utils/date.js"; import { Button } from "./button.jsx"; import { Favicon } from "./favicon.jsx"; import DidHoverCard from "./hover-card/did.jsx"; import RecordHoverCard from "./hover-card/record.jsx"; type BacklinksProps = { target: string; collection: string; path: string; repoDid: string; }; type BacklinkEntry = { collection: string; path: string; counts: { distinct_dids: number; records: number }; }; type CollectionGroup = { collection: string; entries: BacklinkEntry[]; totalRecords: number; }; const flattenLinks = (links: Record): BacklinkEntry[] => { const entries: BacklinkEntry[] = []; Object.keys(links) .toSorted() .forEach((collection) => { const paths = links[collection]; Object.keys(paths) .toSorted() .forEach((path) => { if (paths[path].records > 0) { entries.push({ collection, path, counts: paths[path] }); } }); }); return entries; }; const groupByCollection = (entries: BacklinkEntry[]): CollectionGroup[] => { const map = new Map(); for (const entry of entries) { const existing = map.get(entry.collection); if (existing) { existing.push(entry); } else { map.set(entry.collection, [entry]); } } return Array.from(map.entries()).map(([collection, entries]) => ({ collection, entries, totalRecords: entries.reduce((sum, e) => sum + e.counts.records, 0), })); }; const BacklinkRecords = (props: BacklinksProps & { cursor?: string }) => { const [links, setLinks] = createSignal(); const [more, setMore] = createSignal(false); onMount(async () => { const res = await getRecordBacklinks(props.target, props.collection, props.path, props.cursor); setLinks(res); }); return ( Loading…

}> {({ did, collection, rkey }) => { const uri = `at://${did}/${collection}/${rkey}`; const rkeyIsRepo = rkey === props.repoDid; const timestamp = !rkeyIsRepo && TID.validate(rkey) ? localDateFromTimestamp(TID.parse(rkey).timestamp / 1000) : null; return ( {rkey} e.stopPropagation()} > {did} } /> {timestamp ?? ""} } /> ); }} } >
); }; const BacklinkDirectory = (props: { groups: CollectionGroup[]; pathname: string }) => { return (

No backlinks found.

{(group) => { const authority = () => group.collection.split(".").slice(0, 2).join("."); return (
{group.collection}
{group.totalRecords} record{group.totalRecords !== 1 ? "s" : ""}
); }}
); }; const BacklinkCollectionDetail = (props: { target: string; collection: string; entries: BacklinkEntry[]; pathname: string; repoDid: string; }) => { const authority = () => props.collection.split(".").slice(0, 2).join("."); return (
{props.collection}
{(entry) => (
{entry.path.slice(1)} {entry.counts.records} from {entry.counts.distinct_dids} repo {entry.counts.distinct_dids > 1 ? "s" : ""}
)}
); }; const Backlinks = (props: { target: string }) => { const repo = useRepo(); const location = useLocation(); const [response] = createResource(async () => { const res = await getAllBacklinks(props.target); return flattenLinks(res.links); }); const groups = () => (response() ? groupByCollection(response()!) : []); const selectedCollection = () => { const hash = location.hash; if (hash.startsWith("#backlinks:")) { return hash.slice("#backlinks:".length); } return null; }; const selectedEntries = () => { const col = selectedCollection(); if (!col || !response()) return []; return response()!.filter((e) => e.collection === col); }; return (
Failed to load backlinks.

}> Loading…

}> } >

data from{" "} microcosm

); }; export { Backlinks };