Files
chat-proxy/moved/MessageContent.jsx
T
Samuele E. Locatelli 081576c4a1 Fix grafici output
2025-09-03 16:46:47 +00:00

72 lines
2.4 KiB
React

// MessageContent.jsx
import React, { useCallback } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkMath from 'remark-math';
import remarkGfm from 'remark-gfm';
import rehypeKatex from 'rehype-katex';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import './MessageContent.css';
export default function MessageContent({ content }) {
const handleCopy = useCallback(async (text) => {
try {
await navigator.clipboard.writeText(text);
} catch {
/* you could add a toast here if desired */
}
}, []);
return (
<ReactMarkdown
remarkPlugins={[remarkMath, remarkGfm]}
rehypePlugins={[rehypeKatex]}
components={{
table: (props) => <table className="table table-bordered table-sm" {...props} />,
thead: (props) => <thead className="table-light" {...props} />,
code({ inline, className, children, ...props }) {
const codeText = String(children).replace(/\n$/, '');
const match = /language-(\w+)/.exec(className || '');
const isMultiLine = codeText.includes('\n');
if (inline || !isMultiLine) {
// Inline or single-line — render plainly
return (
<code className={className} {...props}>
{children}
</code>
);
}
// Multi-line fenced code block → highlight + copy button
return (
<div className="position-relative md-pre-wrapper">
<SyntaxHighlighter
style={oneDark}
language={match ? match[1] : null}
PreTag="div"
customStyle={{ margin: 0, borderRadius: '0.25rem', minHeight: '5rem' }}
>
{codeText || ' '} {/* keep at least a space to hold height */}
</SyntaxHighlighter>
<button
type="button"
className="btn btn-sm btn-outline-secondary position-absolute top-0 end-0 m-1 d-flex align-items-center gap-1"
onClick={() => handleCopy(codeText)}
>
<span role="img" aria-label="Copy">
📋
</span>
Copy
</button>
</div>
);
},
}}
>
{content}
</ReactMarkdown>
);
}