Polish ecommerce tool page layouts
This commit is contained in:
@@ -2137,10 +2137,19 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
|
||||
const openHotVideoPage = () => {
|
||||
clearSmartCutoutTransition();
|
||||
setActiveQuickTool("hot-video");
|
||||
setComposerMenu(null);
|
||||
setIsCloneSettingsCollapsed(true);
|
||||
setIsCommandHistoryCollapsed(true);
|
||||
clearQuickPageTransition();
|
||||
runQuickPageTransition(
|
||||
{ title: "正在进入广告视频", subtitle: "AI智能策划 · 一键生成电商短视频" },
|
||||
() => {
|
||||
setActiveQuickTool("hot-video");
|
||||
setComposerMenu(null);
|
||||
setIsCloneSettingsCollapsed(true);
|
||||
setIsCommandHistoryCollapsed(true);
|
||||
setPreviewZoom(1);
|
||||
setRatio("9:16");
|
||||
resetQuickSetSelectState();
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const closeHotVideoPage = () => {
|
||||
@@ -4949,16 +4958,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
className="ecom-command-hidden-file"
|
||||
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">
|
||||
<div className="ecom-image-workbench-heading">
|
||||
<span>图片修改</span>
|
||||
<strong>图片修改</strong>
|
||||
<p>涂抹需要修改的区域,输入提示词后让 AI 替换局部内容。</p>
|
||||
</div>
|
||||
<header className="ecom-quick-set-panel-head ecom-image-workbench-panel-head">
|
||||
<strong className="ecom-quick-set-page-title">图片修改</strong>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeImageWorkbenchPage}>首页</button>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeImageWorkbenchPage}>上一页</button>
|
||||
</header>
|
||||
<p className="ecom-image-workbench-intro">涂抹需要修改的区域,输入提示词后让 AI 替换局部内容。</p>
|
||||
|
||||
<section className="ecom-image-workbench-panel">
|
||||
<header>
|
||||
@@ -5157,16 +5163,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
className="ecom-command-hidden-file"
|
||||
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">
|
||||
<div className="ecom-watermark-heading">
|
||||
<span>AI 电商工具</span>
|
||||
<strong>增/去水印</strong>
|
||||
<p>上传商品素材,快速清理画面中的水印、文字和瑕疵。</p>
|
||||
</div>
|
||||
<header className="ecom-quick-set-panel-head ecom-watermark-panel-head">
|
||||
<strong className="ecom-quick-set-page-title">增/去水印</strong>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeWatermarkRemovalPage}>首页</button>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeWatermarkRemovalPage}>上一页</button>
|
||||
</header>
|
||||
<p className="ecom-watermark-intro">上传商品素材,快速清理画面中的水印、文字和瑕疵。</p>
|
||||
<section className="ecom-watermark-panel">
|
||||
<header>
|
||||
<strong>上传素材</strong>
|
||||
@@ -5347,46 +5350,35 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
);
|
||||
|
||||
const hotVideoPreview = (
|
||||
<main className="ecom-hot-video-page" aria-label="广告视频">
|
||||
<nav className="ecom-hot-video-nav">
|
||||
<button type="button" className="ecom-hot-video-back" onClick={closeHotVideoPage}>
|
||||
‹ 返回首页
|
||||
</button>
|
||||
<div className="ecom-hot-video-nav-title">
|
||||
<h1>广告视频</h1>
|
||||
<span>AI智能策划 · 一键生成电商短视频</span>
|
||||
</div>
|
||||
<div className="ecom-hot-video-nav-meta">
|
||||
<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>
|
||||
<main className="ecom-quick-set-page ecom-hot-video-page" aria-label="广告视频">
|
||||
<div className="ecom-quick-set-body">
|
||||
<aside className="ecom-quick-set-panel" aria-label="广告视频设置">
|
||||
<header className="ecom-quick-set-panel-head">
|
||||
<strong className="ecom-quick-set-page-title">广告视频</strong>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeHotVideoPage}>首页</button>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeHotVideoPage}>上一页</button>
|
||||
</header>
|
||||
<section>
|
||||
<strong><CloudUploadOutlined /> 上传商品图</strong>
|
||||
<div
|
||||
role="button"
|
||||
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()}
|
||||
onKeyDown={(event) => { if (event.key === "Enter" || event.key === " ") quickProductInputRef.current?.click(); }}
|
||||
onDragOver={(event) => { event.preventDefault(); setIsProductUploadDragging(true); }}
|
||||
onDragLeave={(event) => { event.preventDefault(); setIsProductUploadDragging(false); }}
|
||||
onDrop={handleProductDrop}
|
||||
>
|
||||
<CloudUploadOutlined />
|
||||
<span>拖拽或点击上传商品图片</span>
|
||||
<em>支持 JPG / PNG / WebP,建议清晰白底图</em>
|
||||
<FileImageOutlined />
|
||||
<span>拖拽或点击上传</span>
|
||||
<em>支持 JPG / PNG / WebP</em>
|
||||
<b>+ 上传图片</b>
|
||||
{productImages.length > 0 ? (
|
||||
<div className="ecom-hot-video-upload-thumbs">
|
||||
<div className="ecom-quick-upload-thumbs">
|
||||
{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} />
|
||||
<button
|
||||
type="button"
|
||||
aria-label="删除"
|
||||
onClick={(event) => { event.stopPropagation(); removeProductImage(img.id); }}
|
||||
>×</button>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
@@ -5401,8 +5393,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
onChange={handleProductUpload}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="ecom-hot-video-section">
|
||||
<section>
|
||||
<strong>商品描述</strong>
|
||||
<textarea
|
||||
className="ecom-hot-video-textarea"
|
||||
@@ -5413,41 +5404,16 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
maxLength={500}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="ecom-hot-video-section">
|
||||
<strong>电商平台</strong>
|
||||
<div className="ecom-hot-video-options">
|
||||
{platformOptions.map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
type="button"
|
||||
className={platform === option ? "is-active" : ""}
|
||||
onClick={() => setPlatform(option)}
|
||||
>
|
||||
{renderPlatformLogo(option)}
|
||||
<span>{option}</span>
|
||||
</button>
|
||||
))}
|
||||
<section className="ecom-quick-set-basic-section">
|
||||
<span className="ecom-quick-set-label">基础设置</span>
|
||||
<div className="ecom-quick-set-select-anchor">
|
||||
<div className="ecom-quick-set-selects">
|
||||
<button type="button"><span>平台</span><strong>{platform}</strong></button>
|
||||
<button type="button"><span>比例</span><strong>{ratio}</strong></button>
|
||||
</div>
|
||||
</div>
|
||||
</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">
|
||||
<section>
|
||||
<strong>视频质量</strong>
|
||||
<div className="ecom-hot-video-options">
|
||||
{cloneVideoQualityOptions.map((option) => (
|
||||
@@ -5463,8 +5429,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="ecom-hot-video-section">
|
||||
<section>
|
||||
<strong>视频时长 · {cloneVideoDuration}秒</strong>
|
||||
<input
|
||||
type="range"
|
||||
@@ -5481,24 +5446,23 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
<span>{cloneVideoDurationMax}秒</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="ecom-hot-video-start"
|
||||
className="ecom-quick-set-primary"
|
||||
disabled={!productImages.length && !requirement.trim()}
|
||||
onClick={() => setVideoPlanTrigger((prev) => prev + 1)}
|
||||
>
|
||||
一键策划
|
||||
✦ 一键策划
|
||||
</button>
|
||||
</aside>
|
||||
<section className="ecom-hot-video-workspace">
|
||||
<section className="ecom-quick-set-stage">
|
||||
<EcommerceVideoWorkspace
|
||||
isAuthenticated={isAuthenticated}
|
||||
productImageDataUrls={ecommerceVideoImageDataUrls}
|
||||
productImageFiles={ecommerceVideoImageFiles}
|
||||
requirement={requirement}
|
||||
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}
|
||||
resolution={cloneVideoQuality === "standard" ? "720P" : "1080P"}
|
||||
onRequestLogin={() => (isAuthenticated ? undefined : requestLogin())}
|
||||
@@ -5606,8 +5570,11 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
</div>
|
||||
</section>
|
||||
<button type="button" className="ecom-quick-set-primary" onClick={handleGenerate} disabled={!canGenerate}>
|
||||
✦ 开始生成
|
||||
{status === "generating" ? <LoadingOutlined /> : "✦"} {status === "generating" ? "正在生成..." : "开始生成"}
|
||||
</button>
|
||||
{status === "generating" ? (
|
||||
<button type="button" className="ecom-quick-set-primary ecom-quick-set-primary--cancel" onClick={handleCancelGenerate}>取消生成</button>
|
||||
) : null}
|
||||
</aside>
|
||||
<section className="ecom-quick-set-stage">
|
||||
<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}>
|
||||
{detailStatus === "generating" ? <LoadingOutlined /> : "✦"} 开始生成
|
||||
</button>
|
||||
{detailStatus === "generating" ? (
|
||||
<button type="button" className="ecom-quick-set-primary ecom-quick-set-primary--cancel" onClick={handleCancelGenerate}>取消生成</button>
|
||||
) : null}
|
||||
</aside>
|
||||
<section className="ecom-quick-set-stage">
|
||||
<header className="ecom-quick-set-preview-head">
|
||||
@@ -5958,12 +5928,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
? imageWorkbenchPreview
|
||||
: isSmartCutoutTool
|
||||
? smartCutoutPreview
|
||||
: isQuickSetTool
|
||||
? quickProductSetPreview
|
||||
: isQuickDetailTool
|
||||
? quickDetailPreview
|
||||
: isHotVideoTool
|
||||
? hotVideoPreview
|
||||
: isQuickSetTool || isQuickDetailTool || isHotVideoTool
|
||||
? (
|
||||
<div className="ecom-quick-page-wrap">
|
||||
{quickPageSidebar}
|
||||
{isQuickSetTool ? quickProductSetPreview : isQuickDetailTool ? quickDetailPreview : hotVideoPreview}
|
||||
</div>
|
||||
)
|
||||
: 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" }}>
|
||||
@@ -6032,6 +6003,14 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
/>
|
||||
</main>
|
||||
) : 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>
|
||||
|
||||
<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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user