- src/core/math-delims.ts: pure preprocessing for the \(...\)/\[...\] math contract — balanced delimiters rewrite to the two-dollar forms remark-math parses ($ is never math). Skips code fences/spans, escaped delimiters, and leaves unbalanced (mid-stream) delimiters untouched. Display math renders as a block: mid-paragraph gets blank-line padding; indented (list items) degrades to inline so list continuations don't half-parse. - message.tsx: transform in the render path (children-memoized); math plugin now singleDollarTextMath: false — the currency hazard dies structurally. remark-breaks via the cjk remarkPluginsAfter slot (the bare remarkPlugins prop would replace the [remark-gfm, codeMeta] defaults). - mermaid: dark theme + sans font via Streamdown's mermaid prop; dark-styled error fallback (components/mermaid-error.tsx) with error, source in <details>, and retry. - globals.css (appended): @source for streamdown dist — its internal UI chrome (code blocks, mermaid containers, tables) was entirely unstyled because Tailwind v4 never scans node_modules; --color-sidebar → card; wide mermaid SVGs capped to the column; .katex-display scrolls. - tests/render-markdown.test.tsx: 26 tests (transform unit + render). The math describe block in render-cards.test.tsx is updated to the new contract ($...$ now renders as literal text — pinned).
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
import type { MermaidErrorComponentProps } from "streamdown";
|
|
|
|
/**
|
|
* Fallback for mermaid diagrams that fail to parse — wired via Streamdown's
|
|
* `mermaid.errorComponent`. Replaces the default light-themed red box with a
|
|
* card matching the app: the error, the source in a details block (so a
|
|
* broken diagram doesn't flood the transcript), and a retry.
|
|
*/
|
|
export const MermaidError = ({
|
|
chart,
|
|
error,
|
|
retry,
|
|
className,
|
|
}: MermaidErrorComponentProps & { className?: string }) => (
|
|
<div
|
|
className={cn(
|
|
"my-4 rounded-xl border border-destructive/40 bg-destructive/5 p-4",
|
|
className,
|
|
)}
|
|
data-streamdown="mermaid-error"
|
|
>
|
|
<p className="text-sm font-medium text-destructive">
|
|
Diagram failed to render
|
|
</p>
|
|
<p className="mt-1 font-mono text-xs break-words text-muted-foreground">
|
|
{error}
|
|
</p>
|
|
<details className="mt-3">
|
|
<summary className="cursor-pointer text-xs text-muted-foreground">
|
|
Show diagram source
|
|
</summary>
|
|
<pre className="mt-2 overflow-x-auto rounded-lg bg-muted p-3 font-mono text-xs text-foreground">
|
|
{chart}
|
|
</pre>
|
|
</details>
|
|
<Button className="mt-3" onClick={retry} size="sm" variant="outline">
|
|
Retry
|
|
</Button>
|
|
</div>
|
|
);
|