fix: use Button with router.push for reliable navigation
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

- Replace Link components with Button + router.push
- Add e.preventDefault() and e.stopPropagation() to prevent event issues
- Fix file list button click handler in CanvasChatPanel
- Ensures single click navigation works consistently
This commit is contained in:
Your Name 2026-01-26 21:31:58 +08:00
parent 2566c00cb1
commit 8e82b0ea99
3 changed files with 61 additions and 23 deletions

View File

@ -516,7 +516,11 @@ export default function CanvasEditorPage({ params }: PageProps) {
{panelMode === 'chat' ? ( {panelMode === 'chat' ? (
// AI 对话内容 // AI 对话内容
<div className="flex-1 overflow-hidden"> <div className="flex-1 overflow-hidden">
<CanvasChatPanel chatId={`canvas-${id}`} onClose={() => setIsPanelOpen(false)} /> <CanvasChatPanel
chatId={`canvas-${id}`}
onClose={() => setIsPanelOpen(false)}
onOpenFileList={() => setPanelMode('fileList')}
/>
</div> </div>
) : ( ) : (
// 文件列表 // 文件列表

View File

@ -27,6 +27,7 @@ interface CanvasChatPanelProps {
chatId: string; chatId: string;
initialMessages?: ChatMessage[]; initialMessages?: ChatMessage[];
onClose?: () => void; onClose?: () => void;
onOpenFileList?: () => void;
} }
// 建议卡片数据 - 已移除 // 建议卡片数据 - 已移除
@ -55,7 +56,7 @@ function extractImageUrls(text: string): string[] {
return urls; return urls;
} }
export function CanvasChatPanel({ chatId, initialMessages = [], onClose }: CanvasChatPanelProps) { export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenFileList }: CanvasChatPanelProps) {
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [attachments, setAttachments] = useState<Attachment[]>([]); const [attachments, setAttachments] = useState<Attachment[]>([]);
const [selectedModelId, setSelectedModelId] = useState<string>(""); const [selectedModelId, setSelectedModelId] = useState<string>("");
@ -326,7 +327,13 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose }: Canva
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full hover:bg-muted"> <Button variant="ghost" size="icon" className="h-8 w-8 rounded-full hover:bg-muted">
<Share2 className="h-4 w-4" /> <Share2 className="h-4 w-4" />
</Button> </Button>
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full hover:bg-muted"> <Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-muted"
onClick={onOpenFileList}
title="已生成文件列表"
>
<LayoutGrid className="h-4 w-4" /> <LayoutGrid className="h-4 w-4" />
</Button> </Button>
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full hover:bg-muted"> <Button variant="ghost" size="icon" className="h-8 w-8 rounded-full hover:bg-muted">

View File

@ -174,13 +174,21 @@ export function TopNavbar({
)} )}
{/* AI智能精选 */} {/* AI智能精选 */}
<Link <Button
href="/featured" variant="ghost"
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors text-sm font-medium" size="sm"
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
router.push("/featured");
}}
type="button"
title="AI智能精选"
> >
<Sparkles className="h-4 w-4 text-yellow-400" /> <Sparkles className="h-4 w-4 text-yellow-400" />
<span>AI精选</span> <span className="text-sm font-medium">AI精选</span>
</Link> </Button>
{/* 精选榜单 */} {/* 精选榜单 */}
<DropdownMenu open={rankingOpen} onOpenChange={setRankingOpen}> <DropdownMenu open={rankingOpen} onOpenChange={setRankingOpen}>
@ -251,27 +259,39 @@ export function TopNavbar({
</Button> </Button>
{/* 无限画布 */} {/* 无限画布 */}
<button <Button
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors text-sm font-medium" variant="ghost"
onClick={() => { size="sm"
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
const newId = crypto.randomUUID(); const newId = crypto.randomUUID();
window.location.href = `/canvas/${newId}`; router.push(`/canvas/${newId}`);
}} }}
type="button" type="button"
title="无限画布" title="无限画布"
> >
<LayoutGrid className="h-4 w-4 text-purple-400" /> <LayoutGrid className="h-4 w-4 text-purple-400" />
<span>无限画布</span> <span className="text-sm font-medium">无限画布</span>
</button> </Button>
{/* 我的图册 */} {/* 我的图册 */}
<Link <Button
href="/gallery" variant="ghost"
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors text-sm font-medium" size="sm"
className="flex items-center gap-1 h-8 px-3 text-white hover:bg-white/15 hover:text-white rounded-full transition-colors"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
router.push("/gallery");
}}
type="button"
title="我的图册"
> >
<Images className="h-4 w-4" /> <Images className="h-4 w-4" />
<span>我的图册</span> <span className="text-sm font-medium">我的图册</span>
</Link> </Button>
{/* 分隔线 (如果有链接或图册按钮,且是管理员) */} {/* 分隔线 (如果有链接或图册按钮,且是管理员) */}
{isAdmin && ( {isAdmin && (
@ -280,13 +300,20 @@ export function TopNavbar({
{/* 系统设置(仅管理员可见)*/} {/* 系统设置(仅管理员可见)*/}
{isAdmin && ( {isAdmin && (
<Link <Button
href="/settings" variant="ghost"
className="flex items-center justify-center h-8 w-8 text-white hover:bg-white/15 hover:text-white rounded-full" size="sm"
className="h-8 w-8 p-0 text-white hover:bg-white/15 hover:text-white rounded-full"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
router.push("/settings");
}}
type="button"
title="系统设置" title="系统设置"
> >
<Settings className="h-4 w-4" /> <Settings className="h-4 w-4" />
</Link> </Button>
)} )}
</div> </div>