gatepass / src /components /Markdown.tsx
rb125
Initial frontend deploy
4c62137
Raw
History Blame Contribute Delete
3.45 kB
"use client";
import ReactMarkdown from "react-markdown";
export function Markdown({ children }: { children: string }) {
// Fix markdown tables that arrive as a single line (common with LLM output)
// "| col | col | | :--- |" → split rows at "| |" boundary
const processed = children.replace(/\| \|/g, '|\n|');
return (
<div className="prose-custom">
<ReactMarkdown
components={{
table: ({ children }) => (
<table className="gp-table">{children}</table>
),
thead: ({ children }) => (
<thead>{children}</thead>
),
tbody: ({ children }) => (
<tbody>{children}</tbody>
),
tr: ({ children }) => (
<tr>{children}</tr>
),
th: ({ children }) => (
<th>{children}</th>
),
td: ({ children }) => (
<td>{children}</td>
),
}}
>
{processed}
</ReactMarkdown>
<style jsx global>{`
.prose-custom { font-size: 13px; line-height: 1.7; color: var(--text); font-family: "Google Sans", "Inter", sans-serif; }
.prose-custom h1, .prose-custom h2, .prose-custom h3 { color: var(--text); font-weight: 700; margin-top: 1.5em; margin-bottom: 0.5em; }
.prose-custom h1 { font-size: 1.25em; border-bottom: 2px solid var(--accent); padding-bottom: 4px; }
.prose-custom h2 { font-size: 1.1em; border-bottom: 1px solid var(--border); padding-bottom: 2px; }
.prose-custom h3 { font-size: 1em; }
.prose-custom p { margin-bottom: 1em; opacity: 0.9; }
.prose-custom ul, .prose-custom ol { padding-left: 1.5em; margin-bottom: 1em; }
.prose-custom li { margin-bottom: 0.5em; }
.prose-custom li::marker { color: var(--accent); }
.prose-custom code { background: rgba(66, 133, 244, 0.1); padding: 1px 4px; border: 1px solid var(--border); border-radius: 3px; font-size: 0.95em; color: var(--text); font-family: "JetBrains Mono", monospace; }
.prose-custom pre { background: rgba(0,0,0,0.3); padding: 16px; border: 1px solid var(--border); border-radius: 8px; overflow-x: auto; margin-bottom: 1em; }
.prose-custom pre code { background: none; padding: 0; border: none; }
.prose-custom strong { color: var(--text); font-weight: 700; }
.prose-custom blockquote { border-left: 3px solid var(--accent); padding-left: 16px; color: var(--text-dim); margin: 1.5em 0; padding-top: 8px; padding-bottom: 8px; font-style: italic; }
.prose-custom a { color: var(--accent); text-decoration: underline; }
.prose-custom a:hover { color: #fff; }
/* Table styles */
.gp-table { width: 100%; border-collapse: collapse; margin: 1.5em 0; font-size: 12px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
.gp-table thead { background: rgba(138, 180, 248, 0.08); }
.gp-table th { text-align: left; padding: 10px 14px; font-weight: 500; color: var(--accent); border-bottom: 1px solid var(--border); font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; }
.gp-table td { padding: 10px 14px; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: top; }
.gp-table tbody tr:hover { background: rgba(255, 255, 255, 0.04); }
.gp-table tbody tr:last-child td { border-bottom: none; }
`}</style>
</div>
);
}