Merge pull request 'feat: 新增电商灵感实验室模块,包含AI团队/电商套图/商品视频分类卡片' (#5) from feat/ecommerce-inspiration-lab into main
Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
@@ -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
Reference in New Issue
Block a user