← Components/Communication

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: fals
VideoCallUI
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(fa
EmailComposer
Communication