156 lines
5.3 KiB
TypeScript
156 lines
5.3 KiB
TypeScript
import React from 'react';
|
|
import { Box } from '@mui/material';
|
|
import { useTheme } from '@mui/material/styles';
|
|
import { SxProps, Theme } from '@mui/material';
|
|
import Accordion from '@mui/material/Accordion';
|
|
import AccordionSummary from '@mui/material/AccordionSummary';
|
|
import AccordionDetails from '@mui/material/AccordionDetails';
|
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
|
|
import { MessageRoles } from './Message';
|
|
|
|
interface ChatBubbleProps {
|
|
role: MessageRoles,
|
|
isInfo?: boolean;
|
|
isFullWidth?: boolean;
|
|
children: React.ReactNode;
|
|
sx?: SxProps<Theme>;
|
|
className?: string;
|
|
title?: string;
|
|
}
|
|
|
|
function ChatBubble(props: ChatBubbleProps) {
|
|
const { role, isFullWidth, children, sx, className, title } = props;
|
|
const theme = useTheme();
|
|
|
|
const defaultRadius = '16px';
|
|
const defaultStyle = {
|
|
padding: theme.spacing(1, 2),
|
|
fontSize: '0.875rem',
|
|
alignSelf: 'flex-start', // Left-aligned is used by default
|
|
maxWidth: '100%',
|
|
minWidth: '80%',
|
|
'& > *': {
|
|
color: 'inherit', // Children inherit 'color' from parent
|
|
overflow: 'hidden',
|
|
m: 0,
|
|
},
|
|
'& > :last-child': {
|
|
mb: 0,
|
|
m: 0,
|
|
p: 0,
|
|
}
|
|
}
|
|
|
|
const styles = {
|
|
'user': {
|
|
...defaultStyle,
|
|
backgroundColor: theme.palette.background.default, // Warm Gray (#D3CDBF)
|
|
border: `1px solid ${theme.palette.custom.highlight}`, // Golden Ochre (#D4A017)
|
|
borderRadius: `${defaultRadius} ${defaultRadius} 0 ${defaultRadius}`, // Rounded, flat bottom-right for user
|
|
alignSelf: 'flex-end', // Right-aligned for user
|
|
color: theme.palette.primary.main, // Midnight Blue (#1A2536) for text
|
|
},
|
|
'assistant': {
|
|
...defaultStyle,
|
|
backgroundColor: theme.palette.primary.main, // Midnight Blue (#1A2536)
|
|
border: `1px solid ${theme.palette.secondary.main}`, // Dusty Teal (#4A7A7D)
|
|
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`, // Rounded, flat bottom-left for assistant
|
|
color: theme.palette.primary.contrastText, // Warm Gray (#D3CDBF) for text
|
|
},
|
|
'system': {
|
|
...defaultStyle,
|
|
backgroundColor: '#EDEAE0', // Soft warm gray that plays nice with #D3CDBF
|
|
border: `1px dashed ${theme.palette.custom.highlight}`, // Golden Ochre
|
|
borderRadius: defaultRadius,
|
|
maxWidth: isFullWidth ? '100%' : '90%',
|
|
alignSelf: 'center',
|
|
color: theme.palette.text.primary, // Charcoal Black
|
|
fontStyle: 'italic',
|
|
},
|
|
'info': {
|
|
...defaultStyle,
|
|
backgroundColor: '#BFD8D8', // Softened Dusty Teal
|
|
border: `1px solid ${theme.palette.secondary.main}`, // Dusty Teal
|
|
borderRadius: defaultRadius,
|
|
color: theme.palette.text.primary, // Charcoal Black (#2E2E2E) — much better contrast
|
|
opacity: 0.95,
|
|
},
|
|
'status': {
|
|
...defaultStyle,
|
|
backgroundColor: 'rgba(74, 122, 125, 0.15)', // Translucent dusty teal
|
|
border: `1px solid ${theme.palette.secondary.light}`, // Lighter dusty teal
|
|
borderRadius: '4px',
|
|
maxWidth: isFullWidth ? '100%' : '75%',
|
|
alignSelf: 'center',
|
|
color: theme.palette.secondary.dark, // Darker dusty teal for text
|
|
fontWeight: 500, // Slightly bolder than normal
|
|
fontSize: '0.95rem', // Slightly smaller
|
|
padding: '8px 12px',
|
|
opacity: 0.9,
|
|
transition: 'opacity 0.3s ease-in-out', // Smooth fade effect for appearing/disappearing
|
|
},
|
|
'error': {
|
|
...defaultStyle,
|
|
backgroundColor: '#F8E7E7', // Soft light red background
|
|
border: `1px solid #D83A3A`, // Prominent red border
|
|
borderRadius: defaultRadius,
|
|
maxWidth: isFullWidth ? '100%' : '90%',
|
|
alignSelf: 'center',
|
|
color: '#8B2525', // Deep red text for good contrast
|
|
padding: '10px 16px',
|
|
boxShadow: '0 1px 3px rgba(216, 58, 58, 0.15)', // Subtle shadow with red tint
|
|
},
|
|
'content': {
|
|
...defaultStyle,
|
|
backgroundColor: '#F5F2EA', // Light cream background for easy reading
|
|
border: `1px solid ${theme.palette.custom.highlight}`, // Golden Ochre border
|
|
borderRadius: 0,
|
|
maxWidth: '100%', // Full width to maximize reading space
|
|
alignSelf: 'center', // Centered in the chat
|
|
color: theme.palette.text.primary, // Charcoal Black for maximum readability
|
|
padding: '8px 8px', // More generous padding for better text framing
|
|
marginBottom: '0px', // Space between content and conversation
|
|
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.05)', // Subtle elevation
|
|
fontSize: '0.9rem', // Slightly smaller than default
|
|
lineHeight: '1.3', // More compact line height
|
|
fontFamily: theme.typography.fontFamily, // Consistent font with your theme
|
|
},
|
|
};
|
|
|
|
if (role === 'content' && title) {
|
|
return (
|
|
<Accordion
|
|
defaultExpanded
|
|
className={className}
|
|
sx={{ ...styles[role], ...sx }}
|
|
>
|
|
<AccordionSummary
|
|
expandIcon={<ExpandMoreIcon />}
|
|
slotProps={{ content: { sx: { fontWeight: 'bold', fontSize: '1.1rem', m: 0, p: 0, display: 'flex', justifyItems: 'center' } } }}
|
|
>
|
|
{title}
|
|
</AccordionSummary>
|
|
<AccordionDetails sx={{ mt: 0, mb: 0, p: 0, pl: 2, pr: 2 }}>
|
|
{children}
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Box className={className} sx={{ ...styles[role], ...sx }}>
|
|
{children}
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
export type {
|
|
ChatBubbleProps
|
|
};
|
|
|
|
export {
|
|
ChatBubble
|
|
};
|
|
|