import React from 'react';
import CodeBlock from './CodeBlock';
const formatText = (text) => {
// ✅ Handle base64 images
const imageRegex = /\[IMAGE_START\](.*?)\[IMAGE_END\]/gs;
text = text.replace(imageRegex, (match, base64) => {
const src = `data:image/png;base64,${base64.trim()}`;
return `
`;
});
// ✅ Normalize line endings and remove excessive blank lines
text = text.replace(/\r\n|\r/g, '\n');
text = text.replace(/\n{3,}/g, '\n\n');
// ✅ Parse fenced code blocks (```code```)
text = text.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
const language = lang ? ` class="language-${lang}"` : '';
return `
${code.trim().replace(//g, '>')}
`;
});
// ✅ Parse blockquotes
text = text.replace(/^> (.*)$/gm, '$1
');
// ✅ Headings
text = text.replace(/^### (.*)$/gm, '$1
');
// ✅ Horizontal rules
text = text.replace(/^---$/gm, '
');
// ✅ Bold (**text**) and italic (*text*)
text = text.replace(/\*\*(.*?)\*\*/g, '$1');
text = text.replace(/\*(.*?)\*/g, '$1');
// ✅ Emoji rendering using colon syntax (:smile:)
const emojiMap = {
smile: "😄",
sad: "😢",
heart: "❤️",
thumbs_up: "👍",
fire: "🔥",
check: "✅",
x: "❌",
star: "⭐",
rocket: "🚀",
warning: "⚠️",
};
text = text.replace(/:([a-z0-9_+-]+):/g, (match, name) => emojiMap[name] || match);
// ✅ Unordered list (bullets)
const listify = (lines, tag) =>
`<${tag}>` +
lines.map(item => `${item.replace(/^(\-|\d+\.)\s*/, '').trim()}`).join('') +
`${tag}>`;
text = text.replace(
/((?:^[-*] .+(?:\n|$))+)/gm,
(match) => listify(match.trim().split('\n'), 'ul')
);
// ✅ Ordered list (fix separate `1.` items issue)
text = text.replace(/^(\d+\. .+)$/gm, '__ORDERED__START__$1__ORDERED__END__');
text = text.replace(
/__ORDERED__START__(\d+\. .+?)__ORDERED__END__/gs,
(_, line) => `- ${line.replace(/^\d+\.\s*/, '')}
`
);
text = text.replace(/<\/ol>\s*/g, '');
// ✅ Markdown-style tables
text = text.replace(
/^\|(.+?)\|\n\|([-:| ]+)\|\n((?:\|.*\|\n?)*)/gm,
(_, headerRow, dividerRow, bodyRows) => {
const headers = headerRow.split('|').map(h => `| ${h.trim()} | `).join('');
const rows = bodyRows.trim().split('\n').map(r =>
'' + r.split('|').map(cell => `| ${cell.trim()} | `).join('') + '
'
).join('');
return ``;
}
);
// ✅ Paragraphs and line breaks inside paragraphs
const blocks = text.split(/\n{2,}/).map(block => {
if (
block.startsWith('') ||
block.startsWith('
') ||
block.startsWith('') ||
block.startsWith('') ||
block.startsWith('') ||
block.startsWith('') ||
block.startsWith('') ||
block.startsWith('
${block.trim().replace(/\n/g, '
')}`;
}
});
return blocks.join('\n');
};
export default function MessageBubble({ role, content, time }) {
return (
);
}
function FormattedContent({ content }) {
const blocks = content.split('```');
return (
<>
{blocks.map((block, i) =>
i % 2 === 1 ? (
) : (
)
)}
>
);
}