mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-21 00:49:17 +01:00
Add .oxfmtignore to skip generated bindings and wasm-pack output. Add npm format script, update DEVELOPMENT.md for Vite+ toolchain, and format all non-generated files with oxfmt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
3.0 KiB
TypeScript
114 lines
3.0 KiB
TypeScript
import type { CSSProperties } from "react";
|
|
import ReactMarkdown, { type Components } from "react-markdown";
|
|
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
import remarkGfm from "remark-gfm";
|
|
import { ErrorBoundary } from "./ErrorBoundary";
|
|
import { Prose } from "./Prose";
|
|
|
|
interface Props {
|
|
children: string | null;
|
|
className?: string;
|
|
}
|
|
|
|
export function Markdown({ children, className }: Props) {
|
|
if (children == null) return null;
|
|
|
|
return (
|
|
<Prose className={className}>
|
|
<ErrorBoundary name="Markdown">
|
|
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
|
{children}
|
|
</ReactMarkdown>
|
|
</ErrorBoundary>
|
|
</Prose>
|
|
);
|
|
}
|
|
|
|
const prismTheme = {
|
|
'pre[class*="language-"]': {
|
|
// Needs to be here, so the lib doesn't add its own
|
|
},
|
|
|
|
// Syntax tokens
|
|
comment: { color: "var(--textSubtle)" },
|
|
prolog: { color: "var(--textSubtle)" },
|
|
doctype: { color: "var(--textSubtle)" },
|
|
cdata: { color: "var(--textSubtle)" },
|
|
|
|
punctuation: { color: "var(--textSubtle)" },
|
|
|
|
property: { color: "var(--primary)" },
|
|
"attr-name": { color: "var(--primary)" },
|
|
|
|
string: { color: "var(--notice)" },
|
|
char: { color: "var(--notice)" },
|
|
|
|
number: { color: "var(--info)" },
|
|
constant: { color: "var(--info)" },
|
|
symbol: { color: "var(--info)" },
|
|
|
|
boolean: { color: "var(--warning)" },
|
|
"attr-value": { color: "var(--warning)" },
|
|
|
|
variable: { color: "var(--success)" },
|
|
|
|
tag: { color: "var(--info)" },
|
|
operator: { color: "var(--danger)" },
|
|
keyword: { color: "var(--danger)" },
|
|
function: { color: "var(--success)" },
|
|
"class-name": { color: "var(--primary)" },
|
|
builtin: { color: "var(--danger)" },
|
|
selector: { color: "var(--danger)" },
|
|
inserted: { color: "var(--success)" },
|
|
deleted: { color: "var(--danger)" },
|
|
regex: { color: "var(--warning)" },
|
|
|
|
important: { color: "var(--danger)", fontWeight: "bold" },
|
|
italic: { fontStyle: "italic" },
|
|
bold: { fontWeight: "bold" },
|
|
entity: { cursor: "help" },
|
|
};
|
|
|
|
const lineStyle: CSSProperties = {
|
|
paddingRight: "1.5em",
|
|
paddingLeft: "0",
|
|
opacity: 0.5,
|
|
};
|
|
|
|
const markdownComponents: Partial<Components> = {
|
|
// Ensure links open in external browser by adding target="_blank"
|
|
a: ({ href, children, ...rest }) => {
|
|
if (href && !href.match(/https?:\/\//)) {
|
|
href = `http://${href}`;
|
|
}
|
|
return (
|
|
<a target="_blank" rel="noreferrer noopener" href={href} {...rest}>
|
|
{children}
|
|
</a>
|
|
);
|
|
},
|
|
code(props) {
|
|
const { children, className, ref, ...extraProps } = props;
|
|
extraProps.node = undefined;
|
|
|
|
const match = /language-(\w+)/.exec(className || "");
|
|
return match ? (
|
|
<SyntaxHighlighter
|
|
{...extraProps}
|
|
CodeTag="code"
|
|
showLineNumbers
|
|
PreTag="div"
|
|
lineNumberStyle={lineStyle}
|
|
language={match[1]}
|
|
style={prismTheme}
|
|
>
|
|
{String(children as string).replace(/\n$/, "")}
|
|
</SyntaxHighlighter>
|
|
) : (
|
|
<code {...extraProps} ref={ref} className={className}>
|
|
{children}
|
|
</code>
|
|
);
|
|
},
|
|
};
|