Files
paseo/packages/website/src/components/docs-markdown.tsx
T
Mohamed BoudraandGitHub 7e46f6a647 Rework docs navigation and move alternatives to top-level pages (#1487)
* Rework docs navigation and move alternatives to top-level pages

- Add nested docs nav with categories, collapsible groups, breadcrumbs,
  and a right-hand page outline with heading slugs.
- Move alternatives out of /docs/alternatives into /alternatives/*
  marketing pages with 301 redirects.
- Add github-slugger for heading IDs and require explicit width on
  SiteShell so new pages can't accidentally pick the narrow prose layout.
- Remove the best-practices doc from public-docs.

* Make docs content column prose-width
2026-06-12 12:53:30 +00:00

84 lines
2.2 KiB
TypeScript

import * as React from "react";
import ReactMarkdown, { type Components } from "react-markdown";
import { getDocsHighlighter, docsRehypePlugins, docsRemarkPlugins } from "~/docs-rehype";
function getCodeText(children: React.ReactNode): string {
return React.Children.toArray(children).join("");
}
function getLanguage(className: string | undefined): string | undefined {
return className?.match(/language-([^\s]+)/)?.[1];
}
function DocsPre({
children,
node: _node,
...props
}: React.ComponentProps<"pre"> & { node?: unknown }) {
const codeElement = React.Children.only(children);
const codeProps = React.isValidElement<React.ComponentProps<"code">>(codeElement)
? codeElement.props
: undefined;
const code = getCodeText(codeProps?.children);
const language = getLanguage(codeProps?.className);
const [highlightedHtml, setHighlightedHtml] = React.useState<string | null>(null);
React.useEffect(() => {
let cancelled = false;
setHighlightedHtml(null);
if (!language) return;
const lang = language;
async function highlight() {
try {
const highlighter = await getDocsHighlighter();
if (cancelled) return;
setHighlightedHtml(
highlighter.codeToHtml(code.replace(/\n$/, ""), {
lang,
theme: "catppuccin-mocha",
}),
);
} catch {
if (!cancelled) setHighlightedHtml(null);
}
}
void highlight();
return () => {
cancelled = true;
};
}, [code, language]);
const highlightedMarkup = React.useMemo(
() => (highlightedHtml ? { __html: highlightedHtml } : undefined),
[highlightedHtml],
);
if (highlightedMarkup) {
return <div dangerouslySetInnerHTML={highlightedMarkup} />;
}
return <pre {...props}>{children}</pre>;
}
const docsMarkdownComponents: Components = {
pre: DocsPre,
};
export function DocsMarkdown({ children }: { children: string }) {
return (
<div className="docs-prose">
<ReactMarkdown
remarkPlugins={docsRemarkPlugins}
rehypePlugins={docsRehypePlugins}
components={docsMarkdownComponents}
>
{children}
</ReactMarkdown>
</div>
);
}