import { useEffect, useRef, useState } from 'react'; import { MessageSquare, Trash2, X } from 'lucide-react'; import { useChat } from '../../state/chat'; import { useSettings } from '../../state/settings'; import { MessageBubble } from './MessageBubble'; import { CommandBar } from './CommandBar'; interface Props { compact?: boolean; } export function ChatPanel({ compact }: Props) { const messages = useChat((s) => s.messages); const clear = useChat((s) => s.clear); const assistantName = useSettings((s) => s.settings.assistantName); const userName = useSettings((s) => s.settings.userName); const showReasoning = useSettings((s) => s.settings.ui.showReasoning); const listRef = useRef(null); const programmatic = useRef(false); const [zoom, setZoom] = useState(null); const [stick, setStick] = useState(true); useEffect(() => { if (!stick) return; const el = listRef.current; if (!el) return; programmatic.current = true; el.scrollTop = el.scrollHeight; }, [messages, stick]); useEffect(() => { if (!zoom) return; const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setZoom(null); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [zoom]); const onScroll = () => { if (programmatic.current) { programmatic.current = false; return; } const el = listRef.current; if (!el) return; setStick(el.scrollHeight - el.scrollTop - el.clientHeight < 80); }; const visible = compact ? messages.slice(-6) : messages; return (
{!compact && (
Transmission {messages.length} msg
)}
{visible.length === 0 && (
{compact ? 'En attente…' : `Canal ouvert. Parlez ou écrivez à ${assistantName}.`} {!compact && (
Ctrl + Shift + Espace active le micro depuis n’importe où.
)}
)} {visible.map((m) => ( ))}
{zoom && (
setZoom(null)}> aperçu
)}
); }