import { useEffect, useRef, useState } from "react"; import { BookOpen, Bot, Download, Home, Images, Menu, PanelLeftClose, PanelLeftOpen, Plus, Redo2, Trash2, Undo2, Upload } from "lucide-react"; import { Button, Dropdown, Modal, Tooltip } from "antd"; import { UserStatusActions } from "@/components/layout/user-status-actions"; import { canvasThemes } from "@/lib/canvas-theme"; import { useCanvasSidePanelStore } from "@/stores/use-canvas-side-panel-store"; import { useThemeStore } from "@/stores/use-theme-store"; import { DOCS_URL } from "@/constant/env"; export function CanvasTopBar({ title, titleDraft, isTitleEditing, onTitleDraftChange, onStartTitleEditing, onFinishTitleEditing, onCancelTitleEditing, canUndo, canRedo, onHome, onProjects, onCreateProject, onDeleteProject, onExportProject, onImportImage, onOpenPlugins, onUndo, onRedo, agentOpen, compactAgentStatus, onToggleAgent, }: { title: string; titleDraft: string; isTitleEditing: boolean; onTitleDraftChange: (value: string) => void; onStartTitleEditing: () => void; onFinishTitleEditing: () => void; onCancelTitleEditing: () => void; canUndo: boolean; canRedo: boolean; onHome: () => void; onProjects: () => void; onCreateProject: () => void; onDeleteProject: () => void; onExportProject: () => void; onImportImage: () => void; onOpenPlugins: () => void; onUndo: () => void; onRedo: () => void; agentOpen: boolean; compactAgentStatus: { connected: boolean; enabled: boolean; activity: string }; onToggleAgent: () => void; }) { const colorTheme = useThemeStore((state) => state.theme); const theme = canvasThemes[colorTheme]; const titleRef = useRef(null); const [shortcutsOpen, setShortcutsOpen] = useState(false); const sidePanelOpen = useCanvasSidePanelStore((state) => state.panelOpen); const toggleSidePanel = useCanvasSidePanelStore((state) => state.togglePanel); useEffect(() => { if (!isTitleEditing) return; const close = (event: PointerEvent) => { if (!titleRef.current?.contains(event.target as Node)) onFinishTitleEditing(); }; document.addEventListener("pointerdown", close, true); return () => document.removeEventListener("pointerdown", close, true); }, [isTitleEditing, onFinishTitleEditing]); return ( <>
, label: "主页", onClick: onHome }, { key: "docs", icon: , label: "文档", onClick: () => window.open(DOCS_URL, "_blank", "noopener,noreferrer") }, { key: "projects", icon: , label: "我的画布", onClick: onProjects }, { type: "divider" }, { key: "new", icon: , label: "新建画布", onClick: onCreateProject }, { key: "delete", danger: true, icon: , label: "删除当前画布", onClick: onDeleteProject }, { type: "divider" }, { key: "import", icon: , label: "导入资产", onClick: onImportImage }, { key: "export", icon: , label: "导出当前画布", onClick: onExportProject }, { type: "divider" }, { key: "undo", disabled: !canUndo, icon: , label: , onClick: onUndo }, { key: "redo", disabled: !canRedo, icon: , label: , onClick: onRedo }, ], }} >
{isTitleEditing ? ( onTitleDraftChange(event.target.value)} onBlur={onFinishTitleEditing} onKeyDown={(event) => { if (event.key === "Enter") onFinishTitleEditing(); if (event.key === "Escape") onCancelTitleEditing(); }} className="max-w-[280px] bg-transparent p-0 text-left text-lg font-semibold tracking-normal outline-none" style={{ color: theme.node.text }} /> ) : ( )}
setShortcutsOpen(true)} onOpenPlugins={onOpenPlugins} />
setShortcutsOpen(false)} footer={null} centered>
); } function MenuLabel({ text, shortcut }: { text: string; shortcut: string }) { return ( {text} {shortcut} ); } function CompactAgentStatus({ status, onClick }: { status: { connected: boolean; enabled: boolean; activity: string }; onClick: () => void }) { const colorTheme = useThemeStore((state) => state.theme); const theme = canvasThemes[colorTheme]; const label = status.connected ? "Codex 已连接" : status.enabled ? `Codex ${status.activity || "连接中"}` : "Codex 未连接"; const dotColor = status.connected ? "#22c55e" : status.enabled ? "#f59e0b" : theme.node.muted; return ( ); } function Shortcut({ keys, value }: { keys: string[]; value: string }) { return (
{keys.map((key, index) => ( {index ? + : null} {key} ))} {value}
); }