70 lines
2.8 KiB
JavaScript
70 lines
2.8 KiB
JavaScript
import React from 'react';
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
|
export default function MessageBubble({ message }) {
|
|
const isUser = message.role === 'user';
|
|
|
|
return (
|
|
<div className="flex" style={{
|
|
justifyContent: isUser ? 'flex-end' : 'flex-start',
|
|
marginBottom: '12px',
|
|
padding: '0 16px',
|
|
}}>
|
|
{!isUser && (
|
|
<div className="flex items-center justify-center flex-shrink" style={{
|
|
width: '28px',
|
|
height: '28px',
|
|
borderRadius: '50%',
|
|
background: 'var(--accent)',
|
|
fontSize: '12px',
|
|
fontWeight: 600,
|
|
marginRight: '8px',
|
|
alignSelf: 'flex-end',
|
|
}}>N</div>
|
|
)}
|
|
|
|
<div style={{
|
|
maxWidth: '70%',
|
|
padding: '10px 14px',
|
|
borderRadius: isUser ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
|
|
background: isUser ? 'var(--bubble-user)' : 'var(--bubble-ai)',
|
|
color: 'var(--text-primary)',
|
|
fontSize: '14px',
|
|
lineHeight: '1.6',
|
|
border: isUser ? 'none' : '1px solid var(--border)',
|
|
wordBreak: 'break-word',
|
|
}}>
|
|
<ReactMarkdown
|
|
components={{
|
|
// Tighten up default spacing so it fits the bubble style
|
|
p: ({ children }) => <p style={{ margin: '0 0 8px', lineHeight: 1.6 }}>{children}</p>,
|
|
ul: ({ children }) => <ul style={{ margin: '0 0 8px', paddingLeft: '20px' }}>{children}</ul>,
|
|
ol: ({ children }) => <ol style={{ margin: '0 0 8px', paddingLeft: '20px' }}>{children}</ol>,
|
|
li: ({ children }) => <li style={{ marginBottom: '2px' }}>{children}</li>,
|
|
code: ({ inline, children }) => inline
|
|
? <code style={{ background: 'var(--bg-elevated)', padding: '1px 5px', borderRadius: 'var(--radius-sm)', fontSize: '12px', fontFamily: 'monospace' }}>{children}</code>
|
|
: <pre style={{ background: 'var(--bg-elevated)', padding: '10px 12px', borderRadius: 'var(--radius-md)', overflowX: 'auto', fontSize: '12px', fontFamily: 'monospace' }}><code>{children}</code></pre>,
|
|
strong: ({ children }) => <strong style={{ fontWeight: 600, color: 'var(--text-primary)' }}>{children}</strong>,
|
|
}}
|
|
>{message.text}</ReactMarkdown>
|
|
|
|
{message.streaming && (
|
|
<span style={{
|
|
display: 'inline-block',
|
|
width: '8px',
|
|
height: '14px',
|
|
background: 'var(--text-secondary)',
|
|
marginLeft: '2px',
|
|
borderRadius: 'var(--radius-sm)',
|
|
animation: 'blink 1s step-end infinite',
|
|
}} />
|
|
)}
|
|
{message.error && (
|
|
<div className="text-xs" style={{ marginTop: '6px', color: '#ff6b6b' }}>
|
|
⚠ Failed to complete response
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |