Spaces:
Sleeping
Sleeping
File size: 5,549 Bytes
13a0af9 182e8e9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
import { useState } from 'react';
import { motion } from 'motion/react';
import { Bot, User, Crown, Sparkles, MessageSquare } from 'lucide-react';
import { Button } from './ui/button';
import { FeedbackPopup } from './FeedbackPopup';
export interface MessageProps {
content: string;
isUser: boolean;
timestamp: Date;
isPlusResponse?: boolean;
isUnivAiPlusMode?: boolean;
}
export function Message({ content, isUser, timestamp, isPlusResponse, isUnivAiPlusMode }: MessageProps) {
const [showFeedback, setShowFeedback] = useState(false);
return (
<>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className={`flex items-start gap-3 mb-4 ${isUser ? 'flex-row-reverse' : 'flex-row'}`}
>
<div className={`
flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center relative transition-all duration-300
${isUser
? isUnivAiPlusMode
? 'bg-gradient-to-r from-purple-500 to-purple-600 text-white shadow-lg shadow-purple-500/30'
: 'bg-gradient-to-r from-red-500 to-red-600 text-white shadow-lg shadow-red-500/30'
: isPlusResponse
? 'bg-gradient-to-r from-purple-400 to-pink-500 text-white shadow-lg shadow-purple-500/30'
: isUnivAiPlusMode
? 'bg-gradient-to-r from-purple-400 to-pink-500 text-white shadow-lg shadow-purple-500/30'
: 'bg-gradient-to-r from-yellow-400 to-orange-500 text-white shadow-lg shadow-yellow-500/30'
}
`}>
{isUser ? (
<User size={20} />
) : isPlusResponse ? (
<Crown size={20} />
) : isUnivAiPlusMode ? (
<Crown size={20} />
) : (
<Bot size={20} />
)}
{/* Premium indicator sparkle */}
{isPlusResponse && (
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="absolute -top-1 -right-1 w-4 h-4 bg-gradient-to-r from-amber-400 to-yellow-500 rounded-full flex items-center justify-center"
>
<Sparkles size={10} className="text-white" />
</motion.div>
)}
</div>
<div className={`flex flex-col max-w-[70%] ${isUser ? 'items-end' : 'items-start'}`}>
{/* Premium response indicator - moved outside and above the message bubble */}
{isPlusResponse && (
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
className="flex items-center gap-1 px-3 py-1 mb-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white text-xs rounded-full shadow-lg mr-4"
>
<Crown size={12} />
<span>Premium Response</span>
</motion.div>
)}
<div className={`
px-4 py-3 rounded-2xl backdrop-blur-sm border shadow-sm transition-all duration-300 relative
${isUser
? isUnivAiPlusMode
? 'bg-gradient-to-r from-purple-50 to-purple-100 border-purple-200 text-purple-900 ml-4'
: 'bg-gradient-to-r from-red-50 to-red-100 border-red-200 text-red-900 ml-4'
: isPlusResponse
? 'bg-gradient-to-r from-purple-50 via-pink-50 to-amber-50 border-purple-300 text-purple-900 mr-4 shadow-lg shadow-purple-200/50'
: isUnivAiPlusMode
? 'bg-gradient-to-r from-white to-purple-50 border-purple-200 text-purple-900 mr-4'
: 'bg-gradient-to-r from-white to-yellow-50 border-yellow-200 text-red-900 mr-4'
}
`}>
<p className="whitespace-pre-wrap">
{content}
</p>
</div>
<div className={`flex items-center gap-2 mt-1 px-2 ${isUser ? 'flex-row-reverse' : 'flex-row'}`}>
<span className={`text-xs transition-all duration-300 ${
isUnivAiPlusMode
? 'text-purple-600/60'
: 'text-red-600/60'
}`}>
{timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
{isPlusResponse && <span className="ml-2 text-purple-600/80">• Premium</span>}
</span>
{/* Feedback button for bot responses */}
{!isUser && (
<Button
variant="ghost"
size="sm"
onClick={() => setShowFeedback(true)}
className={`text-xs p-1 h-6 transition-all duration-300 opacity-60 hover:opacity-100 ${
isUnivAiPlusMode
? 'hover:bg-purple-100 text-purple-600 dark:hover:bg-purple-900/30 dark:text-purple-400'
: 'hover:bg-red-100 text-red-600 dark:hover:bg-red-900/30 dark:text-red-400'
}`}
>
<MessageSquare size={12} />
</Button>
)}
</div>
</div>
</motion.div>
{/* Feedback Popup */}
<FeedbackPopup
isOpen={showFeedback}
onClose={() => setShowFeedback(false)}
messageId={`msg-${timestamp.getTime()}`}
isUnivAiPlusMode={isUnivAiPlusMode}
/>
</>
);
} |