Merge branch 'main-merge-work' of ssh://118.145.251.184-port2222/OmniAI/omniai-ds-code-package into main-merge-work
This commit is contained in:
@@ -41,35 +41,6 @@ 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",
|
||||||
@@ -295,7 +266,6 @@ import {
|
|||||||
|
|
||||||
|
|
||||||
interface ProductClonePageProps {
|
interface ProductClonePageProps {
|
||||||
onWorkspaceChromeChange?: (state: { isToolPage: boolean }) => void;
|
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,6 +434,13 @@ 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 /> },
|
||||||
@@ -471,6 +448,324 @@ 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 "淘";
|
||||||
@@ -521,6 +816,223 @@ 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 /> },
|
||||||
@@ -738,6 +1250,9 @@ 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 }> = [
|
||||||
@@ -1165,7 +1680,6 @@ 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();
|
||||||
@@ -1197,16 +1711,6 @@ 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");
|
||||||
@@ -7326,20 +7830,6 @@ 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
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ecommerce-standalone__topbar {
|
.ecommerce-standalone__topbar {
|
||||||
position: relative;
|
position: fixed;
|
||||||
|
inset: 0 0 auto;
|
||||||
|
z-index: 80;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -20,7 +22,8 @@
|
|||||||
min-height: 64px;
|
min-height: 64px;
|
||||||
padding: 10px clamp(16px, 3vw, 32px);
|
padding: 10px clamp(16px, 3vw, 32px);
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
background: transparent;
|
background: rgba(8, 12, 10, 0.78);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ecommerce-standalone__brand,
|
.ecommerce-standalone__brand,
|
||||||
@@ -63,6 +66,7 @@
|
|||||||
|
|
||||||
.ecommerce-standalone__content {
|
.ecommerce-standalone__content {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
padding-top: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 工作台与个人中心常驻同层,用 hidden 切换以保活生成任务状态。
|
/* 工作台与个人中心常驻同层,用 hidden 切换以保活生成任务状态。
|
||||||
@@ -226,6 +230,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ecommerce-standalone__content {
|
.ecommerce-standalone__content {
|
||||||
|
padding-top: 58px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +249,8 @@
|
|||||||
|
|
||||||
.ecommerce-standalone__topbar {
|
.ecommerce-standalone__topbar {
|
||||||
border-bottom-color: rgba(126, 235, 255, 0.22);
|
border-bottom-color: rgba(126, 235, 255, 0.22);
|
||||||
background: transparent;
|
background:
|
||||||
|
linear-gradient(90deg, rgba(7, 72, 121, 0.94), rgba(4, 37, 75, 0.92));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ecommerce-standalone__brand::before {
|
.ecommerce-standalone__brand::before {
|
||||||
@@ -312,7 +318,7 @@
|
|||||||
|
|
||||||
.ecommerce-standalone__topbar {
|
.ecommerce-standalone__topbar {
|
||||||
border-bottom-color: rgba(30, 189, 219, 0.16) !important;
|
border-bottom-color: rgba(30, 189, 219, 0.16) !important;
|
||||||
background: transparent !important;
|
background: #f8f9fa !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ecommerce-standalone__brand::before {
|
.ecommerce-standalone__brand::before {
|
||||||
@@ -12257,12 +12263,26 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
|||||||
/* #/imageWorkbench detail popover and topbar blend: no inner scrollbar, no hard header split. */
|
/* #/imageWorkbench detail popover and topbar blend: no inner scrollbar, no hard header split. */
|
||||||
html body #root .ecommerce-standalone.web-shell .ecommerce-standalone__topbar {
|
html body #root .ecommerce-standalone.web-shell .ecommerce-standalone__topbar {
|
||||||
border-bottom-color: transparent !important;
|
border-bottom-color: transparent !important;
|
||||||
background: transparent !important;
|
background:
|
||||||
|
radial-gradient(48rem 14rem at 50% 100%, rgba(30, 189, 219, 0.09), transparent 72%),
|
||||||
|
radial-gradient(28rem 12rem at 12% 100%, rgba(16, 115, 204, 0.045), transparent 68%),
|
||||||
|
linear-gradient(180deg, #fbfdfe 0%, #f8fbfc 100%) !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 .ecommerce-standalone.web-shell .ecommerce-standalone__topbar::after {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 0 !important;
|
||||||
|
bottom: -1px !important;
|
||||||
|
left: 0 !important;
|
||||||
|
height: 1px !important;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(30, 189, 219, 0.08), transparent) !important;
|
||||||
|
content: "" !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--settings-detail {
|
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--settings-detail {
|
||||||
width: min(468px, calc(100vw - 48px)) !important;
|
width: min(468px, calc(100vw - 48px)) !important;
|
||||||
max-width: min(468px, calc(100vw - 48px)) !important;
|
max-width: min(468px, calc(100vw - 48px)) !important;
|
||||||
|
|||||||
Reference in New Issue
Block a user