refactor: optimize Topbar scroll listener; sync WIP ecommerce refactor and CSS
This commit is contained in:
+20
-26
@@ -39,38 +39,32 @@ export function Topbar({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let restoreTimer: number | undefined;
|
let restoreTimer: number | undefined;
|
||||||
let cleanupScrollTarget: (() => void) | undefined;
|
|
||||||
|
|
||||||
const bindScrollTarget = () => {
|
const handleScroll = (event: Event) => {
|
||||||
cleanupScrollTarget?.();
|
if (profileMenuOpen) return;
|
||||||
const target = document.querySelector<HTMLElement>(
|
const target = event.target;
|
||||||
".ecommerce-standalone__page--workspace:not([hidden]) .clone-ai-preview",
|
const activeWorkspace = document.querySelector<HTMLElement>(".ecommerce-standalone__page--workspace:not([hidden])");
|
||||||
);
|
if (!activeWorkspace) return;
|
||||||
if (!target) {
|
const isWorkspacePreviewScroll =
|
||||||
cleanupScrollTarget = undefined;
|
target instanceof HTMLElement && target.classList.contains("clone-ai-preview") && activeWorkspace.contains(target);
|
||||||
return;
|
const isPageScroll =
|
||||||
}
|
target === document ||
|
||||||
|
target === document.scrollingElement ||
|
||||||
|
target === document.documentElement ||
|
||||||
|
target === document.body;
|
||||||
|
if (!isWorkspacePreviewScroll && !isPageScroll) return;
|
||||||
|
|
||||||
const handleScroll = () => {
|
setIsTopbarHidden(true);
|
||||||
if (profileMenuOpen) return;
|
if (restoreTimer) window.clearTimeout(restoreTimer);
|
||||||
setIsTopbarHidden(true);
|
restoreTimer = window.setTimeout(() => {
|
||||||
if (restoreTimer) window.clearTimeout(restoreTimer);
|
setIsTopbarHidden(false);
|
||||||
restoreTimer = window.setTimeout(() => {
|
}, 240);
|
||||||
setIsTopbarHidden(false);
|
|
||||||
}, 240);
|
|
||||||
};
|
|
||||||
|
|
||||||
target.addEventListener("scroll", handleScroll, { passive: true });
|
|
||||||
cleanupScrollTarget = () => target.removeEventListener("scroll", handleScroll);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bindScrollTarget();
|
window.addEventListener("scroll", handleScroll, { capture: true, passive: true });
|
||||||
const observer = new MutationObserver(bindScrollTarget);
|
|
||||||
observer.observe(document.body, { attributes: true, childList: true, subtree: true });
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cleanupScrollTarget?.();
|
window.removeEventListener("scroll", handleScroll, { capture: true });
|
||||||
observer.disconnect();
|
|
||||||
if (restoreTimer) window.clearTimeout(restoreTimer);
|
if (restoreTimer) window.clearTimeout(restoreTimer);
|
||||||
};
|
};
|
||||||
}, [profileMenuOpen]);
|
}, [profileMenuOpen]);
|
||||||
|
|||||||
@@ -41,6 +41,35 @@ import EcommerceTryOnPanel from "./panels/EcommerceTryOnPanel";
|
|||||||
import EcommerceClonePanel from "./panels/EcommerceClonePanel";
|
import EcommerceClonePanel from "./panels/EcommerceClonePanel";
|
||||||
import { ecommerceOssScopes, saveUnifiedEcommerceGenerationRecord, deleteEcommerceGenerationRecord } from "./ecommerceGenerationPersistence";
|
import { ecommerceOssScopes, saveUnifiedEcommerceGenerationRecord, deleteEcommerceGenerationRecord } from "./ecommerceGenerationPersistence";
|
||||||
import { downloadResultAsset } from "../workbench/workbenchDownload";
|
import { downloadResultAsset } from "../workbench/workbenchDownload";
|
||||||
|
import {
|
||||||
|
formatRatioDisplayValue,
|
||||||
|
getQuickSetRatioValue,
|
||||||
|
getRatioDisplayParts,
|
||||||
|
normalizeRatioForApi,
|
||||||
|
normalizeRatioToken,
|
||||||
|
parseRatioToAspectCss,
|
||||||
|
quickSetRatioOptions,
|
||||||
|
} from "./utils/ratioUtils";
|
||||||
|
import {
|
||||||
|
defaultCloneOutput,
|
||||||
|
defaultEcommercePlatform,
|
||||||
|
defaultProductSetOutput,
|
||||||
|
formatUploadedImageRatio,
|
||||||
|
getPlatformDefaultLanguage,
|
||||||
|
getPlatformDefaultRatio,
|
||||||
|
getPlatformLanguageOptions,
|
||||||
|
getPlatformRatioOptions,
|
||||||
|
getUniqueRatioOptions,
|
||||||
|
marketLanguageOptions,
|
||||||
|
marketOptions,
|
||||||
|
normalizeLanguageForPlatform,
|
||||||
|
normalizeMarket,
|
||||||
|
normalizePlatform,
|
||||||
|
normalizeRatioForPlatform,
|
||||||
|
platformOptions,
|
||||||
|
type CloneOutputKey,
|
||||||
|
type ProductSetOutputKey,
|
||||||
|
} from "./utils/platformRules";
|
||||||
|
|
||||||
const smartCutoutColorPresets = [
|
const smartCutoutColorPresets = [
|
||||||
"#ffffff",
|
"#ffffff",
|
||||||
@@ -266,12 +295,11 @@ import {
|
|||||||
|
|
||||||
|
|
||||||
interface ProductClonePageProps {
|
interface ProductClonePageProps {
|
||||||
|
onWorkspaceChromeChange?: (state: { isToolPage: boolean }) => void;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductCloneStatus = "idle" | "ready" | "generating" | "done" | "failed";
|
type ProductCloneStatus = "idle" | "ready" | "generating" | "done" | "failed";
|
||||||
type ProductSetOutputKey = "set" | "detail" | "model" | "video";
|
|
||||||
type CloneOutputKey = ProductSetOutputKey | "hot";
|
|
||||||
type CloneSetCountKey = "selling" | "white" | "scene";
|
type CloneSetCountKey = "selling" | "white" | "scene";
|
||||||
type CloneModelPanelTab = "scene" | "model";
|
type CloneModelPanelTab = "scene" | "model";
|
||||||
type CloneVideoQualityKey = "standard" | "high" | "ultra";
|
type CloneVideoQualityKey = "standard" | "high" | "ultra";
|
||||||
@@ -429,13 +457,6 @@ interface EcommerceImagePromptOptions {
|
|||||||
detailModules?: string[];
|
detailModules?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlatformRatioModeKey = ProductSetOutputKey | "hot";
|
|
||||||
|
|
||||||
interface PlatformRatioGroup {
|
|
||||||
ratios: string[];
|
|
||||||
defaultRatio: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sideTools: Array<{ key: ProductKitToolKey; label: string; icon: ReactNode }> = [
|
const sideTools: Array<{ key: ProductKitToolKey; label: string; icon: ReactNode }> = [
|
||||||
{ key: "set", label: "商品套图", icon: <AppstoreOutlined /> },
|
{ key: "set", label: "商品套图", icon: <AppstoreOutlined /> },
|
||||||
{ key: "detail", label: "A+详情", icon: <FileImageOutlined /> },
|
{ key: "detail", label: "A+详情", icon: <FileImageOutlined /> },
|
||||||
@@ -443,324 +464,6 @@ const sideTools: Array<{ key: ProductKitToolKey; label: string; icon: ReactNode
|
|||||||
{ key: "clone", label: "电商AI作图", icon: <AppstoreOutlined /> },
|
{ key: "clone", label: "电商AI作图", icon: <AppstoreOutlined /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
const platformSpecOptions: Array<{
|
|
||||||
label: string;
|
|
||||||
ratios: string[];
|
|
||||||
defaultRatio: string;
|
|
||||||
ratioGroups?: Partial<Record<PlatformRatioModeKey, PlatformRatioGroup>>;
|
|
||||||
specs: string[];
|
|
||||||
tip?: string;
|
|
||||||
aliases?: string[];
|
|
||||||
}> = [
|
|
||||||
{
|
|
||||||
label: "淘宝/天猫",
|
|
||||||
ratios: ["淘宝主图 / SKU 图 800×800px", "详情页宽 750px", "详情页宽 790px"],
|
|
||||||
defaultRatio: "淘宝主图 / SKU 图 800×800px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1000×1000px\u00a0\u00a0\u00a01:1", "800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: [
|
|
||||||
"750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
"790×1053px\u00a0\u00a0\u00a03:4",
|
|
||||||
"750×1125px\u00a0\u00a0\u00a02:3",
|
|
||||||
"790×1185px\u00a0\u00a0\u00a02:3",
|
|
||||||
],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1080×1440px\u00a0\u00a0\u00a03:4", "1080×1080px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["主图 / SKU 图 800×800px,≤3MB", "详情页宽 750px 或 790px,单张高度≤1546px"],
|
|
||||||
tip: "建议主图 200-400KB JPG,超过 500KB 会影响加载速度。",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "京东",
|
|
||||||
ratios: ["京东主图 / SKU 图 800×800px", "详情页宽 750px", "首图主体占比 ≥80%"],
|
|
||||||
defaultRatio: "京东主图 / SKU 图 800×800px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1000×1000px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: [
|
|
||||||
"750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
"990×1320px\u00a0\u00a0\u00a03:4",
|
|
||||||
"750×1125px\u00a0\u00a0\u00a02:3",
|
|
||||||
"990×1485px\u00a0\u00a0\u00a02:3",
|
|
||||||
],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1125px\u00a0\u00a0\u00a02:3", "990×1485px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1920×1080px\u00a0\u00a0\u00a016:9"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["主图 / SKU 图 800×800px,白底,≤3MB", "详情页宽 750px,首图主体占比 ≥80%"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "拼多多",
|
|
||||||
ratios: ["主图 750×352px", "主图 800×800px", "详情页宽 750px"],
|
|
||||||
defaultRatio: "主图 750×352px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1", "750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["主图 750×352px 或 800×800px,≤1MB", "详情页宽 750px,要求纯白底、无水印、无拼接"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "抖音电商",
|
|
||||||
ratios: ["短视频1080×1920px"],
|
|
||||||
defaultRatio: "短视频1080×1920px",
|
|
||||||
ratioGroups: {
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["短视频 1080×1920px,9:16", "30s 内最佳"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "亚马逊 Amazon",
|
|
||||||
ratios: ["主图 ≥1600×1600px", "建议 2000×2000px+", "最小 500×500px"],
|
|
||||||
defaultRatio: "主图 ≥1600×1600px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["1600×1600px\u00a0\u00a0\u00a01:1", "1200×1800px\u00a0\u00a0\u00a02:3", "1200×1600px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "1200×1800px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["1200×1800px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "1200×1800px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1920×1080px\u00a0\u00a0\u00a016:9"],
|
|
||||||
defaultRatio: "1920×1080px\u00a0\u00a0\u00a016:9",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["主图 1600×1600px+,纯白底,≤10MB", "最小 500×500px,建议 2000px+ 以支持缩放"],
|
|
||||||
aliases: ["亚马逊"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Shopee",
|
|
||||||
ratios: ["商品主图 1024×1024px", "基础主图 800×800px"],
|
|
||||||
defaultRatio: "商品主图 1024×1024px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["商品主图推荐 1024×1024px,基础 800×800px", "≤2MB,白底或浅色底"],
|
|
||||||
aliases: ["虾皮 Shopee/Lazada", "虾皮"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Lazada",
|
|
||||||
ratios: ["商品主图 800×800px"],
|
|
||||||
defaultRatio: "商品主图 800×800px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["商品主图 800×800px,1:1"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Instagram",
|
|
||||||
ratios: ["帖子 1080×1350px", "帖子 1080×1080px", "Stories / Reels 1080×1920px", "头像 320×320px"],
|
|
||||||
defaultRatio: "帖子 1080×1350px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1080×1080px\u00a0\u00a0\u00a01:1", "1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1080px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["帖子 1080×1350px 或 1080×1080px", "Stories / Reels 封面 1080×1920px,头像 320×320px"],
|
|
||||||
tip: "建议 ≤8MB JPG。",
|
|
||||||
aliases: ["Instagram Reels"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "速卖通",
|
|
||||||
ratios: ["主图 800×800px", "主图 1000×1000px+"],
|
|
||||||
defaultRatio: "主图 800×800px",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1000×1000px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["750×1125px\u00a0\u00a0\u00a02:3", "750×1000px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["750×1125px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1920×1080px\u00a0\u00a0\u00a016:9"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["主图建议 800×800px 或更高,1:1", "适合跨境电商主图、SKU 图和场景图"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "eBay",
|
|
||||||
ratios: ["商品图1:1", "白底多角度展示图 1:1"],
|
|
||||||
defaultRatio: "商品图1:1",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["1000×1500px\u00a0\u00a0\u00a02:3", "1200×1600px\u00a0\u00a0\u00a03:4"],
|
|
||||||
defaultRatio: "1000×1500px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["1000×1500px\u00a0\u00a0\u00a02:3"],
|
|
||||||
defaultRatio: "1000×1500px\u00a0\u00a0\u00a02:3",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1920×1080px\u00a0\u00a0\u00a016:9", "1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1920×1080px\u00a0\u00a0\u00a016:9",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["商品图建议 1:1,主体清晰居中", "适合白底主图和多角度展示图"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "TikTok Shop",
|
|
||||||
ratios: ["商品主图 1:1", "短视频/ 竖版封面 9:16"],
|
|
||||||
defaultRatio: "商品主图 1:1",
|
|
||||||
ratioGroups: {
|
|
||||||
set: {
|
|
||||||
ratios: ["1280×1280px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "1280×1280px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
detail: {
|
|
||||||
ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"],
|
|
||||||
defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5",
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"],
|
|
||||||
defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16",
|
|
||||||
},
|
|
||||||
hot: {
|
|
||||||
ratios: ["800×800px\u00a0\u00a0\u00a01:1"],
|
|
||||||
defaultRatio: "800×800px\u00a0\u00a0\u00a01:1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ["商品主图建议 1:1", "短视频竖版封面建议 9:16"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const platformOptions = platformSpecOptions.map((option) => option.label);
|
|
||||||
const getPlatformLogoText = (value: string) => {
|
const getPlatformLogoText = (value: string) => {
|
||||||
const normalized = value.toLowerCase();
|
const normalized = value.toLowerCase();
|
||||||
if (value.includes("淘宝") || value.includes("天猫")) return "淘";
|
if (value.includes("淘宝") || value.includes("天猫")) return "淘";
|
||||||
@@ -811,223 +514,6 @@ const renderPlatformLogo = (value: string) => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const marketLanguageOptions: Array<{ country: string; languages: string[] }> = [
|
|
||||||
{ country: "中国", languages: ["中文"] },
|
|
||||||
{ country: "美国", languages: ["英文"] },
|
|
||||||
{ country: "加拿大", languages: ["英文", "法文"] },
|
|
||||||
{ country: "英国", languages: ["英文"] },
|
|
||||||
{ country: "德国", languages: ["德文"] },
|
|
||||||
{ country: "法国", languages: ["法文"] },
|
|
||||||
{ country: "意大利", languages: ["意大利语"] },
|
|
||||||
{ country: "西班牙", languages: ["西班牙语"] },
|
|
||||||
{ country: "日本", languages: ["日文"] },
|
|
||||||
{ country: "韩国", languages: ["韩文"] },
|
|
||||||
{ country: "澳大利亚", languages: ["英文"] },
|
|
||||||
{ country: "新加坡", languages: ["英文", "中文"] },
|
|
||||||
{ country: "马来西亚", languages: ["马来语", "英文", "中文"] },
|
|
||||||
{ country: "印尼", languages: ["印度尼西亚语", "英文"] },
|
|
||||||
{ country: "越南", languages: ["越南语", "英文"] },
|
|
||||||
{ country: "泰国", languages: ["泰语", "英文"] },
|
|
||||||
{ country: "菲律宾", languages: ["菲律宾语(他加禄语)", "英文"] },
|
|
||||||
{ country: "巴西", languages: ["葡萄牙语"] },
|
|
||||||
{ country: "墨西哥", languages: ["西班牙语"] },
|
|
||||||
{ country: "智利", languages: ["西班牙语"] },
|
|
||||||
{ country: "哥伦比亚", languages: ["西班牙语"] },
|
|
||||||
{ country: "阿联酋", languages: ["阿拉伯语", "英文"] },
|
|
||||||
{ country: "沙特阿拉伯", languages: ["阿拉伯语", "英文"] },
|
|
||||||
{ country: "俄罗斯", languages: ["俄语"] },
|
|
||||||
{ country: "波兰", languages: ["波兰语"] },
|
|
||||||
];
|
|
||||||
const marketOptions = marketLanguageOptions.map((option) => option.country);
|
|
||||||
const languageOptions = Array.from(new Set(marketLanguageOptions.flatMap((option) => option.languages)));
|
|
||||||
const languageAliases: Record<string, string> = {
|
|
||||||
"英文": "英文",
|
|
||||||
"中文": "中文",
|
|
||||||
"英语": "英文",
|
|
||||||
"日语": "日文",
|
|
||||||
"日文": "日文",
|
|
||||||
"德语": "德文",
|
|
||||||
"德文": "德文",
|
|
||||||
"法语": "法文",
|
|
||||||
"法文": "法文",
|
|
||||||
"韩语": "韩文",
|
|
||||||
"韩文": "韩文",
|
|
||||||
"西文": "西班牙语",
|
|
||||||
"西班牙语": "西班牙语",
|
|
||||||
"葡文": "葡萄牙语",
|
|
||||||
"葡萄牙语": "葡萄牙语",
|
|
||||||
"印尼语": "印度尼西亚语",
|
|
||||||
"印度尼西亚语": "印度尼西亚语",
|
|
||||||
"菲律宾语": "菲律宾语(他加禄语)",
|
|
||||||
"菲律宾语(他加禄语)": "菲律宾语(他加禄语)",
|
|
||||||
};
|
|
||||||
const defaultPlatformSpec = platformSpecOptions[0]!;
|
|
||||||
const getPlatformSpec = (value: string) =>
|
|
||||||
platformSpecOptions.find((option) => option.label === value || option.aliases?.includes(value)) ?? defaultPlatformSpec;
|
|
||||||
const legacyPlatformAliases: Record<string, string> = {
|
|
||||||
"淘宝/天猫": "淘宝/天猫",
|
|
||||||
"京东": "京东",
|
|
||||||
"拼多多": "拼多多",
|
|
||||||
"抖音电商": "抖音电商",
|
|
||||||
"亚马逊Amazon": "亚马逊 Amazon",
|
|
||||||
"速卖通": "速卖通",
|
|
||||||
};
|
|
||||||
const normalizePlatform = (value: string) => getPlatformSpec(legacyPlatformAliases[value] ?? value).label;
|
|
||||||
const domesticPlatformLabels = new Set(["淘宝/天猫", "京东", "拼多多", "抖音电商"]);
|
|
||||||
const domesticPlatformLanguages = ["中文"];
|
|
||||||
const isDomesticPlatform = (platformValue: string) => domesticPlatformLabels.has(normalizePlatform(platformValue));
|
|
||||||
const getPlatformRatioGroup = (value: string, mode?: PlatformRatioModeKey): PlatformRatioGroup => {
|
|
||||||
const platformSpec = getPlatformSpec(value);
|
|
||||||
return (mode ? platformSpec.ratioGroups?.[mode] : null) ?? {
|
|
||||||
ratios: platformSpec.ratios,
|
|
||||||
defaultRatio: platformSpec.defaultRatio,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const getPlatformRatioOptions = (value: string, mode?: PlatformRatioModeKey) => getPlatformRatioGroup(value, mode).ratios;
|
|
||||||
const getPlatformDefaultRatio = (value: string, mode?: PlatformRatioModeKey) => getPlatformRatioGroup(value, mode).defaultRatio;
|
|
||||||
const getUniqueRatioOptions = (ratios: string[]) => Array.from(new Set(ratios));
|
|
||||||
const normalizeRatioToken = (value: string) =>
|
|
||||||
value
|
|
||||||
.replaceAll("\u00a0", " ")
|
|
||||||
.replaceAll("脳", "×")
|
|
||||||
.replaceAll("*", "×")
|
|
||||||
.replaceAll(":", ":")
|
|
||||||
.replace(/锛\?/g, ":")
|
|
||||||
.replace(/\s+/g, " ")
|
|
||||||
.trim();
|
|
||||||
const normalizeRatioForPlatform = (platformValue: string, ratioValue: string, mode?: PlatformRatioModeKey) => {
|
|
||||||
const platformRatios = getPlatformRatioOptions(platformValue, mode);
|
|
||||||
if (platformRatios.includes(ratioValue)) return ratioValue;
|
|
||||||
const normalizedRatio = normalizeRatioToken(ratioValue);
|
|
||||||
const matchedRatio = platformRatios.find((option) => normalizeRatioToken(option).includes(normalizedRatio));
|
|
||||||
return matchedRatio ?? getPlatformDefaultRatio(platformValue, mode);
|
|
||||||
};
|
|
||||||
const quickSetRatioOptions = ["1:1", "3:4", "4:3", "9:16", "16:9"];
|
|
||||||
const getQuickSetRatioValue = (value: string) => {
|
|
||||||
const normalizedValue = normalizeRatioToken(value);
|
|
||||||
if (quickSetRatioOptions.includes(normalizedValue)) return normalizedValue;
|
|
||||||
const sizeMatch = normalizedValue.match(/(\d+)\s*[×xX]\s*(\d+)/u);
|
|
||||||
if (sizeMatch) {
|
|
||||||
const width = Number(sizeMatch[1]);
|
|
||||||
const height = Number(sizeMatch[2]);
|
|
||||||
if (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {
|
|
||||||
const aspect = formatAspectRatio(width, height);
|
|
||||||
if (quickSetRatioOptions.includes(aspect)) return aspect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const ratioMatch = normalizedValue.match(/(\d+)\s*[::]\s*(\d+)/u);
|
|
||||||
if (ratioMatch) {
|
|
||||||
const aspect = `${Number(ratioMatch[1])}:${Number(ratioMatch[2])}`;
|
|
||||||
if (quickSetRatioOptions.includes(aspect)) return aspect;
|
|
||||||
}
|
|
||||||
return quickSetRatioOptions[0]!;
|
|
||||||
};
|
|
||||||
const formatRatioDisplayValue = (value: string) => {
|
|
||||||
const normalizedValue = normalizeRatioToken(value);
|
|
||||||
const sizeMatch = normalizedValue.match(/(\d+)\s*[×xX]\s*(\d+)\s*px?/u);
|
|
||||||
if (sizeMatch) {
|
|
||||||
const width = Number(sizeMatch[1]);
|
|
||||||
const height = Number(sizeMatch[2]);
|
|
||||||
return `${width}×${height}px\u00a0\u00a0\u00a0${formatAspectRatio(width, height)}`;
|
|
||||||
}
|
|
||||||
return normalizedValue
|
|
||||||
.replace("淘宝主图 / SKU 图 ", "淘宝主图 / SKU 图 ")
|
|
||||||
.replace("京东主图 / SKU 图 ", "京东主图 / SKU 图 ")
|
|
||||||
.replace("详情页宽", "详情页宽")
|
|
||||||
.replace("短视频", "短视频")
|
|
||||||
.replace("主图", "主图")
|
|
||||||
.replace("商品主图", "商品主图")
|
|
||||||
.replace("鍟嗗搧鍥?", "商品图")
|
|
||||||
.replace(/\s+:/g, ":")
|
|
||||||
.replace(/:\s+/g, ":");
|
|
||||||
};
|
|
||||||
const getRatioDisplayParts = (value: string) => {
|
|
||||||
const display = formatRatioDisplayValue(value).replace(/\u00a0/g, " ").replace(/\s+/g, " ").trim();
|
|
||||||
const aspectMatch = display.match(/(\d+\s*[::]\s*\d+)(?!.*\d+\s*[::]\s*\d+)/u);
|
|
||||||
const aspect = aspectMatch?.[1]?.replace(/\s+/g, "") ?? "自适应";
|
|
||||||
const size = aspectMatch ? display.replace(aspectMatch[0], "").trim() : display;
|
|
||||||
return {
|
|
||||||
size: size || "原图比例",
|
|
||||||
aspect,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/** Extract CSS aspect-ratio from a ratio string like "1000x1000px 1:1" -> "1 / 1" */
|
|
||||||
const parseRatioToAspectCss = (ratioStr: string): string => {
|
|
||||||
const match = ratioStr.match(/(\d+)\D+(\d+)/u);
|
|
||||||
if (!match) return "1 / 1";
|
|
||||||
return `${match[1]} / ${match[2]}`;
|
|
||||||
};
|
|
||||||
const supportedImageApiRatios = ["1:1", "3:4", "4:3", "9:16", "16:9"] as const;
|
|
||||||
type SupportedImageApiRatio = typeof supportedImageApiRatios[number];
|
|
||||||
|
|
||||||
const toSupportedImageApiRatio = (width: number, height: number): SupportedImageApiRatio => {
|
|
||||||
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return "1:1";
|
|
||||||
let bestRatio: SupportedImageApiRatio = "1:1";
|
|
||||||
let bestScore = Number.POSITIVE_INFINITY;
|
|
||||||
const target = Math.log(width / height);
|
|
||||||
for (const ratio of supportedImageApiRatios) {
|
|
||||||
const [left, right] = ratio.split(":").map(Number);
|
|
||||||
const score = Math.abs(target - Math.log(left / right));
|
|
||||||
if (score < bestScore) {
|
|
||||||
bestRatio = ratio;
|
|
||||||
bestScore = score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bestRatio;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Normalize ratio display string ("1000×1000px 1:1") to an image API aspect ratio ("1:1"). */
|
|
||||||
const normalizeRatioForApi = (ratioStr: string): string => {
|
|
||||||
const normalizedValue = normalizeRatioToken(ratioStr);
|
|
||||||
const explicitRatios = Array.from(normalizedValue.matchAll(/(\d+(?:\.\d+)?)\s*:\s*(\d+(?:\.\d+)?)/g));
|
|
||||||
const explicitRatio = explicitRatios.at(-1);
|
|
||||||
if (explicitRatio) {
|
|
||||||
return toSupportedImageApiRatio(Number(explicitRatio[1]), Number(explicitRatio[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const sizeMatch = normalizedValue.match(/(\d+(?:\.\d+)?)\s*[×xX*]\s*(\d+(?:\.\d+)?)/u);
|
|
||||||
if (!sizeMatch) return "1:1";
|
|
||||||
return toSupportedImageApiRatio(Number(sizeMatch[1]), Number(sizeMatch[2]));
|
|
||||||
};
|
|
||||||
const greatestCommonDivisor = (left: number, right: number): number => {
|
|
||||||
let a = Math.abs(left);
|
|
||||||
let b = Math.abs(right);
|
|
||||||
while (b) {
|
|
||||||
[a, b] = [b, a % b];
|
|
||||||
}
|
|
||||||
return a || 1;
|
|
||||||
};
|
|
||||||
const formatAspectRatio = (width: number, height: number) => {
|
|
||||||
const divisor = greatestCommonDivisor(width, height);
|
|
||||||
return `${Math.round(width / divisor)}:${Math.round(height / divisor)}`;
|
|
||||||
};
|
|
||||||
const formatUploadedImageRatio = (image?: CloneImageItem) => {
|
|
||||||
if (!image) return null;
|
|
||||||
const format = image.format ? `\u00a0\u00a0\u00a0${image.format}` : "";
|
|
||||||
if (!image.width || !image.height) return `上传图片\u00a0\u00a0\u00a0原图比例${format}`;
|
|
||||||
return `上传图片 ${image.width}×${image.height}px\u00a0\u00a0\u00a0${formatAspectRatio(image.width, image.height)}${format}`;
|
|
||||||
};
|
|
||||||
const defaultMarketLanguageOption = marketLanguageOptions[0]!;
|
|
||||||
const normalizeMarket = (value: string) =>
|
|
||||||
marketLanguageOptions.some((option) => option.country === value) ? value : defaultMarketLanguageOption.country;
|
|
||||||
const normalizeLanguage = (value: string) => languageAliases[value] ?? value;
|
|
||||||
const uniqueLanguages = (languages: string[]) => Array.from(new Set(languages));
|
|
||||||
const appendEnglish = (languages: string[]) => Array.from(new Set([...languages, "英文"]));
|
|
||||||
const getMarketLanguageOptions = (marketValue: string) =>
|
|
||||||
appendEnglish((marketLanguageOptions.find((option) => option.country === marketValue) ?? defaultMarketLanguageOption).languages);
|
|
||||||
const getPlatformLanguageOptions = (platformValue: string, marketValue: string) => {
|
|
||||||
const marketLanguages = getMarketLanguageOptions(marketValue);
|
|
||||||
if (!isDomesticPlatform(platformValue)) return marketLanguages;
|
|
||||||
const localLanguages = marketLanguages.filter((item) => item !== "英文");
|
|
||||||
return uniqueLanguages([...localLanguages, ...domesticPlatformLanguages, "英文"]);
|
|
||||||
};
|
|
||||||
const getPlatformDefaultLanguage = (platformValue: string, marketValue: string) =>
|
|
||||||
isDomesticPlatform(platformValue) ? "中文" : (getPlatformLanguageOptions(platformValue, marketValue)[0] ?? languageOptions[0] ?? "英文");
|
|
||||||
const normalizeLanguageForPlatform = (platformValue: string, marketValue: string, languageValue: string) => {
|
|
||||||
const normalizedLanguage = normalizeLanguage(languageValue);
|
|
||||||
const platformLanguages = getPlatformLanguageOptions(platformValue, marketValue);
|
|
||||||
return platformLanguages.includes(normalizedLanguage) ? normalizedLanguage : getPlatformDefaultLanguage(platformValue, marketValue);
|
|
||||||
};
|
|
||||||
const productSetOutputOptions: Array<{ key: ProductSetOutputKey; label: string; desc: string; icon: ReactNode }> = [
|
const productSetOutputOptions: Array<{ key: ProductSetOutputKey; label: string; desc: string; icon: ReactNode }> = [
|
||||||
{ key: "set", label: "套图", desc: "主图/卖点/场景", icon: <AppstoreOutlined /> },
|
{ key: "set", label: "套图", desc: "主图/卖点/场景", icon: <AppstoreOutlined /> },
|
||||||
{ key: "detail", label: "详情图", desc: "长图模块化生成", icon: <LayoutOutlined /> },
|
{ key: "detail", label: "详情图", desc: "长图模块化生成", icon: <LayoutOutlined /> },
|
||||||
@@ -1164,9 +650,6 @@ const maxCloneProductImages = 20;
|
|||||||
const maxCloneReferenceImages = 20;
|
const maxCloneReferenceImages = 20;
|
||||||
const cloneVideoDurationMin = 5;
|
const cloneVideoDurationMin = 5;
|
||||||
const cloneVideoDurationMax = 45;
|
const cloneVideoDurationMax = 45;
|
||||||
const defaultEcommercePlatform = "淘宝/天猫";
|
|
||||||
const defaultProductSetOutput: ProductSetOutputKey = "set";
|
|
||||||
const defaultCloneOutput: CloneOutputKey = "set";
|
|
||||||
const cloneLatestSettingStorageKey = "omniai.clone-ai.latest-setting";
|
const cloneLatestSettingStorageKey = "omniai.clone-ai.latest-setting";
|
||||||
const ecommerceHistoryStorageKey = "omniai.ecommerce.history.records";
|
const ecommerceHistoryStorageKey = "omniai.ecommerce.history.records";
|
||||||
const cloneVideoQualityOptions: Array<{ key: CloneVideoQualityKey; label: string; desc: string }> = [
|
const cloneVideoQualityOptions: Array<{ key: CloneVideoQualityKey; label: string; desc: string }> = [
|
||||||
@@ -1594,6 +1077,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
const countHoldTimeoutRef = useRef<number | null>(null);
|
const countHoldTimeoutRef = useRef<number | null>(null);
|
||||||
const countHoldIntervalRef = useRef<number | null>(null);
|
const countHoldIntervalRef = useRef<number | null>(null);
|
||||||
const isAuthenticated = Boolean((_props as Record<string, unknown>).isAuthenticated);
|
const isAuthenticated = Boolean((_props as Record<string, unknown>).isAuthenticated);
|
||||||
|
const onWorkspaceChromeChange = _props.onWorkspaceChromeChange;
|
||||||
const requestLogin = () => {
|
const requestLogin = () => {
|
||||||
const handler = (_props as Record<string, unknown>).onRequireLogin;
|
const handler = (_props as Record<string, unknown>).onRequireLogin;
|
||||||
if (typeof handler === "function") handler();
|
if (typeof handler === "function") handler();
|
||||||
@@ -1625,6 +1109,16 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
const [showHostingModal, setShowHostingModal] = useState(false);
|
const [showHostingModal, setShowHostingModal] = useState(false);
|
||||||
const [productImages, setProductImages] = useState<CloneImageItem[]>([]);
|
const [productImages, setProductImages] = useState<CloneImageItem[]>([]);
|
||||||
const [activeQuickTool, setActiveQuickTool] = useState<"cutout" | "detail" | "watermark" | "image-edit" | "translate" | "hot" | null>(null);
|
const [activeQuickTool, setActiveQuickTool] = useState<"cutout" | "detail" | "watermark" | "image-edit" | "translate" | "hot" | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
const handleWorkspaceHome = () => {
|
||||||
|
setActiveTool("clone");
|
||||||
|
setActiveQuickTool(null);
|
||||||
|
setActiveHistoryRecordId(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("ecommerce-workspace-home", handleWorkspaceHome);
|
||||||
|
return () => window.removeEventListener("ecommerce-workspace-home", handleWorkspaceHome);
|
||||||
|
}, []);
|
||||||
const [smartCutoutImage, setSmartCutoutImage] = useState<SmartCutoutImageItem | null>(null);
|
const [smartCutoutImage, setSmartCutoutImage] = useState<SmartCutoutImageItem | null>(null);
|
||||||
const [smartCutoutBatchImages, setSmartCutoutBatchImages] = useState<SmartCutoutImageItem[]>([]);
|
const [smartCutoutBatchImages, setSmartCutoutBatchImages] = useState<SmartCutoutImageItem[]>([]);
|
||||||
const [smartCutoutBackgroundColor, setSmartCutoutBackgroundColor] = useState("#ffffff");
|
const [smartCutoutBackgroundColor, setSmartCutoutBackgroundColor] = useState("#ffffff");
|
||||||
@@ -7716,6 +7210,20 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
|||||||
const isRecordDetailWorkspace = isMainCloneWorkspace && Boolean(activeHistoryRecordId);
|
const isRecordDetailWorkspace = isMainCloneWorkspace && Boolean(activeHistoryRecordId);
|
||||||
const currentResultCount = canvasNodes.reduce((count, node) => count + node.results.length, 0);
|
const currentResultCount = canvasNodes.reduce((count, node) => count + node.results.length, 0);
|
||||||
const activeHistoryRecord = activeHistoryRecordId ? ecommerceHistoryRecords.find((record) => record.id === activeHistoryRecordId) : null;
|
const activeHistoryRecord = activeHistoryRecordId ? ecommerceHistoryRecords.find((record) => record.id === activeHistoryRecordId) : null;
|
||||||
|
const isFocusedToolPage =
|
||||||
|
isRecordDetailWorkspace || isSmartCutoutTool || isQuickDetailTool || isWatermarkTool || isTranslateTool || isImageEditTool || isHotCloneTool;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onWorkspaceChromeChange?.({
|
||||||
|
isToolPage: isFocusedToolPage,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
onWorkspaceChromeChange?.({
|
||||||
|
isToolPage: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [isFocusedToolPage, onWorkspaceChromeChange]);
|
||||||
const activeConversationTurns = activeHistoryRecord
|
const activeConversationTurns = activeHistoryRecord
|
||||||
? activeHistoryRecord.turns?.length
|
? activeHistoryRecord.turns?.length
|
||||||
? activeHistoryRecord.turns
|
? activeHistoryRecord.turns
|
||||||
|
|||||||
@@ -17418,21 +17418,24 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
|||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar {
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar {
|
||||||
border-bottom: none !important;
|
border-bottom: none !important;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
background-image: none !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
backdrop-filter: none !important;
|
backdrop-filter: none !important;
|
||||||
-webkit-backdrop-filter: none !important;
|
-webkit-backdrop-filter: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar::before,
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar::after {
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar::after {
|
||||||
content: none !important;
|
content: none !important;
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep topbar transparent and remove any background/border from inner controls. */
|
/* Keep topbar transparent and remove any background/border from inner controls. */
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand,
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand,
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand strong,
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand strong,
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__credits,
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__credits,
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__account button,
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__account button:not(.ecommerce-standalone__login-button):not(.ecommerce-profile-menu__trigger) {
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger {
|
|
||||||
color: #10202c !important;
|
color: #10202c !important;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
@@ -17444,6 +17447,487 @@ html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecomm
|
|||||||
-webkit-backdrop-filter: none !important;
|
-webkit-backdrop-filter: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand:hover,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__account button:not(.ecommerce-standalone__login-button):not(.ecommerce-profile-menu__trigger):hover {
|
||||||
|
background: transparent !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
background-image: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__credits {
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__credits {
|
||||||
color: #3a5a6a !important;
|
color: #3a5a6a !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Topbar composition: quiet brand chip + single account capsule. */
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar {
|
||||||
|
padding: 14px clamp(18px, 2.5vw, 30px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] {
|
||||||
|
--ecommerce-workspace-top-offset: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand {
|
||||||
|
gap: 10px !important;
|
||||||
|
min-height: 42px !important;
|
||||||
|
padding: 5px 12px 5px 6px !important;
|
||||||
|
border: 1px solid rgba(30, 189, 219, 0.16) !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
background: rgba(255, 255, 255, 0.62) !important;
|
||||||
|
box-shadow: 0 12px 34px rgba(16, 115, 204, 0.07) !important;
|
||||||
|
backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
-webkit-backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
transition: border-color 180ms ease, box-shadow 180ms ease, transform 180ms ease, background 180ms ease !important;
|
||||||
|
will-change: opacity, transform, filter !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand:hover {
|
||||||
|
border-color: rgba(30, 189, 219, 0.28) !important;
|
||||||
|
background: rgba(255, 255, 255, 0.78) !important;
|
||||||
|
box-shadow: 0 16px 42px rgba(16, 115, 204, 0.1) !important;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__logo {
|
||||||
|
width: 34px !important;
|
||||||
|
height: 34px !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
box-shadow: 0 8px 18px rgba(16, 115, 204, 0.16) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand strong {
|
||||||
|
max-width: 168px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
color: #10202c !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
line-height: 1 !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu {
|
||||||
|
position: relative !important;
|
||||||
|
gap: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger {
|
||||||
|
gap: 10px !important;
|
||||||
|
min-height: 46px !important;
|
||||||
|
padding: 4px 6px 4px 14px !important;
|
||||||
|
border: 1px solid rgba(30, 189, 219, 0.16) !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
background: rgba(255, 255, 255, 0.66) !important;
|
||||||
|
box-shadow: 0 12px 34px rgba(16, 115, 204, 0.08) !important;
|
||||||
|
backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
-webkit-backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
transition: border-color 180ms ease, box-shadow 180ms ease, transform 180ms ease, background 180ms ease !important;
|
||||||
|
will-change: opacity, transform, filter !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="true"] .ecommerce-standalone__brand,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="true"] .ecommerce-profile-menu__trigger,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="true"] .ecommerce-standalone__login-button {
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
filter: blur(4px) saturate(0.96) !important;
|
||||||
|
transform: translateY(-14px) scale(0.96) !important;
|
||||||
|
transition:
|
||||||
|
opacity 160ms ease,
|
||||||
|
transform 190ms cubic-bezier(0.4, 0, 1, 1),
|
||||||
|
filter 160ms ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="false"] .ecommerce-standalone__brand,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="false"] .ecommerce-profile-menu__trigger,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__topbar[data-scroll-hidden="false"] .ecommerce-standalone__login-button {
|
||||||
|
opacity: 1 !important;
|
||||||
|
filter: blur(0) saturate(1) !important;
|
||||||
|
transform: translateY(0) scale(1) !important;
|
||||||
|
transition:
|
||||||
|
opacity 260ms ease 40ms,
|
||||||
|
transform 360ms cubic-bezier(0.16, 1, 0.3, 1) 40ms,
|
||||||
|
filter 260ms ease 40ms,
|
||||||
|
border-color 180ms ease,
|
||||||
|
box-shadow 180ms ease,
|
||||||
|
background 180ms ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger:hover,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger[aria-expanded="true"] {
|
||||||
|
border-color: rgba(30, 189, 219, 0.3) !important;
|
||||||
|
background: rgba(255, 255, 255, 0.82) !important;
|
||||||
|
box-shadow: 0 16px 42px rgba(16, 115, 204, 0.12) !important;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger .ecommerce-standalone__credits {
|
||||||
|
min-height: auto !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: 0 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
color: #3a5a6a !important;
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
letter-spacing: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__name {
|
||||||
|
max-width: 82px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
color: #10202c !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger .local-user-avatar--sm {
|
||||||
|
width: 34px !important;
|
||||||
|
height: 34px !important;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.86) !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(30, 189, 219, 0.22),
|
||||||
|
0 8px 18px rgba(16, 115, 204, 0.16) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__brand strong,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__name {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-profile-menu__trigger {
|
||||||
|
padding-left: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__account button.ecommerce-standalone__login-button {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
min-height: 40px !important;
|
||||||
|
padding: 0 16px !important;
|
||||||
|
border: 1px solid rgba(30, 189, 219, 0.22) !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
color: #10202c !important;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(241, 250, 252, 0.82)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 10px 26px rgba(16, 115, 204, 0.08),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.92) !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__account button.ecommerce-standalone__login-button:hover {
|
||||||
|
border-color: rgba(30, 189, 219, 0.38) !important;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(232, 250, 253, 0.9)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 14px 32px rgba(30, 189, 219, 0.14),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.96) !important;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the workspace surface paint behind the transparent fixed topbar. */
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__content {
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
height: 100dvh !important;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--profile {
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
height: 100dvh !important;
|
||||||
|
padding-top: var(--ecommerce-topbar-height) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-shell,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-preview.clone-ai-preview {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-preview.clone-ai-preview:has(.ecom-inspiration-lab) {
|
||||||
|
padding-top: calc(var(--ecommerce-topbar-height) + var(--ecommerce-workspace-top-offset, 50px) + clamp(18px, 2.5vh, 30px)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__toggle.ecom-command-history__toggle {
|
||||||
|
top: calc(var(--ecommerce-topbar-height) + 12px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__toggle.ecom-command-history__toggle:hover {
|
||||||
|
transform: translateY(-2px) scale(1.035) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history.ecom-command-history {
|
||||||
|
top: calc(var(--ecommerce-topbar-height) + 18px) !important;
|
||||||
|
right: 18px !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
height: calc(100dvh - var(--ecommerce-topbar-height) - 42px) !important;
|
||||||
|
width: min(316px, calc(100vw - 72px)) !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
border: 1px solid rgba(30, 189, 219, 0.2) !important;
|
||||||
|
border-radius: 24px !important;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(238, 250, 253, 0.82)) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 24px 68px rgba(16, 115, 204, 0.16),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.9) !important;
|
||||||
|
backdrop-filter: blur(22px) saturate(1.12) !important;
|
||||||
|
-webkit-backdrop-filter: blur(22px) saturate(1.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history.ecom-command-history {
|
||||||
|
top: calc(var(--ecommerce-topbar-height) + 12px) !important;
|
||||||
|
right: 18px !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
width: 42px !important;
|
||||||
|
height: 42px !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
border: 0 !important;
|
||||||
|
border-radius: 15px !important;
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
transform: none !important;
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
-webkit-backdrop-filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__tools {
|
||||||
|
padding: 14px 14px 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__heading {
|
||||||
|
padding-inline: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__list {
|
||||||
|
padding: 10px 12px 16px !important;
|
||||||
|
overflow: hidden auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__toggle.ecom-command-history__toggle {
|
||||||
|
position: relative !important;
|
||||||
|
top: auto !important;
|
||||||
|
right: auto !important;
|
||||||
|
left: auto !important;
|
||||||
|
z-index: 130 !important;
|
||||||
|
width: 42px !important;
|
||||||
|
height: 42px !important;
|
||||||
|
min-height: 42px !important;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__tools {
|
||||||
|
display: block !important;
|
||||||
|
width: 42px !important;
|
||||||
|
height: 42px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History overlay final behavior: panel floats above the workspace and never reserves layout space. */
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] {
|
||||||
|
--ecom-history-offset: 0px !important;
|
||||||
|
--ecom-history-panel-width: 0px !important;
|
||||||
|
--history-detail-workspace-width: 100vw !important;
|
||||||
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] > .product-clone-shell.product-clone-shell {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: none !important;
|
||||||
|
padding-right: 0 !important;
|
||||||
|
filter: none !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
transform: none !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
user-select: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .product-clone-preview.clone-ai-preview {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-detail .ecom-command-composer-wrap.has-generated.is-compact {
|
||||||
|
left: 50vw !important;
|
||||||
|
width: min(760px, calc(100vw - clamp(48px, 8vw, 96px))) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-detail .clone-ai-canvas-node:not(.is-generating) {
|
||||||
|
max-width: min(860px, calc(100vw - 80px)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__backdrop {
|
||||||
|
background: rgba(16, 38, 56, 0.08) !important;
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
-webkit-backdrop-filter: none !important;
|
||||||
|
animation: ecommerce-soft-scrim-in 180ms ease-out both !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history.ecom-command-history {
|
||||||
|
position: fixed !important;
|
||||||
|
z-index: 130 !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
transform: translateX(0) scale(1) !important;
|
||||||
|
transform-origin: top right !important;
|
||||||
|
transition:
|
||||||
|
opacity 240ms ease,
|
||||||
|
top 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
||||||
|
width 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
||||||
|
height 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
||||||
|
border-radius 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
||||||
|
border-color 220ms ease,
|
||||||
|
background 220ms ease,
|
||||||
|
transform 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
||||||
|
box-shadow 260ms ease !important;
|
||||||
|
will-change: opacity, transform !important;
|
||||||
|
animation: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history.ecom-command-history {
|
||||||
|
opacity: 1 !important;
|
||||||
|
transform: translateX(0) scale(1) !important;
|
||||||
|
animation: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__tools,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__new,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__refresh,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__heading,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__refresh-note,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-history__list {
|
||||||
|
transition:
|
||||||
|
opacity 220ms ease,
|
||||||
|
transform 360ms cubic-bezier(0.34, 0, 0.22, 1),
|
||||||
|
visibility 0s linear 220ms !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__tools,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__new,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__refresh,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__heading,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__refresh-note,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"]:not(.is-history-collapsed) .ecom-command-history__list {
|
||||||
|
opacity: 1 !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
transform: translateY(0) !important;
|
||||||
|
transition:
|
||||||
|
opacity 180ms ease 90ms,
|
||||||
|
transform 280ms cubic-bezier(0.22, 0.61, 0.36, 1) 70ms,
|
||||||
|
visibility 0s linear 0s !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__new,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__refresh,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__heading,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__refresh-note,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"][data-tool="clone"].is-history-collapsed .ecom-command-history__list {
|
||||||
|
opacity: 0 !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
transform: translateY(6px) !important;
|
||||||
|
transition:
|
||||||
|
opacity 160ms ease,
|
||||||
|
transform 220ms ease,
|
||||||
|
visibility 0s linear 160ms !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ecom-history-panel-enter {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(26px) scale(0.975);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focused tool page sample: the inner tool header owns navigation, so the global brand steps away. */
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__brand {
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
filter: blur(4px) saturate(0.96) !important;
|
||||||
|
transform: translateY(-10px) scale(0.96) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__topbar[data-scroll-hidden] .ecommerce-standalone__brand {
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
filter: blur(4px) saturate(0.96) !important;
|
||||||
|
transform: translateY(-10px) scale(0.96) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__topbar {
|
||||||
|
padding-inline: clamp(16px, 2vw, 24px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"].is-quick-set-page .ecom-quick-set-page,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-set-page,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"].is-image-workbench-page .ecom-image-workbench-page,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"].is-watermark-page .ecom-watermark-page,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .product-clone-page[data-tool="clone"].is-translate-page .ecom-translate-page {
|
||||||
|
padding-top: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-quick-set-panel,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-image-workbench-side,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-watermark-side,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-translate-side {
|
||||||
|
border-radius: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-quick-set-panel-head,
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-image-workbench-panel-head {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto auto !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 8px !important;
|
||||||
|
min-height: 48px !important;
|
||||||
|
margin: -18px -16px 10px !important;
|
||||||
|
padding: 12px 12px 10px 16px !important;
|
||||||
|
border-bottom: 1px solid rgba(16, 115, 204, 0.08) !important;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(248, 252, 254, 0.9)) !important;
|
||||||
|
box-shadow: 0 10px 28px rgba(16, 115, 204, 0.05) !important;
|
||||||
|
backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
-webkit-backdrop-filter: blur(18px) saturate(1.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-quick-set-page-title {
|
||||||
|
min-width: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
color: #10202c !important;
|
||||||
|
font-size: 18px !important;
|
||||||
|
font-weight: 950 !important;
|
||||||
|
line-height: 1.1 !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-quick-set-back {
|
||||||
|
min-width: 58px !important;
|
||||||
|
min-height: 32px !important;
|
||||||
|
padding: 0 12px !important;
|
||||||
|
border: 1px solid rgba(16, 115, 204, 0.12) !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
color: #526474 !important;
|
||||||
|
background: rgba(255, 255, 255, 0.78) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 850 !important;
|
||||||
|
letter-spacing: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html body #root div.ecommerce-standalone.web-shell[data-view="ecommerce"][data-workspace-tool-page="true"] .ecommerce-standalone__page--workspace .ecom-quick-set-back:hover {
|
||||||
|
border-color: rgba(30, 189, 219, 0.34) !important;
|
||||||
|
color: #1073cc !important;
|
||||||
|
background: rgba(232, 249, 253, 0.92) !important;
|
||||||
|
transform: translateY(-1px) !important;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user