// Animated corporate chat between colaboradores. // Reused on hero AND in section 6 (the full demo). const COLABS = [ { id: 'director', name: 'Director General', role: 'Coordina', color: '#1B3A6B', initial: 'D' }, { id: 'mkt', name: 'Marketing', role: 'Contenido', color: '#7C3AED', initial: 'M' }, { id: 'analitica',name: 'Analítica', role: 'Métricas', color: '#0EA5E9', initial: 'A' }, { id: 'soporte', name: 'Atención', role: 'Soporte', color: '#14B8A6', initial: 'S' }, { id: 'logistica',name: 'Logística', role: 'Reparto', color: '#E8620A', initial: 'L' }, { id: 'inventario',name:'Inventario', role: 'Catálogo', color: '#A16207', initial: 'I' }, ]; const COLAB_BY = Object.fromEntries(COLABS.map(c => [c.id, c])); // Script for the chat demo — designed to feel like the team is actually working const CHAT_SCRIPT = [ { who: 'mkt', text: 'Listos los 3 posts para esta semana. Adjunto imágenes generadas.', attach: 'imagen', delay: 1100 }, { who: 'analitica', text: 'El miércoles 7pm es el mejor horario según métricas de las últimas 4 semanas.', delay: 1400 }, { who: 'logistica', text: 'Coordinando entrega #142 — cliente confirmó dirección.', delay: 1300 }, { who: 'director', text: 'Recibido. Programo publicación al miércoles 7pm y envío al dueño para aprobación.', tagOwner: true, delay: 1500 }, { who: 'soporte', text: 'Tres consultas resueltas en los últimos 20 min. CSAT 4.9.', delay: 1300 }, { who: 'inventario',text: 'Detecté 2 productos sin descripción SEO. Redactando.', delay: 1300 }, ]; function Avatar({ c, size = 28 }) { return (
{c.initial}
); } function TypingDots({ color = '#94A3B8' }) { return ( {[0,1,2].map(i => ( ))} ); } function ChatMessage({ msg, isLast, typing }) { const c = COLAB_BY[msg.who]; return (
{c.name} {c.role} ahora
{msg.text} {msg.tagOwner && ( @dueño )}
{msg.attach === 'imagen' && (
{[0,1,2].map(i => (
IMG {i+1}
))}
)} {isLast && typing && (
escribiendo…
)}
); } // Full chat window (used in section 6) function ChatWindow({ compact = false, brandName = 'AI Company' }) { const printing = typeof document !== 'undefined' && document.body.classList.contains('printing'); const [visible, setVisible] = React.useState(printing ? CHAT_SCRIPT.length : 1); const [typing, setTyping] = React.useState(!printing); const scrollRef = React.useRef(null); React.useEffect(() => { if (printing) return; // no animation in print let stopped = false; let to; const step = () => { setTyping(true); to = setTimeout(() => { if (stopped) return; setTyping(false); setVisible(v => { const next = v >= CHAT_SCRIPT.length ? 1 : v + 1; return next; }); to = setTimeout(step, 450); }, CHAT_SCRIPT[visible % CHAT_SCRIPT.length]?.delay || 1200); }; step(); return () => { stopped = true; clearTimeout(to); }; }, [visible]); React.useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [visible, typing]); return (
{/* Window chrome */}
# general — {brandName}
6 en línea
{/* Messages */}
{CHAT_SCRIPT.slice(0, visible).map((m, i) => ( ))}
{/* Composer (decorative) */}
Escribe a tu equipo…
); } // Compact "activity dock" used inside hero (sleeker than full chat) function ActivityDock({ brandName = 'AI Company' }) { const items = [ { c: COLAB_BY.mkt, text: 'Redactando post para Instagram', progress: 64 }, { c: COLAB_BY.logistica, text: 'Coordinando entrega #142', progress: 88 }, { c: COLAB_BY.analitica, text: 'Optimizando campaña Meta Ads', progress: 42 }, { c: COLAB_BY.soporte, text: 'Resolviendo 3 tickets', progress: 71 }, ]; const [tick, setTick] = React.useState(0); React.useEffect(() => { const i = setInterval(() => setTick(t => t + 1), 1400); return () => clearInterval(i); }, []); return (
Equipo activo · {brandName}
en vivo
{items.map((it, i) => { const prog = Math.min(100, (it.progress + tick * 3) % 110); return (
{it.c.name} {Math.round(prog)}%
{it.text}
); })}
); } Object.assign(window, { ChatWindow, ActivityDock, Avatar, COLABS, COLAB_BY });