import { useEffect, useRef, useState } from "react"; import { docsApi } from "../api/endpoints"; import type { DocDetail } from "../api/types"; import { useUpgrade } from "../hooks/useUpgrade"; import { Drawer, formatDate, Loading } from "./ui"; /** Reads a post from the corpus with the exact line numbers citations point at. */ export function Reader({ documentId, highlight, onClose, }: { documentId: string; highlight?: { start: number; end: number }; onClose: () => void; }) { const [doc, setDoc] = useState(null); const [error, setError] = useState(null); const first = useRef(null); const { openUpgrade } = useUpgrade(); useEffect(() => { setDoc(null); docsApi.get(documentId).then(setDoc, () => setError("Could not open this post.")); }, [documentId]); useEffect(() => { first.current?.scrollIntoView({ block: "center" }); }, [doc, highlight]); // Skip the front matter block for display, but keep real line numbers. let bodyStart = 0; if (doc?.lines[0] === "---") { const close = doc.lines.indexOf("---", 1); bodyStart = close > 0 ? close + 1 : 0; } return ( {!doc && !error && } {error &&

{error}

} {doc && (

{doc.source_title ?? "Post"}

{formatDate(doc.published_at)} · {doc.words} words {doc.url.startsWith("http") && ( <> {" · "} Open original )}

{doc.lines.slice(bodyStart).map((line, i) => { const n = i + bodyStart + 1; const hit = highlight && n >= highlight.start && n <= highlight.end; if (!line.trim() && !hit) return
; const heading = line.match(/^(#{1,3})\s+(.*)/); return (
{n} {heading ? ( {heading[2]} ) : ( {line} )}
); })}
{doc.preview && (
This post is not indexed

Your plan indexes your latest {doc.limit ?? 5} posts. Upgrade to index this one and the rest of your archive, so you can ask about it and turn it into audio, video and Launch Kits.

)}
)}
); }