ChatBubble
chatbubble-1779388706190.tsx
'use client';
import { useState } from 'react';
export default function ChatBubble() {
const [messages, setMessages] = useState([
{ id: 1, text: 'Hey! The new design looks amazing š„', self: false, time: '09:41', reactions: { 'š': 2, 'š„': 1 } },
{ id: 2, text: 'Thanks! I worked on the dark mode especially', self: true, time: '09:42', reactions: {} },
{ id: 3, text: 'The gold accent color was a great choice', self: false, time: '09:43', reactions: { 'ā¤ļø': 3 } },
{ id: 4, text: 'Agreed! It gives it a premium feel without being flashy', self: true, time: '09:44', reactions: {} },
]);
const [input, setInput] = useState('');
const [hoveredMsg, setHoveredMsg] = useState(null);
const addReaction = (msgId, emoji) => {
setMessages(prev => prev.map(m => {
if (m.id !== msgId) return m;
const reactions = { ...m.reactions };
reactions[emoji] = (reactions[emoji] || 0) + 1;
return { ...m, reactions };
}));
};
const send = () => {
if (!input.trim()) return;
setMessages(prev => [...prev, { id: Date.now(), text: input, self: true, time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), reactions: {} }]);
setInput('');
};
const emojis = ['š', 'ā¤ļø', 'š„', 'š', 'š®'];
return (
<div style={{ fontFamily: 'system-ui, sans-serif', width: '360px', background: '#0f0f0f', border: '1px solid rgba(255,255,255,0.08)', borderRadius: '16px', overflow: 'hidden' }}>
<div style={{ padding: '14px 16px', borderBottom: '1px solid rgba(255,255,255,0.07)', display: 'flex', alignItems: 'center', gap: '10px' }}>
<div style={{ width: '32px', height: '32px', borderRadius: '50%', background: 'linear-gradient(135deg, #C9A84C, #6366f1)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '14px', fontWeight: 700, color: '#fff' }}>A</div>
<div>
<p style={{ margin: 0, color: '#F5F5F0', fontSize: '14px', fontWeight: 600 }}>Alex</p>
<p style={{ margin: 0, color: '#4ade80', fontSize: '11px' }}>ā Online</p>
</div>
</div>
<div style={{ padding: '16px', height: '280px', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: '12px' }}>
{messages.map(msg => (
<div key={msg.id} style={{ display: 'flex', flexDirection: 'column', alignItems: msg.self ? 'flex-end' : 'flex-start' }}
onMouseEnter={() => setHoveredMsg(msg.id)}
onMouseLeave={() => setHoveredMsg(null)}
>
<div style={{ position: 'relative' }}>
<div style={{
background: msg.self ? 'linear-gradient(135deg, #C9A84C, #b8922e)' : 'rgba(255,255,255,0.06)',
color: msg.self ? '#0A0A0A' : '#F5F5F0',
borderRadius: msg.self ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
padding: '10px 14px', fontSize: '13px', maxWidth: '220px', lineHeight: 1.5,
}}>{msg.text}</div>
{hoveredMsg === msg.id && (
<div style={{
position: 'absolute', [msg.self ? 'left' : 'right']: '100%', top: 0,
marginLeft: msg.self ? 0 : '8px', marginRight: msg.self ? '8px' : 0,
background: '#1e1e1e', border: '1px solid rgba(255,255,255,0.1)',
borderRadius: '12px', padding: '6px 8px',
display: 'flex', gap: '6px',
}}>
{emojis.map(e => (
<span key={e} onClick={() => addReaction(msg.id, e)} style={{ cursor: 'pointer', fontSize: '16px', transition: 'transform 0.1s' }}
onMouseEnter={el => el.currentTarget.style.transform = 'scale(1.3)'}
onMouseLeave={el => el.currentTarget.style.transform = 'scale(1)'}
>{e}</span>
))}
</div>
)}
</div>
{Object.keys(msg.reactions).length > 0 && (
<div style={{ display: 'flex', gap: '4px', marginTop: '4px' }}>
{Object.entries(msg.reactions).map(([e, count]) => (
<span key={e} style={{ background: 'rgba(255,255,255,0.07)', borderRadius: '10px', padding: '2px 6px', fontSize: '11px', color: 'rgba(245,245,240,0.7)' }}>{e} {count}</span>
))}
</div>
)}
<span style={{ color: 'rgba(245,245,240,0.25)', fontSize: '10px', marginTop: '4px' }}>{msg.time}</span>
</div>
))}
</div>
<div style={{ padding: '12px 16px', borderTop: '1px solid rgba(255,255,255,0.07)', display: 'flex', gap: '10px', alignItems: 'center' }}>
<input value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()}
placeholder="Type a message..." style={{
flex: 1, background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)',
borderRadius: '20px', padding: '9px 16px', color: '#F5F5F0', fontSize: '13px', outline: 'none', fontFamily: 'system-ui',
}} />
<button onClick={send} style={{ background: 'linear-gradient(135deg, #C9A84C, #e8c96d)', border: 'none', borderRadius: '50%', width: '36px', height: '36px', cursor: 'pointer', fontSize: '16px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>ā¤</button>
</div>
</div>
);
}Component info
CategoryCommunication
Frameworkreact
TierFREE
Views0
Copies0
About
Chat conversation bubbles with reactions
More from Communication
'use client'
import { useState } from 'react'
const PARTICIPANTS = [
{ id: 1, name: 'You', initials: 'ME', color: '#C9A84C', muted: false, camera: true, speaking: true },
{ id: 2, name: 'Sarah Chen', initials: 'SC', color: '#6366f1', muted: falsVideoCallUI
Communication
'use client';
import { useState, useEffect } from 'react';
export default function TypingIndicator({ users = ["Alice", "Bob"] }) {
const [visible, setVisible] = useState(true);
const [dot, setDot] = useState(0);
useEffect(() => {
const d TypingIndicator
Communication
'use client';
import { useState } from 'react';
export default function EmailComposer() {
const [to, setTo] = useState('');
const [subject, setSubject] = useState('');
const [body, setBody] = useState('');
const [sent, setSent] = useState(faEmailComposer
Communication