···
import { AtProtoProvider } from "../lib/providers/AtProtoProvider";
9
-
import { AtProtoRecord } from "../lib/core/AtProtoRecord";
import { TangledString } from "../lib/components/TangledString";
import { LeafletDocument } from "../lib/components/LeafletDocument";
import { BlueskyProfile } from "../lib/components/BlueskyProfile";
···
40
-
const customComponentSnippet = `import { useLatestRecord, useColorScheme, AtProtoRecord } from 'atproto-ui';
40
+
const prefetchedDataSnippet = `import { BlueskyPost, useLatestRecord } from 'atproto-ui';
import type { FeedPostRecord } from 'atproto-ui';
43
-
const LatestPostSummary: React.FC<{ did: string }> = ({ did }) => {
44
-
const scheme = useColorScheme('system');
45
-
const { rkey, loading, error } = useLatestRecord<FeedPostRecord>(did, 'app.bsky.feed.post');
43
+
const LatestPostWithPrefetch: React.FC<{ did: string }> = ({ did }) => {
44
+
// Fetch once with the hook
45
+
const { record, rkey, loading } = useLatestRecord<FeedPostRecord>(
47
+
'app.bsky.feed.post'
if (loading) return <span>Loading…</span>;
48
-
if (error || !rkey) return <span>No post yet.</span>;
51
+
if (!record || !rkey) return <span>No posts yet.</span>;
51
-
<AtProtoRecord<FeedPostRecord>
53
-
collection="app.bsky.feed.post"
55
-
renderer={({ record }) => (
56
-
<article data-color-scheme={scheme}>
57
-
<strong>{record?.text ?? 'Empty post'}</strong>
53
+
// Pass prefetched record—BlueskyPost won't re-fetch it
54
+
return <BlueskyPost did={did} rkey={rkey} record={record} />;
const codeBlockBase: React.CSSProperties = {
···
const basicCodeRef = useRef<HTMLElement | null>(null);
const customCodeRef = useRef<HTMLElement | null>(null);
222
-
// Latest Bluesky post
215
+
// Latest Bluesky post - fetch with record for prefetch demo
217
+
record: latestPostRecord,
loading: loadingLatestPost,
228
-
} = useLatestRecord<unknown>(did, BLUESKY_POST_COLLECTION);
222
+
} = useLatestRecord<FeedPostRecord>(did, BLUESKY_POST_COLLECTION);
const quoteSampleDid = "did:plc:ttdrpj45ibqunmfhdsb4zdwq";
const quoteSampleRkey = "3m2prlq6xxc2v";
···
<div style={columnStackStyle}>
<section style={panelStyle}>
<h3 style={sectionHeaderStyle}>
326
-
Latest Bluesky Post
320
+
Latest Post (Prefetched Data)
322
+
<p style={{ fontSize: 12, color: mutedTextColor, margin: "0 0 8px" }}>
323
+
Using <code style={{ background: scheme === "dark" ? "#1e293b" : "#e2e8f0", padding: "2px 4px", borderRadius: 3 }}>useLatestRecord</code> to fetch once, then passing <code style={{ background: scheme === "dark" ? "#1e293b" : "#e2e8f0", padding: "2px 4px", borderRadius: 3 }}>record</code> prop—no re-fetch!
···
348
-
{!loadingLatestPost && latestPostRkey && (
345
+
{!loadingLatestPost && latestPostRkey && latestPostRecord && (
349
+
record={latestPostRecord}
colorScheme={colorSchemePreference}
···
<section style={{ ...panelStyle, marginTop: 32 }}>
395
-
<h3 style={sectionHeaderStyle}>Build your own component</h3>
393
+
<h3 style={sectionHeaderStyle}>Code Examples</h3>
<p style={{ color: mutedTextColor, margin: "4px 0 8px" }}>
Wrap your app with the provider once and drop the ready-made
components wherever you need them.
···
<p style={{ color: mutedTextColor, margin: "16px 0 8px" }}>
410
-
Need to make your own component? Compose your own renderer
411
-
with the hooks and utilities that ship with the library.
408
+
Pass prefetched data to components to skip API calls—perfect for SSR or caching.
<pre style={codeBlockStyle}>
···
419
-
{customComponentSnippet}
416
+
{prefetchedDataSnippet}
427
-
flexDirection: "column",
431
-
<p style={{ color: mutedTextColor, margin: 0 }}>
432
-
Live example with your handle:
436
-
handle={showHandle}
437
-
colorScheme={colorSchemePreference}
446
-
const LatestPostSummary: React.FC<{
449
-
colorScheme: ColorSchemePreference;
450
-
}> = ({ did, colorScheme }) => {
451
-
const { record, rkey, loading, error } = useLatestRecord<FeedPostRecord>(
453
-
BLUESKY_POST_COLLECTION,
455
-
const scheme = useColorScheme(colorScheme);
458
-
? latestSummaryPalette.dark
459
-
: latestSummaryPalette.light;
461
-
if (loading) return <div style={palette.muted}>Loading summary…</div>;
463
-
return <div style={palette.error}>Failed to load the latest post.</div>;
464
-
if (!rkey) return <div style={palette.muted}>No posts published yet.</div>;
466
-
const atProtoProps = record
468
-
: { did, collection: "app.bsky.feed.post", rkey };
471
-
<AtProtoRecord<FeedPostRecord>
473
-
renderer={({ record: resolvedRecord }) => (
474
-
<article data-color-scheme={scheme}>
475
-
<strong>{resolvedRecord?.text ?? "Empty post"}</strong>
const sectionHeaderStyle: React.CSSProperties = {
···
const loadingBox: React.CSSProperties = { padding: 8 };
const errorBox: React.CSSProperties = { padding: 8, color: "crimson" };
const infoBox: React.CSSProperties = { padding: 8, color: "#555" };
490
-
const latestSummaryPalette = {
493
-
border: "1px solid #e2e8f0",
494
-
background: "#ffffff",
498
-
flexDirection: "column",
500
-
} satisfies React.CSSProperties,
503
-
alignItems: "baseline",
504
-
justifyContent: "space-between",
507
-
} satisfies React.CSSProperties,
511
-
} satisfies React.CSSProperties,
515
-
whiteSpace: "pre-wrap",
516
-
} satisfies React.CSSProperties,
521
-
textDecoration: "none",
522
-
} satisfies React.CSSProperties,
525
-
} satisfies React.CSSProperties,
528
-
} satisfies React.CSSProperties,
532
-
border: "1px solid #1e293b",
533
-
background: "#0f172a",
537
-
flexDirection: "column",
539
-
} satisfies React.CSSProperties,
542
-
alignItems: "baseline",
543
-
justifyContent: "space-between",
546
-
} satisfies React.CSSProperties,
550
-
} satisfies React.CSSProperties,
554
-
whiteSpace: "pre-wrap",
555
-
} satisfies React.CSSProperties,
560
-
textDecoration: "none",
561
-
} satisfies React.CSSProperties,
564
-
} satisfies React.CSSProperties,
567
-
} satisfies React.CSSProperties,
export const App: React.FC = () => {