Polish ecommerce tool page layouts
This commit is contained in:
@@ -2137,10 +2137,19 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
|
|
||||||
const openHotVideoPage = () => {
|
const openHotVideoPage = () => {
|
||||||
clearSmartCutoutTransition();
|
clearSmartCutoutTransition();
|
||||||
setActiveQuickTool("hot-video");
|
clearQuickPageTransition();
|
||||||
setComposerMenu(null);
|
runQuickPageTransition(
|
||||||
setIsCloneSettingsCollapsed(true);
|
{ title: "正在进入广告视频", subtitle: "AI智能策划 · 一键生成电商短视频" },
|
||||||
setIsCommandHistoryCollapsed(true);
|
() => {
|
||||||
|
setActiveQuickTool("hot-video");
|
||||||
|
setComposerMenu(null);
|
||||||
|
setIsCloneSettingsCollapsed(true);
|
||||||
|
setIsCommandHistoryCollapsed(true);
|
||||||
|
setPreviewZoom(1);
|
||||||
|
setRatio("9:16");
|
||||||
|
resetQuickSetSelectState();
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeHotVideoPage = () => {
|
const closeHotVideoPage = () => {
|
||||||
@@ -4949,16 +4958,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
className="ecom-command-hidden-file"
|
className="ecom-command-hidden-file"
|
||||||
onChange={handleImageWorkbenchUpload}
|
onChange={handleImageWorkbenchUpload}
|
||||||
/>
|
/>
|
||||||
<nav className="ecom-image-workbench-nav" aria-label="图片修改导航">
|
|
||||||
<button type="button" onClick={closeImageWorkbenchPage}>首页</button>
|
|
||||||
<button type="button" onClick={closeImageWorkbenchPage}>上一页</button>
|
|
||||||
</nav>
|
|
||||||
<aside className="ecom-image-workbench-side">
|
<aside className="ecom-image-workbench-side">
|
||||||
<div className="ecom-image-workbench-heading">
|
<header className="ecom-quick-set-panel-head ecom-image-workbench-panel-head">
|
||||||
<span>图片修改</span>
|
<strong className="ecom-quick-set-page-title">图片修改</strong>
|
||||||
<strong>图片修改</strong>
|
<button type="button" className="ecom-quick-set-back" onClick={closeImageWorkbenchPage}>首页</button>
|
||||||
<p>涂抹需要修改的区域,输入提示词后让 AI 替换局部内容。</p>
|
<button type="button" className="ecom-quick-set-back" onClick={closeImageWorkbenchPage}>上一页</button>
|
||||||
</div>
|
</header>
|
||||||
|
<p className="ecom-image-workbench-intro">涂抹需要修改的区域,输入提示词后让 AI 替换局部内容。</p>
|
||||||
|
|
||||||
<section className="ecom-image-workbench-panel">
|
<section className="ecom-image-workbench-panel">
|
||||||
<header>
|
<header>
|
||||||
@@ -5157,16 +5163,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
className="ecom-command-hidden-file"
|
className="ecom-command-hidden-file"
|
||||||
onChange={handleWatermarkUpload}
|
onChange={handleWatermarkUpload}
|
||||||
/>
|
/>
|
||||||
<nav className="ecom-watermark-nav" aria-label="去水印导航">
|
|
||||||
<button type="button" onClick={closeWatermarkRemovalPage}>首页</button>
|
|
||||||
<button type="button" onClick={closeWatermarkRemovalPage}>上一页</button>
|
|
||||||
</nav>
|
|
||||||
<aside className="ecom-watermark-side">
|
<aside className="ecom-watermark-side">
|
||||||
<div className="ecom-watermark-heading">
|
<header className="ecom-quick-set-panel-head ecom-watermark-panel-head">
|
||||||
<span>AI 电商工具</span>
|
<strong className="ecom-quick-set-page-title">增/去水印</strong>
|
||||||
<strong>增/去水印</strong>
|
<button type="button" className="ecom-quick-set-back" onClick={closeWatermarkRemovalPage}>首页</button>
|
||||||
<p>上传商品素材,快速清理画面中的水印、文字和瑕疵。</p>
|
<button type="button" className="ecom-quick-set-back" onClick={closeWatermarkRemovalPage}>上一页</button>
|
||||||
</div>
|
</header>
|
||||||
|
<p className="ecom-watermark-intro">上传商品素材,快速清理画面中的水印、文字和瑕疵。</p>
|
||||||
<section className="ecom-watermark-panel">
|
<section className="ecom-watermark-panel">
|
||||||
<header>
|
<header>
|
||||||
<strong>上传素材</strong>
|
<strong>上传素材</strong>
|
||||||
@@ -5347,46 +5350,35 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const hotVideoPreview = (
|
const hotVideoPreview = (
|
||||||
<main className="ecom-hot-video-page" aria-label="广告视频">
|
<main className="ecom-quick-set-page ecom-hot-video-page" aria-label="广告视频">
|
||||||
<nav className="ecom-hot-video-nav">
|
<div className="ecom-quick-set-body">
|
||||||
<button type="button" className="ecom-hot-video-back" onClick={closeHotVideoPage}>
|
<aside className="ecom-quick-set-panel" aria-label="广告视频设置">
|
||||||
‹ 返回首页
|
<header className="ecom-quick-set-panel-head">
|
||||||
</button>
|
<strong className="ecom-quick-set-page-title">广告视频</strong>
|
||||||
<div className="ecom-hot-video-nav-title">
|
<button type="button" className="ecom-quick-set-back" onClick={closeHotVideoPage}>首页</button>
|
||||||
<h1>广告视频</h1>
|
<button type="button" className="ecom-quick-set-back" onClick={closeHotVideoPage}>上一页</button>
|
||||||
<span>AI智能策划 · 一键生成电商短视频</span>
|
</header>
|
||||||
</div>
|
<section>
|
||||||
<div className="ecom-hot-video-nav-meta">
|
<strong><CloudUploadOutlined /> 上传商品图</strong>
|
||||||
<span>{platform} / {formatRatioDisplayValue(ratio)} / {cloneVideoDuration}秒 / {cloneVideoQuality === "standard" ? "720P" : "1080P"}</span>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div className="ecom-hot-video-body">
|
|
||||||
<aside className="ecom-hot-video-settings" aria-label="视频设置">
|
|
||||||
<section className="ecom-hot-video-section">
|
|
||||||
<strong>上传商品图</strong>
|
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={`ecom-hot-video-upload${productImages.length ? " has-images" : ""}${isProductUploadDragging ? " is-dragging" : ""}`}
|
className={`ecom-quick-set-upload${productImages.length ? " has-images" : ""}`}
|
||||||
onClick={() => quickProductInputRef.current?.click()}
|
onClick={() => quickProductInputRef.current?.click()}
|
||||||
onKeyDown={(event) => { if (event.key === "Enter" || event.key === " ") quickProductInputRef.current?.click(); }}
|
onKeyDown={(event) => { if (event.key === "Enter" || event.key === " ") quickProductInputRef.current?.click(); }}
|
||||||
onDragOver={(event) => { event.preventDefault(); setIsProductUploadDragging(true); }}
|
onDragOver={(event) => { event.preventDefault(); setIsProductUploadDragging(true); }}
|
||||||
onDragLeave={(event) => { event.preventDefault(); setIsProductUploadDragging(false); }}
|
onDragLeave={(event) => { event.preventDefault(); setIsProductUploadDragging(false); }}
|
||||||
onDrop={handleProductDrop}
|
onDrop={handleProductDrop}
|
||||||
>
|
>
|
||||||
<CloudUploadOutlined />
|
<FileImageOutlined />
|
||||||
<span>拖拽或点击上传商品图片</span>
|
<span>拖拽或点击上传</span>
|
||||||
<em>支持 JPG / PNG / WebP,建议清晰白底图</em>
|
<em>支持 JPG / PNG / WebP</em>
|
||||||
|
<b>+ 上传图片</b>
|
||||||
{productImages.length > 0 ? (
|
{productImages.length > 0 ? (
|
||||||
<div className="ecom-hot-video-upload-thumbs">
|
<div className="ecom-quick-upload-thumbs">
|
||||||
{productImages.map((img) => (
|
{productImages.map((img) => (
|
||||||
<figure key={img.id}>
|
<figure key={img.id} className="ecom-command-asset-thumb ecom-quick-upload-thumb">
|
||||||
<img src={img.src} alt={img.name} />
|
<img src={img.src} alt={img.name} />
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label="删除"
|
|
||||||
onClick={(event) => { event.stopPropagation(); removeProductImage(img.id); }}
|
|
||||||
>×</button>
|
|
||||||
</figure>
|
</figure>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -5401,8 +5393,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
onChange={handleProductUpload}
|
onChange={handleProductUpload}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
<section className="ecom-hot-video-section">
|
|
||||||
<strong>商品描述</strong>
|
<strong>商品描述</strong>
|
||||||
<textarea
|
<textarea
|
||||||
className="ecom-hot-video-textarea"
|
className="ecom-hot-video-textarea"
|
||||||
@@ -5413,41 +5404,16 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
maxLength={500}
|
maxLength={500}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
<section className="ecom-quick-set-basic-section">
|
||||||
<section className="ecom-hot-video-section">
|
<span className="ecom-quick-set-label">基础设置</span>
|
||||||
<strong>电商平台</strong>
|
<div className="ecom-quick-set-select-anchor">
|
||||||
<div className="ecom-hot-video-options">
|
<div className="ecom-quick-set-selects">
|
||||||
{platformOptions.map((option) => (
|
<button type="button"><span>平台</span><strong>{platform}</strong></button>
|
||||||
<button
|
<button type="button"><span>比例</span><strong>{ratio}</strong></button>
|
||||||
key={option}
|
</div>
|
||||||
type="button"
|
|
||||||
className={platform === option ? "is-active" : ""}
|
|
||||||
onClick={() => setPlatform(option)}
|
|
||||||
>
|
|
||||||
{renderPlatformLogo(option)}
|
|
||||||
<span>{option}</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
<section className="ecom-hot-video-section">
|
|
||||||
<strong>视频比例</strong>
|
|
||||||
<div className="ecom-hot-video-options ecom-hot-video-options--ratio">
|
|
||||||
{cloneRatioOptions.map((option) => (
|
|
||||||
<button
|
|
||||||
key={option}
|
|
||||||
type="button"
|
|
||||||
className={ratio === option ? "is-active" : ""}
|
|
||||||
onClick={() => setRatio(option)}
|
|
||||||
>
|
|
||||||
{formatRatioDisplayValue(option)}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="ecom-hot-video-section">
|
|
||||||
<strong>视频质量</strong>
|
<strong>视频质量</strong>
|
||||||
<div className="ecom-hot-video-options">
|
<div className="ecom-hot-video-options">
|
||||||
{cloneVideoQualityOptions.map((option) => (
|
{cloneVideoQualityOptions.map((option) => (
|
||||||
@@ -5463,8 +5429,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
<section className="ecom-hot-video-section">
|
|
||||||
<strong>视频时长 · {cloneVideoDuration}秒</strong>
|
<strong>视频时长 · {cloneVideoDuration}秒</strong>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
@@ -5481,24 +5446,23 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
<span>{cloneVideoDurationMax}秒</span>
|
<span>{cloneVideoDurationMax}秒</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="ecom-hot-video-start"
|
className="ecom-quick-set-primary"
|
||||||
disabled={!productImages.length && !requirement.trim()}
|
disabled={!productImages.length && !requirement.trim()}
|
||||||
onClick={() => setVideoPlanTrigger((prev) => prev + 1)}
|
onClick={() => setVideoPlanTrigger((prev) => prev + 1)}
|
||||||
>
|
>
|
||||||
一键策划
|
✦ 一键策划
|
||||||
</button>
|
</button>
|
||||||
</aside>
|
</aside>
|
||||||
<section className="ecom-hot-video-workspace">
|
<section className="ecom-quick-set-stage">
|
||||||
<EcommerceVideoWorkspace
|
<EcommerceVideoWorkspace
|
||||||
isAuthenticated={isAuthenticated}
|
isAuthenticated={isAuthenticated}
|
||||||
productImageDataUrls={ecommerceVideoImageDataUrls}
|
productImageDataUrls={ecommerceVideoImageDataUrls}
|
||||||
productImageFiles={ecommerceVideoImageFiles}
|
productImageFiles={ecommerceVideoImageFiles}
|
||||||
requirement={requirement}
|
requirement={requirement}
|
||||||
platform={platform}
|
platform={platform}
|
||||||
aspectRatio={ratio.includes("9:16") || ratio.includes("9:16") ? "9:16" : ratio.includes("16:9") || ratio.includes("16:9") ? "16:9" : ratio.includes("3:4") || ratio.includes("3:4") ? "3:4" : "9:16"}
|
aspectRatio={ratio.includes("9:16") ? "9:16" : ratio.includes("16:9") ? "16:9" : ratio.includes("3:4") ? "3:4" : "9:16"}
|
||||||
durationSeconds={cloneVideoDuration}
|
durationSeconds={cloneVideoDuration}
|
||||||
resolution={cloneVideoQuality === "standard" ? "720P" : "1080P"}
|
resolution={cloneVideoQuality === "standard" ? "720P" : "1080P"}
|
||||||
onRequestLogin={() => (isAuthenticated ? undefined : requestLogin())}
|
onRequestLogin={() => (isAuthenticated ? undefined : requestLogin())}
|
||||||
@@ -5606,8 +5570,11 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<button type="button" className="ecom-quick-set-primary" onClick={handleGenerate} disabled={!canGenerate}>
|
<button type="button" className="ecom-quick-set-primary" onClick={handleGenerate} disabled={!canGenerate}>
|
||||||
✦ 开始生成
|
{status === "generating" ? <LoadingOutlined /> : "✦"} {status === "generating" ? "正在生成..." : "开始生成"}
|
||||||
</button>
|
</button>
|
||||||
|
{status === "generating" ? (
|
||||||
|
<button type="button" className="ecom-quick-set-primary ecom-quick-set-primary--cancel" onClick={handleCancelGenerate}>取消生成</button>
|
||||||
|
) : null}
|
||||||
</aside>
|
</aside>
|
||||||
<section className="ecom-quick-set-stage">
|
<section className="ecom-quick-set-stage">
|
||||||
<header className="ecom-quick-set-preview-head">
|
<header className="ecom-quick-set-preview-head">
|
||||||
@@ -5777,6 +5744,9 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
<button type="button" className="ecom-quick-set-primary" onClick={handleDetailGenerate} disabled={!canGenerateDetail}>
|
<button type="button" className="ecom-quick-set-primary" onClick={handleDetailGenerate} disabled={!canGenerateDetail}>
|
||||||
{detailStatus === "generating" ? <LoadingOutlined /> : "✦"} 开始生成
|
{detailStatus === "generating" ? <LoadingOutlined /> : "✦"} 开始生成
|
||||||
</button>
|
</button>
|
||||||
|
{detailStatus === "generating" ? (
|
||||||
|
<button type="button" className="ecom-quick-set-primary ecom-quick-set-primary--cancel" onClick={handleCancelGenerate}>取消生成</button>
|
||||||
|
) : null}
|
||||||
</aside>
|
</aside>
|
||||||
<section className="ecom-quick-set-stage">
|
<section className="ecom-quick-set-stage">
|
||||||
<header className="ecom-quick-set-preview-head">
|
<header className="ecom-quick-set-preview-head">
|
||||||
@@ -5958,12 +5928,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
? imageWorkbenchPreview
|
? imageWorkbenchPreview
|
||||||
: isSmartCutoutTool
|
: isSmartCutoutTool
|
||||||
? smartCutoutPreview
|
? smartCutoutPreview
|
||||||
: isQuickSetTool
|
: isQuickSetTool || isQuickDetailTool || isHotVideoTool
|
||||||
? quickProductSetPreview
|
? (
|
||||||
: isQuickDetailTool
|
<div className="ecom-quick-page-wrap">
|
||||||
? quickDetailPreview
|
{quickPageSidebar}
|
||||||
: isHotVideoTool
|
{isQuickSetTool ? quickProductSetPreview : isQuickDetailTool ? quickDetailPreview : hotVideoPreview}
|
||||||
? hotVideoPreview
|
</div>
|
||||||
|
)
|
||||||
: cloneOutput === "video-outfit" && results.length > 0 && results[0].type === "video"
|
: cloneOutput === "video-outfit" && results.length > 0 && results[0].type === "video"
|
||||||
? (
|
? (
|
||||||
<main className="product-clone-preview product-clone-preview--video-outfit" style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
|
<main className="product-clone-preview product-clone-preview--video-outfit" style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||||
@@ -6032,6 +6003,14 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
) : activePreview}
|
) : activePreview}
|
||||||
|
|
||||||
|
{quickPageTransition ? (
|
||||||
|
<div className="ecom-quick-page-transition" role="status" aria-live="polite">
|
||||||
|
<span aria-hidden="true" />
|
||||||
|
<strong>{quickPageTransition.title}</strong>
|
||||||
|
<em>{quickPageTransition.subtitle}</em>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside className="ecom-command-history" aria-label="生成历史">
|
<aside className="ecom-command-history" aria-label="生成历史">
|
||||||
|
|||||||
+622
-274
File diff suppressed because it is too large
Load Diff
@@ -579,6 +579,44 @@ textarea.image-workbench-prompt {
|
|||||||
background: rgba(var(--accent-rgb), 0.18) !important;
|
background: rgba(var(--accent-rgb), 0.18) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-workbench-page--image-tool .image-workbench-panel--left,
|
||||||
|
.watermark-removal-page .image-workbench-panel--left {
|
||||||
|
margin: 12px 0 12px 12px;
|
||||||
|
border: 1px solid rgba(var(--accent-rgb), 0.14);
|
||||||
|
border-radius: 12px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(var(--accent-rgb), 0.06), transparent 180px),
|
||||||
|
var(--bg-elevated);
|
||||||
|
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-workbench-page--image-tool .image-workbench-panel--left .image-workbench-control-card,
|
||||||
|
.watermark-removal-page .image-workbench-panel--left .image-workbench-control-card {
|
||||||
|
border-color: rgba(var(--accent-rgb), 0.14);
|
||||||
|
border-radius: 10px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent),
|
||||||
|
var(--bg-elevated);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-workbench-page--image-tool .image-workbench-panel--left .image-workbench-upload,
|
||||||
|
.watermark-removal-page .image-workbench-panel--left .image-workbench-upload,
|
||||||
|
.image-workbench-page--image-tool .image-workbench-panel--left :where(input, textarea, select),
|
||||||
|
.watermark-removal-page .image-workbench-panel--left :where(input, textarea, select) {
|
||||||
|
border-color: rgba(var(--accent-rgb), 0.18);
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(var(--accent-rgb), 0.035), transparent),
|
||||||
|
var(--bg-inset);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-workbench-page--image-tool .image-workbench-panel--left .image-workbench-actions,
|
||||||
|
.watermark-removal-page .image-workbench-panel--left .image-workbench-actions {
|
||||||
|
margin-top: 2px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid rgba(var(--accent-rgb), 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
.image-workbench-canvas {
|
.image-workbench-canvas {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user