feat: polish agent workflow material and banner ui
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-21 12:41:47 +08:00
parent 21a915cb13
commit e2f4d5a3db
6 changed files with 52 additions and 17 deletions

View File

@ -11,8 +11,8 @@ import type {
} from "@/types/agent";
interface AgentWorkflowMaterialPickerProps {
title: string;
description: string;
title?: string;
description?: string;
value: string;
queryMode: AgentWorkflowMaterialQueryType;
placeholder: string;
@ -90,12 +90,18 @@ export function AgentWorkflowMaterialPicker({
isDark ? "border-white/12 bg-black/20" : "bg-muted/20"
)}
>
<div className="space-y-1">
<div className={cn("text-sm font-medium", isDark ? "text-white/92" : "")}>{title}</div>
<div className={cn("text-xs", isDark ? "text-white/62" : "text-muted-foreground")}>
{description}
{title || description ? (
<div className="space-y-1">
{title ? (
<div className={cn("text-sm font-medium", isDark ? "text-white/92" : "")}>{title}</div>
) : null}
{description ? (
<div className={cn("text-xs", isDark ? "text-white/62" : "text-muted-foreground")}>
{description}
</div>
) : null}
</div>
</div>
) : null}
<div className="flex flex-wrap gap-2">
{(["sku", "spu"] as const).map((mode) => (

View File

@ -211,8 +211,6 @@ export function AgentWorkflowMaterialSelectionPanel({
) : null}
<AgentWorkflowMaterialPicker
title="主 SKU / SPU"
description="主商品图会优先自动填充到“产品图1”;如果没有搭配图,再继续补到“产品图2”。"
value={inputs.primarySku}
queryMode={materialSearchMode.primary}
placeholder={materialSearchMode.primary === "spu" ? "输入主 SPU" : "输入主 SKU"}
@ -281,8 +279,6 @@ export function AgentWorkflowMaterialSelectionPanel({
{isSecondaryMaterialVisible ? (
<AgentWorkflowMaterialPicker
title="搭配 SKU"
description="搭配商品图会优先自动填充到“产品图2”;品牌模特图会在上方单独选择并进入模特图槽位。"
value={inputs.secondarySku}
queryMode={materialSearchMode.secondary}
placeholder={materialSearchMode.secondary === "spu" ? "输入搭配 SPU" : "输入搭配 SKU"}

View File

@ -385,7 +385,7 @@ export function AgentWorkflowPanelDarkV2({
const workflowContent = (
<div className="space-y-8">
{/* 基础配置 */}
{/* 品牌和店铺选择 */}
<motion.section
className="rounded-2xl border border-white/12 bg-white/[0.04] p-5 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
initial={{ opacity: 0, y: 20 }}
@ -396,7 +396,7 @@ export function AgentWorkflowPanelDarkV2({
<span className="flex h-6 w-6 items-center justify-center rounded-md bg-emerald-500/20 text-xs font-bold text-emerald-400">
1
</span>
基础配置
品牌和店铺选择
</h2>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 max-w-2xl">
<SearchableSelect

View File

@ -4,11 +4,26 @@ import { cn } from "@/lib/utils";
type AgentWorkflowParticleScatterProps = {
className?: string;
particleSize?: number;
particleCount?: number;
};
export function AgentWorkflowParticleScatter({
className,
particleSize,
particleCount,
}: AgentWorkflowParticleScatterProps) {
const searchParams = new URLSearchParams();
if (typeof particleSize === "number" && Number.isFinite(particleSize) && particleSize > 0) {
searchParams.set("particleSize", String(particleSize));
}
if (typeof particleCount === "number" && Number.isFinite(particleCount) && particleCount > 0) {
searchParams.set("particleCount", String(Math.round(particleCount)));
}
const src = searchParams.size
? `/particle-scatter-effect.html?${searchParams.toString()}`
: "/particle-scatter-effect.html";
return (
<div
className={cn(
@ -18,9 +33,9 @@ export function AgentWorkflowParticleScatter({
>
<iframe
aria-hidden="true"
className="h-full w-full border-0 bg-transparent [mask-image:linear-gradient(to_top,black_72%,transparent_100%)]"
className="h-full w-full border-0 bg-transparent"
loading="eager"
src="/particle-scatter-effect.html"
src={src}
tabIndex={-1}
title="Particle Scatter Background"
/>

View File

@ -44,7 +44,13 @@ export function AgentWorkflowShowcaseBanner({
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<AgentWorkflowParticleScatter className="top-0 h-full opacity-20" />
<AgentWorkflowParticleScatter
className="top-0 h-full"
particleSize={110}
particleCount={76000}
/>
<div className="pointer-events-none absolute inset-0 bg-black/80" />
<div className="pointer-events-none absolute inset-x-0 top-0 h-[24%] bg-gradient-to-b from-black via-black/72 to-transparent" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-[34%] bg-gradient-to-t from-black via-black/28 to-transparent" />
<div className="relative z-10">

View File

@ -25,6 +25,17 @@
interactionMode: "auto",
manualControlTarget: "camera"
};
try {
const urlParams = new URLSearchParams(window.location.search);
const particleSizeOverride = Number(urlParams.get("particleSize"));
const particleCountOverride = Number(urlParams.get("particleCount"));
if (Number.isFinite(particleSizeOverride) && particleSizeOverride > 0) {
CONFIG.particleSize = particleSizeOverride;
}
if (Number.isFinite(particleCountOverride) && particleCountOverride > 0) {
CONFIG.particleCount = Math.floor(particleCountOverride);
}
} catch (error) {}
let uploadedImage = CONFIG.uploadedImage;
let particleSize = CONFIG.particleSize;
const PARTICLE_COUNT = CONFIG.particleCount;
@ -153,6 +164,7 @@
if (!sceneData) return;
sceneData.camera.aspect = window.innerWidth / window.innerHeight;
sceneData.camera.updateProjectionMatrix();
sceneData.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
sceneData.renderer.setSize(window.innerWidth, window.innerHeight);
});
renderer.domElement.addEventListener("mousedown", function(e) {
@ -296,4 +308,4 @@
document.addEventListener("DOMContentLoaded", initParticleCanvas);
</script>
</body>
</html>
</html>