From aed5e1c977b9ce98f22e5504cfc1c87a4f873b77 Mon Sep 17 00:00:00 2001 From: 134 Date: Sun, 4 Oct 2026 10:31:32 +0800 Subject: [PATCH] fix: restore canvas skills and local uploads, simplify home and canvas headers --- .../[id]/CanvasEditorLegacyPageClient.tsx | 126 +---- app/globals.css | 24 +- components/canvas/CanvasAddImageDialog.tsx | 90 +++- components/canvas/CanvasChatPanel.tsx | 106 ++-- components/canvas/CanvasSurfaceHeader.tsx | 104 ++-- components/home/lovart-home.tsx | 505 +++++++++--------- .../home/lovart/lovart-promo-banner.tsx | 2 +- components/home/lovart/lovart-sidebar.tsx | 11 +- 8 files changed, 494 insertions(+), 474 deletions(-) diff --git a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx index 7465038d9..7cd560b04 100644 --- a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx +++ b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx @@ -250,7 +250,6 @@ import type { AgentWorkflowUiConfig, } from "@/types/agent"; import type { - AgentSlotNodeData, CanvasEdge, CanvasInitialProject, CanvasNode, @@ -7515,7 +7514,7 @@ export default function CanvasEditorLegacyPage({ materialMimeType: image.mimeType || undefined, originalHeight: dimensions.originalHeight, originalWidth: dimensions.originalWidth, - source: "agent-workflow-material-search", + source: image.sourceType === "upload" ? "local-upload" : "agent-workflow-material-search", }, }, connections: [], @@ -7527,7 +7526,7 @@ export default function CanvasEditorLegacyPage({ if (createdNodeIds.length > 0) { selectNodes(createdNodeIds); - toast.success(`已添加 ${createdNodeIds.length} 张白底图到画布`); + toast.success(`已添加 ${createdNodeIds.length} 张${validImages.every((image) => image.sourceType === "upload") ? "图片" : "白底图"}到画布`); } }, [createCanvasNode, getVisibleCanvasOrigin, selectNodes] @@ -7543,64 +7542,6 @@ export default function CanvasEditorLegacyPage({ setIsAddImageDialogOpen(true); }, [handleAddWorkflowNode, isVideoMode]); - const handleAddAgentSlotNode = useCallback((slotType: AgentSlotNodeData["slotType"]) => { - if (isVideoMode) return; - - const slotDefaults: Record< - AgentSlotNodeData["slotType"], - { - label: string; - size: CanvasNode["size"]; - aspectRatio: string; - } - > = { - image: { - label: "图片槽位", - size: { width: 320, height: 320 }, - aspectRatio: "1:1", - }, - video: { - label: "视频槽位", - size: { width: 360, height: 220 }, - aspectRatio: "16:9", - }, - "ui-screen": { - label: "UI 槽位", - size: { width: 360, height: 260 }, - aspectRatio: "16:9", - }, - }; - const defaults = slotDefaults[slotType]; - const origin = getVisibleCanvasOrigin(); - createCanvasNode({ - type: "agent-slot", - position: { - x: origin.x + 40, - y: origin.y + 40, - }, - size: defaults.size, - data: { - slotType, - label: defaults.label, - status: "empty", - aspectRatio: defaults.aspectRatio, - fillPolicy: "replace-empty", - acceptedSources: ["text", "image", "selection", "annotation"], - filledNodeIds: [], - metadata: { - createdBy: "toolbar", - createdSlotType: slotType, - createdAt: new Date().toISOString(), - }, - }, - connections: [], - }); - }, [createCanvasNode, getVisibleCanvasOrigin, isVideoMode]); - - const handleAddAgentImageSlotNode = useCallback(() => { - handleAddAgentSlotNode("image"); - }, [handleAddAgentSlotNode]); - const handleAddVideoNode = useCallback(() => { if (isVideoMode) { handleAddWorkflowNode("video-input"); @@ -10325,7 +10266,7 @@ export default function CanvasEditorLegacyPage({
- {!isVideoMode && - isCanvasToolbarItemEnabled( - canvasToolbarConfig, - "addAgentImageSlot" - ) ? ( - - - - - - - - - { - getCanvasToolbarItem( - canvasToolbarConfig, - "addAgentImageSlot" - ).label - } - - - - handleAddAgentImageSlotNode()} - > - - 图片槽位 - - handleAddAgentSlotNode("video")} - > - - - handleAddAgentSlotNode("ui-screen")} - > - - UI 槽位 - - - - ) : null} - +
{!materialSearchEnabled ? (
- 风格化功能或素材搜索步骤未开启,当前只显示空白图片入口。 + 风格化功能或素材搜索步骤未开启,可从本地上传或添加空白图片。
) : null} {errorText ? ( -
+
{errorText}
) : null} @@ -440,6 +513,7 @@ export function CanvasAddImageDialog({
) : ( -
-
-

准备怎么开启你的创作?

-
- - {canvasSkillTags.length > 0 ? : null} - - {onOpenFileList ? : null} -
+
+
+

+ Hi,{" "} + {greetingUserName ? ( + {greetingUserName} + ) : null}{" "} + {greetingPeriodText} +

+

+ 开始创作吧! 累计为你生成了{" "} + + {Number.isFinite(totalGeneratedImages) ? totalGeneratedImages : 0} + {" "} + 张图。 +

- {canvasSkillTags.length > 0 && isCanvasSkillPickerOpen ? ( -
+ {canvasSkillTags.length > 0 ? ( +

{canvasSkillTagsTitle}

@@ -15965,40 +15972,38 @@ export function CanvasChatPanel({ ) : null}
) : null} - {canvasSkillTags.length > 4 ? ( -
- - - setCanvasSkillTagSearchQuery(event.target.value) +
+ + + setCanvasSkillTagSearchQuery(event.target.value) + } + onKeyDown={(event) => { + if (event.key === "Escape") { + setCanvasSkillTagSearchQuery(""); } - onKeyDown={(event) => { - if (event.key === "Escape") { - setCanvasSkillTagSearchQuery(""); - } - }} - placeholder="搜索快捷技能" - aria-label="搜索快捷技能" - autoComplete="off" - enterKeyHint="search" - spellCheck={false} - className="h-full min-w-0 flex-1 bg-transparent text-[13px] text-[#1f2328] outline-none placeholder:text-[#9aa1ad] dark:text-zinc-100 dark:placeholder:text-zinc-500" - /> - {canvasSkillTagSearchQuery ? ( - - ) : null} -
- ) : null} + }} + placeholder="搜索快捷技能" + aria-label="搜索快捷技能" + autoComplete="off" + enterKeyHint="search" + spellCheck={false} + className="h-full min-w-0 flex-1 bg-transparent text-[13px] text-[#1f2328] outline-none placeholder:text-[#9aa1ad] dark:text-zinc-100 dark:placeholder:text-zinc-500" + /> + {canvasSkillTagSearchQuery ? ( + + ) : null} +
{filteredCanvasSkillTags.map((tag) => { @@ -16093,6 +16098,15 @@ export function CanvasChatPanel({ ) : null}
) : null} +
+ + {canvasSkillTags.length > 0 ? : null} + + {onOpenFileList ? : null} +
)}
diff --git a/components/canvas/CanvasSurfaceHeader.tsx b/components/canvas/CanvasSurfaceHeader.tsx index 2331575c9..fb2aff3d1 100644 --- a/components/canvas/CanvasSurfaceHeader.tsx +++ b/components/canvas/CanvasSurfaceHeader.tsx @@ -27,8 +27,12 @@ export function CanvasSurfaceHeader({ rightInset, }: CanvasSurfaceHeaderProps) { return ( - <> -
+
+
-
-
-
- - -
- - - - {projectTitle || "页面 1"} - - - -
+ +
+ + + + {projectTitle || "页面 1"} + + +
- + +
); } diff --git a/components/home/lovart-home.tsx b/components/home/lovart-home.tsx index 02d7b49cb..03f0e7b22 100644 --- a/components/home/lovart-home.tsx +++ b/components/home/lovart-home.tsx @@ -3,7 +3,7 @@ import { ReferenceIcon, type ReferenceIconName } from "@/components/lovart/reference-icon"; import dynamic from "next/dynamic"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { type CSSProperties, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useRouter } from "next/navigation"; import { useTheme } from "next-themes"; import useSWR from "swr"; @@ -71,7 +71,6 @@ import { normalizeLovartHomeSidebarConfig, type LovartHomeSidebarItemKey, } from "@/lib/home/lovart-sidebar-config"; -import { BrandTopBar } from "@/components/layout/brand-top-bar"; import { LovartFeaturedGallery } from "@/components/home/lovart/lovart-featured-gallery"; import { LovartHeroComposer } from "@/components/home/lovart/lovart-hero-composer"; import { LovartProjectsSection } from "@/components/home/lovart/lovart-projects-section"; @@ -422,16 +421,15 @@ function AccountMenuItem({ onClick: () => void; }) { return ( - + ); } @@ -1717,6 +1715,259 @@ export function LovartHome({ THEME_MODE_OPTIONS[0]; const SelectedThemeIcon = selectedThemeOption.icon; + const homeThemeControl = () => ( + + + + + +
+ {THEME_MODE_OPTIONS.map((option) => { + const OptionIcon = option.icon; + const isSelected = selectedThemeMode === option.value; + + return ( + setTheme(option.value)} + title={option.label} + > + + + ); + })} +
+
+
+ ); + const homeUtilityControls = () => ( + <> + + {homeThemeControl()} + + ); + const homeAccountControls = () => ( +
+ {isMembershipEnabled ? ( + + + + + +
+
+
+
+ {currentPlan?.name || "Free"} +
+
+ +
+
+
+ + + 积分 + + {membershipData?.summary?.currentCredits ?? 0} +
+
+ + + 每日免费积分 + + {membershipData?.summary?.dailyFreeCredits ?? 0} +
+
+ +
+
+
+ ) : null} + + {isAuthenticated ? ( + + + + + +
+
+
+
+ {userInitials} +
+
+ +
+
+
+ {userDisplayName} +
+
+ {user?.email || ""} +
+
+ {isMembershipEnabled ? ( + + + + ) : null} +
+ +
+ + + +
+
+ +
+ {isMembershipEnabled ? ( + toast.info("团队功能后续开放")} + /> + ) : null} + { + setAccountCenterTab("account"); + setUsageFilter("all"); + setAccountCenterOpen(true); + }} + /> + toast.info("使用指南后续开放")} + /> + setContactDialogOpen(true)} + /> +
+ + 通知与主题 + +
+ {homeUtilityControls()} +
+
+ { + void handleLogout(); + }} + /> +
+
+
+
+ ) : ( + <> + {homeThemeControl()} + + + )} +
+ ); + return (
{shouldShowHomeBanner ? ( @@ -1728,237 +1979,12 @@ export function LovartHome({ text={homeBannerText} /> ) : null} - window.scrollTo({ top: 0, behavior: "smooth" })} - showBrand={false} - siteName={siteName || "Lovart"} - > - - - {isMembershipEnabled ? ( - - - - - -
-
-
-
- {currentPlan?.name || "Free"} -
-
- -
-
-
- - - 积分 - - {membershipData?.summary?.currentCredits ?? 0} -
-
- - - 每日免费积分 - - {membershipData?.summary?.dailyFreeCredits ?? 0} -
-
- -
-
-
- ) : null} - - - - - - -
- {THEME_MODE_OPTIONS.map((option) => { - const OptionIcon = option.icon; - const isSelected = selectedThemeMode === option.value; - - return ( - setTheme(option.value)} - title={option.label} - > - - - ); - })} -
-
-
- - {isAuthenticated ? ( - - - - - -
-
-
-
- {userInitials} -
-
- -
-
-
- {userDisplayName} -
-
- {user?.email || ""} -
-
- {isMembershipEnabled ? ( - - ) : null} -
- -
- -
-
- -
- {isMembershipEnabled ? ( - toast.info("团队功能后续开放")} - /> - ) : null} - { - setAccountCenterTab("account"); - setUsageFilter("all"); - setAccountCenterOpen(true); - }} - /> - toast.info("使用指南后续开放")} - /> - setContactDialogOpen(true)} - /> - { - void handleLogout(); - }} - /> -
-
-
-
- ) : ( - - )} -
+
+ {homeAccountControls()} +
{!isProjectsOnlyView && ( @@ -2153,7 +2182,7 @@ export function LovartHome({ {loginDialogOpen ? (
setLoginDialogOpen(false)} >
+

diff --git a/components/home/lovart/lovart-sidebar.tsx b/components/home/lovart/lovart-sidebar.tsx index aeff0afd4..c9183df7f 100644 --- a/components/home/lovart/lovart-sidebar.tsx +++ b/components/home/lovart/lovart-sidebar.tsx @@ -20,6 +20,7 @@ type SidebarItem = { }; type LovartSidebarProps = { + accountControls?: ReactNode; agentEnabled: boolean; getItem: (key: LovartHomeSidebarItemKey) => SidebarItem; isEnabled: (key: LovartHomeSidebarItemKey) => boolean; @@ -56,6 +57,7 @@ type LovartSidebarProps = { }; export function LovartSidebar({ + accountControls, agentEnabled, getItem, isEnabled, @@ -172,7 +174,7 @@ export function LovartSidebar({ style={{ top: topOffset }} > -

+
+
+ {settingsHref ? tooltipButton("settings", () => onRoute(settingsHref)) : null} + {accountControls}