backstory/frontend/src/ChatBubble.tsx
2025-04-26 16:06:51 -07:00

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
};