A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.
1import React from "react";
2import { AtProtoRecord } from "../core/AtProtoRecord";
3import { TangledRepoRenderer } from "../renderers/TangledRepoRenderer";
4import type { TangledRepoRecord } from "../types/tangled";
5import { useAtProto } from "../providers/AtProtoProvider";
6
7/**
8 * Props for rendering Tangled Repo records.
9 */
10export interface TangledRepoProps {
11 /** DID of the repository that stores the repo record. */
12 did: string;
13 /** Record key within the `sh.tangled.repo` collection. */
14 rkey: string;
15 /** Prefetched Tangled Repo record. When provided, skips fetching from the network. */
16 record?: TangledRepoRecord;
17 /** Optional renderer override for custom presentation. */
18 renderer?: React.ComponentType<TangledRepoRendererInjectedProps>;
19 /** Fallback node displayed before loading begins. */
20 fallback?: React.ReactNode;
21 /** Indicator node shown while data is loading. */
22 loadingIndicator?: React.ReactNode;
23 /** Preferred color scheme for theming. */
24 colorScheme?: "light" | "dark" | "system";
25 /** Whether to show star count from backlinks. Defaults to true. */
26 showStarCount?: boolean;
27 /** Branch to query for language information. Defaults to trying "main", then "master". */
28 branch?: string;
29 /** Prefetched language names (e.g., ['TypeScript', 'React']). When provided, skips fetching languages from the knot server. */
30 languages?: string[];
31}
32
33/**
34 * Values injected into custom Tangled Repo renderer implementations.
35 */
36export type TangledRepoRendererInjectedProps = {
37 /** Loaded Tangled Repo record value. */
38 record: TangledRepoRecord;
39 /** Indicates whether the record is currently loading. */
40 loading: boolean;
41 /** Fetch error, if any. */
42 error?: Error;
43 /** Preferred color scheme for downstream components. */
44 colorScheme?: "light" | "dark" | "system";
45 /** DID associated with the record. */
46 did: string;
47 /** Record key for the repo. */
48 rkey: string;
49 /** Canonical external URL for linking to the repo. */
50 canonicalUrl: string;
51 /** Whether to show star count from backlinks. */
52 showStarCount?: boolean;
53 /** Branch to query for language information. */
54 branch?: string;
55 /** Prefetched language names. */
56 languages?: string[];
57};
58
59/** NSID for Tangled Repo records. */
60export const TANGLED_REPO_COLLECTION = "sh.tangled.repo";
61
62/**
63 * Resolves a Tangled Repo record and renders it with optional overrides while computing a canonical link.
64 *
65 * @param did - DID whose Tangled Repo should be fetched.
66 * @param rkey - Record key within the Tangled Repo collection.
67 * @param renderer - Optional component override that will receive injected props.
68 * @param fallback - Node rendered before the first load begins.
69 * @param loadingIndicator - Node rendered while the Tangled Repo is loading.
70 * @param colorScheme - Preferred color scheme for theming the renderer.
71 * @param showStarCount - Whether to show star count from backlinks. Defaults to true.
72 * @param branch - Branch to query for language information. Defaults to trying "main", then "master".
73 * @param languages - Prefetched language names (e.g., ['TypeScript', 'React']). When provided, skips fetching languages from the knot server.
74 * @returns A JSX subtree representing the Tangled Repo record with loading states handled.
75 */
76export const TangledRepo: React.FC<TangledRepoProps> = React.memo(({
77 did,
78 rkey,
79 record,
80 renderer,
81 fallback,
82 loadingIndicator,
83 colorScheme,
84 showStarCount = true,
85 branch,
86 languages,
87}) => {
88 const { tangledBaseUrl } = useAtProto();
89 const Comp: React.ComponentType<TangledRepoRendererInjectedProps> =
90 renderer ?? ((props) => <TangledRepoRenderer {...props} />);
91 const Wrapped: React.FC<{
92 record: TangledRepoRecord;
93 loading: boolean;
94 error?: Error;
95 }> = (props) => (
96 <Comp
97 {...props}
98 colorScheme={colorScheme}
99 did={did}
100 rkey={rkey}
101 canonicalUrl={`${tangledBaseUrl}/repos/${did}/${encodeURIComponent(rkey)}`}
102 showStarCount={showStarCount}
103 branch={branch}
104 languages={languages}
105 />
106 );
107
108 if (record !== undefined) {
109 return (
110 <AtProtoRecord<TangledRepoRecord>
111 record={record}
112 renderer={Wrapped}
113 fallback={fallback}
114 loadingIndicator={loadingIndicator}
115 />
116 );
117 }
118
119 return (
120 <AtProtoRecord<TangledRepoRecord>
121 did={did}
122 collection={TANGLED_REPO_COLLECTION}
123 rkey={rkey}
124 renderer={Wrapped}
125 fallback={fallback}
126 loadingIndicator={loadingIndicator}
127 />
128 );
129});
130
131export default TangledRepo;