feat(canvas): 前端重构与渠道兼容 - 重构工作区、任务中心等多页面,修复智能体对话与节点生成

Co-authored-by: sikongyue <3155157671@qq.com>
Original-PR: https://github.com/ddcat-ai/open-ai-canvas/pull/217
This commit is contained in:
爱笑的毛毛虫andsikongyue authored and GitHub committed 2026-08-14 12:01:21 +08:00
1 parent fb2a54b345
commit cfdf08d05f
37 files changed
+4599 -912

No files matched your search

@@ -1,5 +1,5 @@
import { App, Popover, Switch } from "antd";
import { ChevronRight, LogIn, LogOut, Moon, ShieldCheck, Sun, UserRound } from "lucide-react";
import { ChevronRight, CircleUserRound, LogIn, LogOut, Moon, ShieldCheck, Sun } from "lucide-react";
import { useEffect, useState, type ReactNode } from "react";
import { Link, useNavigate } from "react-router";
@@ -17,9 +17,10 @@ type WorkspaceSidebarFooterProps = {
expandedClassName: string;
collapsedClassName: string;
accountClassName: string;
showAnnouncement?: boolean;
};
export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName, accountClassName }: WorkspaceSidebarFooterProps) {
export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName, accountClassName, showAnnouncement = true }: WorkspaceSidebarFooterProps) {
const theme = useThemeStore((state) => state.theme);
const setTheme = useThemeStore((state) => state.setTheme);
const user = useUserStore((state) => state.user);
@@ -49,10 +50,10 @@ export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName,
return (
<div>
{user ? (
{user && showAnnouncement ? (
<SystemAnnouncementCenter
userId={user.id}
className={cn("relative mb-1 flex h-9 w-full items-center rounded-md text-xs text-foreground/55 transition-colors hover:bg-foreground/[.05] hover:text-foreground", collapsedClassName)}
className={cn("relative mb-1 flex h-9 w-full items-center rounded-md text-xs text-foreground/55 transition-colors hover:bg-surface-hover hover:text-foreground", collapsedClassName)}
showLabel
labelClassName={expandedClassName}
staticMotion
@@ -81,7 +82,7 @@ export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName,
) : null}
<div className="border-y border-border/65 py-2">
<AppChangelogButton className="flex h-8 w-full items-center gap-2 rounded px-2 text-[var(--fs-label)] text-foreground/58 hover:bg-foreground/[.055] hover:text-foreground [&_svg]:size-3.5" showLabel showVersion versionClassName="ml-auto text-[var(--fs-micro)] tabular-nums text-foreground/32" />
<AppChangelogButton className="flex h-8 w-full items-center gap-2 rounded px-2 text-[var(--fs-label)] text-foreground/58 hover:bg-surface-hover hover:text-foreground [&_svg]:size-3.5" showLabel showVersion versionClassName="ml-auto text-[var(--fs-micro)] tabular-nums text-foreground/32" />
</div>
<div className="flex h-10 items-center px-2">
@@ -89,11 +90,11 @@ export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName,
<span className="ml-2 flex-1 text-xs text-foreground/65">深色模式</span>
<Switch size="small" checked={theme === "dark"} onChange={(checked) => setTheme(checked ? "dark" : "light")} aria-label="深色模式" />
</div>
<button type="button" className="flex h-9 w-full items-center gap-2 rounded px-2 text-xs text-foreground/55 hover:bg-foreground/[.055] hover:text-foreground" onClick={() => void handleLogout()}><LogOut className="size-3.5" />退出登录</button>
<button type="button" className="flex h-9 w-full items-center gap-2 rounded px-2 text-xs text-foreground/55 hover:bg-surface-hover hover:text-foreground" onClick={() => void handleLogout()}><LogOut className="size-3.5" />退出登录</button>
</div>
)}
>
<button type="button" className={cn("flex min-h-10 w-full min-w-0 items-center overflow-hidden rounded-md text-left transition-colors hover:bg-foreground/[.045]", accountClassName)} title={creditsEnabled ? `${user.displayName || user.username} · ${balance} 积分` : user.displayName || user.username}>
<button type="button" className={cn("flex min-h-10 w-full min-w-0 items-center overflow-hidden rounded-md text-left transition-colors hover:bg-surface-hover", accountClassName)} title={creditsEnabled ? `${user.displayName || user.username} · ${balance} 积分` : user.displayName || user.username}>
<UserAvatar user={user} className="size-7" />
<span className={cn("min-w-0 flex-1 flex-col", expandedClassName)}>
<span className="truncate text-xs font-medium">{user.displayName || user.username}</span>
@@ -103,7 +104,7 @@ export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName,
</button>
</Popover>
) : (
<Link to="/login" className={cn("flex h-10 items-center rounded-md text-xs text-foreground/65 hover:bg-foreground/[.05] hover:text-foreground", collapsedClassName)} title="登录">
<Link to="/login" className={cn("flex h-10 items-center rounded-md text-xs text-foreground/65 hover:bg-surface-hover hover:text-foreground", collapsedClassName)} title="登录">
<LogIn className="size-4 shrink-0" /><span className={expandedClassName}>登录</span>
</Link>
)}
@@ -112,7 +113,7 @@ export function WorkspaceSidebarFooter({ expandedClassName, collapsedClassName,
}
function MenuLink({ to, icon, label, onNavigate }: { to: string; icon: ReactNode; label: string; onNavigate: () => void }) {
return <Link to={to} onClick={onNavigate} className="flex h-9 items-center gap-2.5 rounded px-2 text-xs text-foreground/62 hover:bg-foreground/[.055] hover:text-foreground [&_svg]:size-3.5 [&_svg]:shrink-0">{icon}<span className="flex-1">{label}</span><ChevronRight className="!size-3 text-foreground/25" /></Link>;
return <Link to={to} onClick={onNavigate} className="flex h-9 items-center gap-2.5 rounded px-2 text-xs text-foreground/62 hover:bg-surface-hover hover:text-foreground [&_svg]:size-3.5 [&_svg]:shrink-0">{icon}<span className="flex-1">{label}</span><ChevronRight className="!size-3 text-foreground/25" /></Link>;
}
function UserAvatar({ user, className }: { user: LocalUser; className: string }) {
@@ -123,11 +124,11 @@ function UserAvatar({ user, className }: { user: LocalUser; className: string })
return (
<span className={`relative grid shrink-0 place-items-center ${className}`}>
<span className="grid size-full place-items-center overflow-hidden rounded-full bg-muted text-foreground/55">
<span className="grid size-full place-items-center overflow-hidden rounded-md bg-transparent text-foreground/55">
{avatarUrl && !failed ? (
<img src={avatarUrl} alt="" referrerPolicy="no-referrer" className="size-full object-cover" onError={() => setFailed(true)} />
) : (
<UserRound className="size-[52%]" aria-hidden />
<CircleUserRound className="app-workspace-account-icon" aria-hidden />
)}
</span>
<IdentityProviderBadge user={user} compact className="absolute -bottom-1 -right-1" />