Scrum4Me/app/(app)/manual/_components/markdown-view.tsx
Madhura68 797c7d32b0 feat(PBI-58): /manual route renders developer manual chapters in-app
Catch-all route at app/(app)/manual/[[...slug]]/page.tsx with
generateStaticParams covering every TOC entry. Server-side
MarkdownView uses react-markdown with remark-gfm, rehype-slug, and
rehype-autolink-headings; mermaid code blocks are routed to a
client-only MermaidBlock that dynamic-imports mermaid on mount.

ManualSidebar (client) reads the typed TOC and highlights the active
chapter via usePathname.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:43:47 +02:00

42 lines
1.4 KiB
TypeScript

import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import { MermaidBlock } from './mermaid-block'
type Props = {
markdown: string
}
export function MarkdownView({ markdown }: Props) {
return (
<article className="prose prose-neutral max-w-none dark:prose-invert prose-headings:scroll-mt-20 prose-a:text-primary prose-code:rounded prose-code:bg-muted prose-code:px-1 prose-code:py-0.5 prose-code:text-sm prose-pre:bg-muted prose-pre:text-foreground">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[
rehypeSlug,
[rehypeAutolinkHeadings, { behavior: 'wrap' }],
]}
components={{
code(props) {
const { className, children } = props as {
className?: string
children?: React.ReactNode
}
const match = /language-(\w+)/.exec(className ?? '')
const lang = match?.[1]
const text = String(children ?? '').replace(/\n$/, '')
if (lang === 'mermaid') {
return <MermaidBlock source={text} />
}
return (
<code className={className}>{children}</code>
)
},
}}
>
{markdown}
</ReactMarkdown>
</article>
)
}