'use client' import * as React from 'react' import Image from 'next/image' import Textarea from 'react-textarea-autosize' import { useAtomValue } from 'jotai' import { useEnterSubmit } from '@/lib/hooks/use-enter-submit' import { cn } from '@/lib/utils' import BrushIcon from '@/assets/images/brush.svg' import ChatIcon from '@/assets/images/chat.svg' import VisualSearchIcon from '@/assets/images/visual-search.svg' import SendIcon from '@/assets/images/send.svg' import PinIcon from '@/assets/images/pin.svg' import PinFillIcon from '@/assets/images/pin-fill.svg' import { useBing } from '@/lib/hooks/use-bing' import { voiceListenAtom } from '@/state' import Voice from './voice' import { ChatImage } from './chat-image' import { ChatAttachments } from './chat-attachments' export interface ChatPanelProps extends Pick< ReturnType, | 'generating' | 'input' | 'setInput' | 'sendMessage' | 'resetConversation' | 'isSpeaking' | 'attachmentList' | 'uploadImage' | 'setAttachmentList' > { id?: string className?: string } export function ChatPanel({ isSpeaking, generating, input, setInput, className, sendMessage, resetConversation, attachmentList, uploadImage, setAttachmentList }: ChatPanelProps) { const inputRef = React.useRef(null) const {formRef, onKeyDown} = useEnterSubmit() const [focused, setFocused] = React.useState(false) const [active, setActive] = React.useState(false) const [pin, setPin] = React.useState(false) const [tid, setTid] = React.useState() const voiceListening = useAtomValue(voiceListenAtom) const setBlur = React.useCallback(() => { clearTimeout(tid) setActive(false) const _tid = setTimeout(() => setFocused(false), 2000); setTid(_tid) }, [tid]) const setFocus = React.useCallback(() => { setFocused(true) setActive(true) clearTimeout(tid) inputRef.current?.focus() }, [tid]) React.useEffect(() => { if (input) { setFocus() } }, [input, setFocus]) return (
{ e.preventDefault() if (generating) { return; } if (!input?.trim()) { return } setInput('') setPin(false) await sendMessage(input) }} ref={formRef} >
chat