163 lines
3.6 KiB
TypeScript
163 lines
3.6 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
import { View, Text, StyleSheet } from 'react-native';
|
||
|
|
import { AppColors } from '@/constants/theme';
|
||
|
|
import { Message } from '@/data/mockData';
|
||
|
|
|
||
|
|
interface ChatBubbleProps {
|
||
|
|
message: Message;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ChatBubble({ message }: ChatBubbleProps) {
|
||
|
|
const isAI = message.senderType === 'ai';
|
||
|
|
|
||
|
|
return (
|
||
|
|
<View style={[styles.container, isAI ? styles.aiContainer : styles.userContainer]}>
|
||
|
|
{/* Avatar */}
|
||
|
|
<View style={[styles.avatar, isAI ? styles.aiAvatar : styles.userAvatar]}>
|
||
|
|
<Text style={styles.avatarEmoji}>{isAI ? '📖' : '👤'}</Text>
|
||
|
|
</View>
|
||
|
|
|
||
|
|
{/* Bubble */}
|
||
|
|
<View style={[styles.bubble, isAI ? styles.aiBubble : styles.userBubble]}>
|
||
|
|
<Text style={[styles.text, isAI ? styles.aiText : styles.userText]}>
|
||
|
|
{message.content}
|
||
|
|
</Text>
|
||
|
|
</View>
|
||
|
|
</View>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Typing indicator component
|
||
|
|
export function TypingIndicator() {
|
||
|
|
return (
|
||
|
|
<View style={[styles.container, styles.aiContainer]}>
|
||
|
|
<View style={[styles.avatar, styles.aiAvatar]}>
|
||
|
|
<Text style={styles.avatarEmoji}>📖</Text>
|
||
|
|
</View>
|
||
|
|
<View style={[styles.bubble, styles.aiBubble]}>
|
||
|
|
<View style={styles.typingDots}>
|
||
|
|
<View style={[styles.dot, styles.dot1]} />
|
||
|
|
<View style={[styles.dot, styles.dot2]} />
|
||
|
|
<View style={[styles.dot, styles.dot3]} />
|
||
|
|
</View>
|
||
|
|
</View>
|
||
|
|
</View>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Time separator component
|
||
|
|
export function TimeSeparator({ time }: { time: string }) {
|
||
|
|
return (
|
||
|
|
<View style={styles.timeContainer}>
|
||
|
|
<View style={styles.timeBadge}>
|
||
|
|
<Text style={styles.timeText}>{time}</Text>
|
||
|
|
</View>
|
||
|
|
</View>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const styles = StyleSheet.create({
|
||
|
|
container: {
|
||
|
|
flexDirection: 'row',
|
||
|
|
marginBottom: 16,
|
||
|
|
paddingHorizontal: 14,
|
||
|
|
},
|
||
|
|
aiContainer: {
|
||
|
|
flexDirection: 'row',
|
||
|
|
},
|
||
|
|
userContainer: {
|
||
|
|
flexDirection: 'row-reverse',
|
||
|
|
},
|
||
|
|
avatar: {
|
||
|
|
width: 40,
|
||
|
|
height: 40,
|
||
|
|
borderRadius: 10,
|
||
|
|
alignItems: 'center',
|
||
|
|
justifyContent: 'center',
|
||
|
|
},
|
||
|
|
aiAvatar: {
|
||
|
|
backgroundColor: AppColors.lavender,
|
||
|
|
marginRight: 10,
|
||
|
|
},
|
||
|
|
userAvatar: {
|
||
|
|
backgroundColor: AppColors.blushPink,
|
||
|
|
marginLeft: 10,
|
||
|
|
},
|
||
|
|
avatarEmoji: {
|
||
|
|
fontSize: 18,
|
||
|
|
},
|
||
|
|
bubble: {
|
||
|
|
maxWidth: '70%',
|
||
|
|
paddingVertical: 12,
|
||
|
|
paddingHorizontal: 16,
|
||
|
|
borderRadius: 18,
|
||
|
|
},
|
||
|
|
aiBubble: {
|
||
|
|
backgroundColor: AppColors.white,
|
||
|
|
borderTopLeftRadius: 4,
|
||
|
|
shadowColor: AppColors.deepPurple,
|
||
|
|
shadowOffset: { width: 0, height: 2 },
|
||
|
|
shadowOpacity: 0.06,
|
||
|
|
shadowRadius: 8,
|
||
|
|
elevation: 2,
|
||
|
|
},
|
||
|
|
userBubble: {
|
||
|
|
backgroundColor: AppColors.mediumPurple,
|
||
|
|
borderTopRightRadius: 4,
|
||
|
|
shadowColor: AppColors.mediumPurple,
|
||
|
|
shadowOffset: { width: 0, height: 2 },
|
||
|
|
shadowOpacity: 0.3,
|
||
|
|
shadowRadius: 8,
|
||
|
|
elevation: 3,
|
||
|
|
},
|
||
|
|
text: {
|
||
|
|
fontSize: 15,
|
||
|
|
lineHeight: 22,
|
||
|
|
},
|
||
|
|
aiText: {
|
||
|
|
color: AppColors.deepPurple,
|
||
|
|
},
|
||
|
|
userText: {
|
||
|
|
color: AppColors.white,
|
||
|
|
},
|
||
|
|
// Typing indicator styles
|
||
|
|
typingDots: {
|
||
|
|
flexDirection: 'row',
|
||
|
|
alignItems: 'center',
|
||
|
|
height: 20,
|
||
|
|
paddingHorizontal: 4,
|
||
|
|
},
|
||
|
|
dot: {
|
||
|
|
width: 8,
|
||
|
|
height: 8,
|
||
|
|
borderRadius: 4,
|
||
|
|
backgroundColor: AppColors.slatePurple,
|
||
|
|
marginHorizontal: 2,
|
||
|
|
opacity: 0.5,
|
||
|
|
},
|
||
|
|
dot1: {
|
||
|
|
opacity: 1,
|
||
|
|
},
|
||
|
|
dot2: {
|
||
|
|
opacity: 0.7,
|
||
|
|
},
|
||
|
|
dot3: {
|
||
|
|
opacity: 0.4,
|
||
|
|
},
|
||
|
|
// Time separator styles
|
||
|
|
timeContainer: {
|
||
|
|
alignItems: 'center',
|
||
|
|
marginVertical: 16,
|
||
|
|
},
|
||
|
|
timeBadge: {
|
||
|
|
paddingVertical: 4,
|
||
|
|
paddingHorizontal: 12,
|
||
|
|
backgroundColor: 'rgba(140, 142, 163, 0.1)',
|
||
|
|
borderRadius: 12,
|
||
|
|
},
|
||
|
|
timeText: {
|
||
|
|
fontSize: 12,
|
||
|
|
color: AppColors.slatePurple,
|
||
|
|
},
|
||
|
|
});
|