Files
2026-08-16 14:58:47 +08:00

59 lines
4.0 KiB
TypeScript

'use client';
/**
* PBL v2 — Markdown text renderer.
*
* Thin wrapper around `streamdown` (the same markdown renderer
* OpenMAIC uses for AI-element messages) so Instructor replies,
* milestone scripts, and document content render with consistent
* typography and code formatting.
*/
import { Streamdown } from 'streamdown';
import { cn } from '@/lib/utils/cn';
interface Props {
readonly content: string;
readonly className?: string;
}
export function MarkdownText({ content, className }: Props) {
return (
<div
className={cn(
'prose prose-sm dark:prose-invert max-w-none',
'prose-p:my-2 prose-pre:my-2 prose-headings:mt-3 prose-headings:mb-1',
'prose-a:text-primary prose-strong:text-foreground prose-li:marker:text-muted-foreground',
'prose-code:before:content-none prose-code:after:content-none',
'prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:bg-white/10 prose-code:text-violet-100',
'prose-pre:bg-zinc-950 prose-pre:text-zinc-100 prose-pre:p-3 prose-pre:rounded-md',
'prose-pre:overflow-x-auto',
'[&_div[data-streamdown=code-block]]:relative [&_div[data-streamdown=code-block]]:my-2 [&_div[data-streamdown=code-block]]:gap-0',
'[&_div[data-streamdown=code-block]]:overflow-hidden [&_div[data-streamdown=code-block]]:rounded-lg [&_div[data-streamdown=code-block]]:border-border/70',
'[&_div[data-streamdown=code-block]]:bg-zinc-950 [&_div[data-streamdown=code-block]]:p-0',
'[&_div[data-streamdown=code-block-header]]:absolute [&_div[data-streamdown=code-block-header]]:left-3 [&_div[data-streamdown=code-block-header]]:top-2',
'[&_div[data-streamdown=code-block-header]]:z-10 [&_div[data-streamdown=code-block-header]]:h-auto [&_div[data-streamdown=code-block-header]]:text-[11px]',
'[&_div[data-streamdown=code-block-header]]:text-zinc-400 [&_div[data-streamdown=code-block-header]>span]:ml-0',
'[&_*:has(>div[data-streamdown=code-block-actions])]:!static [&_*:has(>div[data-streamdown=code-block-actions])]:!m-0',
'[&_*:has(>div[data-streamdown=code-block-actions])]:!h-0 [&_*:has(>div[data-streamdown=code-block-actions])]:!p-0',
'[&_div[data-streamdown=code-block-actions]]:!absolute [&_div[data-streamdown=code-block-actions]]:!bottom-1.5 [&_div[data-streamdown=code-block-actions]]:!right-1.5',
'[&_div[data-streamdown=code-block-actions]]:!rounded-md [&_div[data-streamdown=code-block-actions]]:!border-white/10 [&_div[data-streamdown=code-block-actions]]:!bg-zinc-900/85 [&_div[data-streamdown=code-block-actions]]:!text-zinc-300',
'[&_div[data-streamdown=code-block-body]]:!min-h-[76px] [&_div[data-streamdown=code-block-body]]:!rounded-none [&_div[data-streamdown=code-block-body]]:!border-0',
'[&_div[data-streamdown=code-block-body]]:!bg-transparent [&_div[data-streamdown=code-block-body]]:!px-3 [&_div[data-streamdown=code-block-body]]:!pb-10 [&_div[data-streamdown=code-block-body]]:!pt-8',
'[&_div[data-streamdown=code-block-body]]:!text-[13px] [&_div[data-streamdown=code-block-body]]:!text-zinc-100',
// streamdown ships the code body as `overflow-hidden`, so a long line is
// clipped on the right with no way to reach it. Make the body (and its
// <pre>) scroll horizontally instead; keep the vertical axis clipped so
// the box height is unchanged. The absolutely-positioned header / copy
// button anchor to the outer code-block, so they stay put while scrolling.
'[&_div[data-streamdown=code-block-body]]:!overflow-x-auto [&_div[data-streamdown=code-block-body]]:!overflow-y-hidden',
'[&_div[data-streamdown=code-block-body]>pre]:!m-0 [&_div[data-streamdown=code-block-body]>pre]:!overflow-x-auto [&_div[data-streamdown=code-block-body]>pre]:!bg-transparent [&_div[data-streamdown=code-block-body]>pre]:!text-zinc-100',
'[&_div[data-streamdown=code-block-body]_code]:!text-zinc-100 [&_div[data-streamdown=code-block-body]_span]:!text-zinc-100',
className,
)}
>
<Streamdown>{content}</Streamdown>
</div>
);
}