import type { ReactNode, AnchorHTMLAttributes } from "react";
import { Children } from "react";
import Link from "next/link";
import Markdown from "markdown-to-jsx";
import { CopyLinkButton } from "yt-dlp-transcript-common/components/CopyLinkButton";
// The documentation renderer.
//
// WHY NOT common/components/Markdown.tsx. Three reasons, each disqualifying on
// its own: it hard-codes `target="_blank"` on EVERY anchor, so an internal
// cross-link between doc pages would open a new tab; it is tuned for chat
// density (small headings, tight rhythm), which is wrong for a document someone
// reads top to bottom; and it has no heading anchors, so a section can't be
// linked to. This borrows Changelog.tsx's anchored-heading pattern instead.
//
// A TRAP WORTH NAMING: markdown-to-jsx does NOT escape raw HTML by default
// (`disableParsingRawHTML` is off), despite the header comment on Markdown.tsx
// claiming it does. That is safe here only because these files are hand-written
// and in-repo — never render untrusted Markdown through this component.
function flattenText(children: ReactNode): string {
let out = "";
Children.forEach(children, (child) => {
if (child == null || typeof child === "boolean") return;
if (typeof child === "string" || typeof child === "number") {
out += String(child);
return;
}
if (typeof child === "object" && "props" in child) {
const props = (child as { props?: { children?: ReactNode } }).props;
if (props?.children !== undefined) out += flattenText(props.children);
}
});
return out;
}
function slugify(input: string): string {
return input
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "");
}
function anchored(
Tag: "h2" | "h3",
className: string,
): (p: { children?: ReactNode }) => ReactNode {
return function Heading({ children }) {
const anchor = slugify(flattenText(children).trim()) || null;
return (
{children}
{anchor && }
);
};
}
// A leading `# Title` is stripped by the loader, but a stray one shouldn't
// out-shout the page's own title if a file grows a second top-level heading.
function H1({ children }: { children?: ReactNode }) {
return (