feat: 新增电商灵感实验室模块,包含AI团队/电商套图/商品视频分类卡片 #5

Merged
stringadmin merged 1 commits from feat/ecommerce-inspiration-lab into main 2026-06-11 10:24:28 +00:00
2 changed files with 1226 additions and 2 deletions
Showing only changes of commit b81f4b91c2 - Show all commits
+90 -2
View File
@@ -101,6 +101,48 @@ const smartCutoutSizeOptions = [
type SmartCutoutSizeKey = (typeof smartCutoutSizeOptions)[number]["key"];
type SmartCutoutImageItem = { src: string; name: string; originalSrc?: string };
const ecommerceInspirationTabs = ["最近打开", "一键同款", "海报模板", "热门", "商品图", "模特穿戴"];
const ecommerceInspirationRows = [
{
title: "AI团队",
desc: "不止作图,更懂转化。",
variant: "team",
cards: [
{ title: "指定ASIN,优化listing", meta: "竞品拆解 · 卖点重排 · 图文建议" },
{ title: "TikTok美区爆品分析", meta: "脚本方向 · 人群洞察 · 素材策略" },
{ title: "竞品分析 + 全套listing", meta: "关键词 · 主图结构 · 转化建议" },
{ title: "世界杯属性快闪视频", meta: "热点追踪 · 模板复用 · 15秒短片" },
],
},
{
title: "电商套图",
desc: "主图 / 详情图全套一次性生成。",
variant: "listing",
cards: [
{ title: "科技礼盒主图", meta: "高反差质感 · 参数卖点" },
{ title: "美妆节日套图", meta: "促销氛围 · 多规格展示" },
{ title: "防晒产品场景", meta: "户外光感 · 功效表达" },
{ title: "露营家具详情", meta: "场景组合 · 尺寸说明" },
{ title: "香氛A+页面", meta: "材质细节 · 品牌氛围" },
{ title: "童装listing组合", meta: "多角度 · 人群展示" },
],
},
{
title: "商品视频",
desc: "口播模拟 / 商品展示视频 / 社媒短片。",
variant: "video",
cards: [
{ title: "口播种草短片", meta: "手持展示 · 真实推荐" },
{ title: "香水质感视频", meta: "光影旋转 · 高级静物" },
{ title: "玩具互动短视频", meta: "生活场景 · 情绪表达" },
{ title: "器皿产品展示", meta: "极简背景 · 材质突出" },
{ title: "饰品模特试戴", meta: "近景特写 · 搭配建议" },
{ title: "包袋生活方式", meta: "室内场景 · 组合展示" },
],
},
] as const;
const clampNumber = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));
const normalizeHexColor = (value: string) => {
@@ -4180,6 +4222,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
handleGenerate();
};
const scrollInspirationRow = (event: ReactMouseEvent<HTMLButtonElement>, direction: -1 | 1) => {
const row = event.currentTarget.closest(".ecom-inspiration-row");
const strip = row?.querySelector<HTMLElement>(".ecom-inspiration-strip");
if (!strip) return;
strip.scrollBy({ left: direction * Math.max(280, strip.clientWidth * 0.78), behavior: "smooth" });
};
const clonePreview = (
<main className="product-clone-preview clone-ai-preview" data-status={status} aria-label="电商 AI 作图预览" {...getPreviewSurfaceProps()}>
<header className="clone-ai-preview-header">
@@ -4551,7 +4600,46 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
))}
</section>
) : null}
<span className="clone-ai-char-count">{requirement.length}/500</span>
{status !== "done" ? (
<section className="ecom-inspiration-lab" aria-label="电商灵感案例">
<nav className="ecom-inspiration-tabs" aria-label="案例分类">
{ecommerceInspirationTabs.map((tab, index) => (
<button key={tab} type="button" className={index === 3 ? "is-active" : ""}>
{tab}
</button>
))}
</nav>
<div className="ecom-inspiration-rows">
{ecommerceInspirationRows.map((row) => (
<section key={row.title} className={`ecom-inspiration-row ecom-inspiration-row--${row.variant}`} aria-label={row.title}>
<div className="ecom-inspiration-row__meta">
<strong>{row.title}</strong>
<span>{row.desc}</span>
<div className="ecom-inspiration-row__controls">
<button type="button" aria-label={`向左浏览${row.title}`} onClick={(event) => scrollInspirationRow(event, -1)}></button>
<button type="button" aria-label={`向右浏览${row.title}`} onClick={(event) => scrollInspirationRow(event, 1)}></button>
</div>
</div>
<div className="ecom-inspiration-strip" tabIndex={0}>
{row.cards.map((card, index) => (
<article key={card.title} className="ecom-inspiration-card">
<div className="ecom-inspiration-card__visual" aria-hidden="true">
<span />
<span />
<span />
<span />
</div>
<strong>{card.title}</strong>
<p>{card.meta}</p>
<em>{String(index + 1).padStart(2, "0")}</em>
</article>
))}
</div>
</section>
))}
</div>
</section>
) : null}
</section>
</main>
);
@@ -5919,7 +6007,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
aria-label={isCommandHistoryCollapsed ? "展开记录" : "收起记录"}
aria-expanded={!isCommandHistoryCollapsed}
>
{isCommandHistoryCollapsed ? "" : ""}
{isCommandHistoryCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</button>
<button type="button" className="ecom-command-history__new" onClick={handleNewEcommerceConversation}></button>
<button
File diff suppressed because it is too large Load Diff