72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { useMemo } from 'react';
|
|
import CodeBlock from './CodeBlock';
|
|
|
|
interface MessageContentProps {
|
|
content: string;
|
|
isLoading?: boolean;
|
|
}
|
|
|
|
const MessageContent = ({ content, isLoading }: MessageContentProps) => {
|
|
const parts = useMemo(() => {
|
|
// Parse content for code blocks
|
|
const codeBlockRegex = /```(\w*)\n?([\s\S]*?)```/g;
|
|
const result: { type: 'text' | 'code'; content: string; language?: string }[] = [];
|
|
|
|
let lastIndex = 0;
|
|
let match;
|
|
|
|
while ((match = codeBlockRegex.exec(content)) !== null) {
|
|
// Add text before code block
|
|
if (match.index > lastIndex) {
|
|
const textBefore = content.slice(lastIndex, match.index);
|
|
if (textBefore.trim()) {
|
|
result.push({ type: 'text', content: textBefore });
|
|
}
|
|
}
|
|
|
|
// Add code block
|
|
result.push({
|
|
type: 'code',
|
|
language: match[1] || 'text',
|
|
content: match[2].trim(),
|
|
});
|
|
|
|
lastIndex = match.index + match[0].length;
|
|
}
|
|
|
|
// Add remaining text
|
|
if (lastIndex < content.length) {
|
|
const remaining = content.slice(lastIndex);
|
|
if (remaining.trim()) {
|
|
result.push({ type: 'text', content: remaining });
|
|
}
|
|
}
|
|
|
|
// If no code blocks found, return entire content as text
|
|
if (result.length === 0 && content) {
|
|
result.push({ type: 'text', content });
|
|
}
|
|
|
|
return result;
|
|
}, [content]);
|
|
|
|
return (
|
|
<div className="font-pixel text-sm text-primary">
|
|
{parts.map((part, index) => (
|
|
<div key={index}>
|
|
{part.type === 'code' ? (
|
|
<CodeBlock code={part.content} language={part.language || 'text'} />
|
|
) : (
|
|
<p className="whitespace-pre-wrap break-words">{part.content}</p>
|
|
)}
|
|
</div>
|
|
))}
|
|
{isLoading && content === '' && (
|
|
<span className="animate-pulse">▊</span>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MessageContent;
|