53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
import type { RefObject } from 'react';
|
|
import { ArrowDown } from 'lucide-react';
|
|
import type { ChatMessage } from './types';
|
|
import { MessageBubble, StreamingBubble } from './MessageBubble';
|
|
|
|
type MessageListProps = {
|
|
messages: ChatMessage[];
|
|
streamingText: string;
|
|
isGenerating: boolean;
|
|
showJumpToBottom: boolean;
|
|
onJumpToBottom: () => void;
|
|
onQuestionAnswer?: (text: string) => void;
|
|
scrollViewportRef: RefObject<HTMLDivElement | null>;
|
|
bottomRef: RefObject<HTMLDivElement | null>;
|
|
};
|
|
|
|
export const MessageList = ({
|
|
messages,
|
|
streamingText,
|
|
isGenerating,
|
|
showJumpToBottom,
|
|
onJumpToBottom,
|
|
onQuestionAnswer,
|
|
scrollViewportRef,
|
|
bottomRef,
|
|
}: MessageListProps) => (
|
|
<div className="flex-1 min-h-0 relative">
|
|
<div ref={scrollViewportRef} className="h-full overflow-y-auto">
|
|
<div className="p-4 space-y-3">
|
|
{messages.length === 0 && !isGenerating && (
|
|
<div className="flex items-center justify-center h-full min-h-[200px] text-duck-dark/30 text-sm">
|
|
Send a message to start
|
|
</div>
|
|
)}
|
|
{messages.map((msg, i) => (
|
|
<MessageBubble key={i} message={msg} onAnswer={onQuestionAnswer} />
|
|
))}
|
|
{isGenerating && <StreamingBubble text={streamingText} />}
|
|
<div ref={bottomRef} />
|
|
</div>
|
|
</div>
|
|
|
|
{showJumpToBottom && (
|
|
<button
|
|
onClick={onJumpToBottom}
|
|
className="absolute bottom-2 left-1/2 -translate-x-1/2 bg-duck-teal text-white rounded-full p-1.5 shadow-lg hover:bg-duck-teal/90 transition-colors cursor-pointer"
|
|
>
|
|
<ArrowDown className="h-4 w-4" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
);
|