PicoBot/web/src/components/Chat/MessageList.tsx
oudecheng 624d8e8943 feat: 添加 React Web UI 前端界面
- 使用 React 18 + TypeScript + Vite + Tailwind CSS 构建前端
- 实现 WebSocket 实时通信(useWebSocket hook)
- 添加聊天界面组件(MessageList, MessageBubble, MessageInput)
- 集成 Topic 管理(新建、列出、切换)
- 支持 Markdown 渲染(react-markdown + remark-gfm)
- 添加工具调用展示面板
- 实现深色科技主题(Tech Dark)
- 后端集成静态文件服务(tower-http)
- 添加 Makefile 和 build.sh 构建脚本
- 更新 .gitignore 忽略前端构建产物

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 17:43:15 +08:00

50 lines
1.7 KiB
TypeScript

import { useEffect, useRef } from 'react'
import { MessageBubble } from './MessageBubble'
import type { ChatMessage } from '../../types/protocol'
import { Sparkles } from 'lucide-react'
interface MessageListProps {
messages: ChatMessage[]
}
export function MessageList({ messages }: MessageListProps) {
const bottomRef = useRef<HTMLDivElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (bottomRef.current) {
bottomRef.current.scrollIntoView({ behavior: 'smooth' })
}
}, [messages])
if (messages.length === 0) {
return (
<div className="flex h-full items-center justify-center">
<div className="text-center animate-fade-in">
<div className="mb-6 inline-flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-[#00f0ff]/20 to-[#3b82f6]/20 shadow-2xl shadow-[#00f0ff]/20">
<Sparkles className="h-10 w-10 text-[#00f0ff]" />
</div>
<h2 className="mb-2 text-2xl font-bold text-white"></h2>
<p className="text-zinc-500"> AI </p>
<div className="mt-8 flex items-center justify-center gap-4 text-sm text-zinc-600">
<span className="px-3 py-1 rounded-full bg-zinc-800/50 border border-zinc-700">/new </span>
<span className="px-3 py-1 rounded-full bg-zinc-800/50 border border-zinc-700">/list </span>
</div>
</div>
</div>
)
}
return (
<div
ref={containerRef}
className="h-full overflow-y-auto p-6 space-y-6"
>
{messages.map((message) => (
<MessageBubble key={message.id} message={message} />
))}
<div ref={bottomRef} />
</div>
)
}