feat(web): 添加全局 Toast 通知系统和资产预览导航功能
- 新增 ToastProvider 和 useToast hook,支持全局成功/错误/信息提示 - 资产预览增加左右导航按钮、键盘快捷键(方向键)和计数器显示 - 资产库增加图片/视频类型筛选标签页及计数 - 对话列表增加最近对话展示、搜索优化和删除确认 - 消息增加删除确认对话框 - 优化聊天自动滚动行为,仅在用户未手动滚动时跟随新内容 - 新增删除消息 API 端点 - 优化消息历史清理逻辑,过滤错误消息和孤儿 tool 消息 - 添加自定义滚动条样式 - 优化账户参考图显示逻辑,支持本地文件显示 - 修复对话创建流程,直接导航到新创建的对话
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { renderMarkdown } from '@/lib/markdown';
|
||||
import { Bot, User, Copy, Trash2, ChevronDown, ChevronRight, RefreshCw, ArrowRight, Quote, Check, Brain } from 'lucide-react';
|
||||
import { Bot, User, Copy, Trash2, ChevronDown, ChevronRight, RefreshCw, ArrowRight, Quote, Brain } from 'lucide-react';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import type { Message } from '@/types';
|
||||
|
||||
type MessageState = 'streaming' | 'thinking' | 'done';
|
||||
@@ -26,16 +27,20 @@ function getState(msg: Message, isLast: boolean, isThinking: boolean): MessageSt
|
||||
export function ChatMessage({ message, isLast, isThinking, onRegenerate, onContinue, onQuote, onDelete }: Props) {
|
||||
const isUser = message.role === 'user';
|
||||
const isTool = message.role === 'tool';
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [reasoningOpen, setReasoningOpen] = useState(false);
|
||||
const { toast } = useToast();
|
||||
const state = getState(message, !!isLast, !!isThinking);
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
navigator.clipboard.writeText(message.content).then(() => {
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
toast('已复制到剪贴板', 'success');
|
||||
});
|
||||
}, [message.content]);
|
||||
}, [message.content, toast]);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
if (!confirm('确定删除这条消息?')) return;
|
||||
onDelete?.(message.id);
|
||||
}, [message.id, onDelete]);
|
||||
|
||||
// Tool messages
|
||||
if (isTool) {
|
||||
@@ -125,13 +130,13 @@ export function ChatMessage({ message, isLast, isThinking, onRegenerate, onConti
|
||||
<div className="flex gap-0.5 mt-1 opacity-0 group-hover/msg:opacity-100 transition-opacity px-1">
|
||||
<button onClick={handleCopy}
|
||||
className="flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors">
|
||||
{copied ? <><Check size={10} />已复制</> : <><Copy size={10} />复制</>}
|
||||
<Copy size={10} />复制
|
||||
</button>
|
||||
<button onClick={() => onQuote?.(message.content)}
|
||||
className="flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors">
|
||||
<Quote size={10} />引用
|
||||
</button>
|
||||
<button onClick={() => onDelete?.(message.id)}
|
||||
<button onClick={handleDelete}
|
||||
className="flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-red-500 hover:bg-red-50 transition-colors">
|
||||
<Trash2 size={10} />删除
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user