mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-09-21 21:03:38 +08:00
feat: build an AI agent from 0 to 1 -- 11 progressive sessions
- 11 sessions from basic agent loop to autonomous teams - Python MVP implementations for each session - Mental-model-first docs in en/zh/ja - Interactive web platform with step-through visualizations - Incremental architecture: each session adds one mechanism
This commit is contained in:
91
web/src/components/docs/doc-renderer.tsx
Normal file
91
web/src/components/docs/doc-renderer.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import { useLocale } from "@/lib/i18n";
|
||||
import docsData from "@/data/generated/docs.json";
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkRehype from "remark-rehype";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import rehypeHighlight from "rehype-highlight";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
|
||||
interface DocRendererProps {
|
||||
version: string;
|
||||
}
|
||||
|
||||
function renderMarkdown(md: string): string {
|
||||
const result = unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkRehype, { allowDangerousHtml: true })
|
||||
.use(rehypeRaw)
|
||||
.use(rehypeHighlight, { detect: false, ignoreMissing: true })
|
||||
.use(rehypeStringify)
|
||||
.processSync(md);
|
||||
return String(result);
|
||||
}
|
||||
|
||||
function postProcessHtml(html: string): string {
|
||||
// Add language labels to highlighted code blocks
|
||||
html = html.replace(
|
||||
/<pre><code class="hljs language-(\w+)">/g,
|
||||
'<pre class="code-block" data-language="$1"><code class="hljs language-$1">'
|
||||
);
|
||||
|
||||
// Wrap plain pre>code (ASCII art / diagrams) in diagram container
|
||||
html = html.replace(
|
||||
/<pre><code(?! class="hljs)([^>]*)>/g,
|
||||
'<pre class="ascii-diagram"><code$1>'
|
||||
);
|
||||
|
||||
// Mark the first blockquote as hero callout
|
||||
html = html.replace(
|
||||
/<blockquote>/,
|
||||
'<blockquote class="hero-callout">'
|
||||
);
|
||||
|
||||
// Remove the h1 (it's redundant with the page header)
|
||||
html = html.replace(/<h1>.*?<\/h1>\n?/, "");
|
||||
|
||||
// Fix ordered list counter for interrupted lists (ol start="N")
|
||||
html = html.replace(
|
||||
/<ol start="(\d+)">/g,
|
||||
(_, start) => `<ol style="counter-reset:step-counter ${parseInt(start) - 1}">`
|
||||
);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
export function DocRenderer({ version }: DocRendererProps) {
|
||||
const locale = useLocale();
|
||||
|
||||
const doc = useMemo(() => {
|
||||
const match = docsData.find(
|
||||
(d: { version: string; locale: string }) =>
|
||||
d.version === version && d.locale === locale
|
||||
);
|
||||
if (match) return match;
|
||||
return docsData.find(
|
||||
(d: { version: string; locale: string }) =>
|
||||
d.version === version && d.locale === "en"
|
||||
);
|
||||
}, [version, locale]);
|
||||
|
||||
if (!doc) return null;
|
||||
|
||||
const html = useMemo(() => {
|
||||
const raw = renderMarkdown(doc.content);
|
||||
return postProcessHtml(raw);
|
||||
}, [doc.content]);
|
||||
|
||||
return (
|
||||
<div className="py-4">
|
||||
<div
|
||||
className="prose-custom"
|
||||
dangerouslySetInnerHTML={{ __html: html }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user