feat: optimize ecommerce hot clone UI
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
import {
|
||||
AppstoreOutlined,
|
||||
ClearOutlined,
|
||||
CloudUploadOutlined,
|
||||
@@ -16,6 +16,7 @@
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
PaperClipOutlined,
|
||||
PlusOutlined,
|
||||
QuestionCircleOutlined,
|
||||
ReloadOutlined,
|
||||
ScissorOutlined,
|
||||
@@ -986,9 +987,8 @@ const productSetOutputOptions: Array<{ key: ProductSetOutputKey; label: string;
|
||||
{ key: "model", label: "模特图", desc: "真人穿搭展示", icon: <SkinOutlined /> },
|
||||
{ key: "video", label: "短视频", desc: "分镜视频链路", icon: <VideoCameraOutlined /> },
|
||||
];
|
||||
const cloneOutputOptions: Array<{ key: CloneOutputKey; label: string; desc: string; icon: ReactNode }> = [
|
||||
const cloneOutputOptions: Array<{ key: ProductSetOutputKey; label: string; desc: string; icon: ReactNode }> = [
|
||||
...productSetOutputOptions,
|
||||
{ key: "hot", label: "爆款复刻", desc: "参考图风格迁移", icon: <FireOutlined /> },
|
||||
];
|
||||
const cloneSetCountOptions: Array<{
|
||||
key: CloneSetCountKey;
|
||||
@@ -1370,6 +1370,8 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const garmentInputRef = useRef<HTMLInputElement>(null);
|
||||
const detailInputRef = useRef<HTMLInputElement>(null);
|
||||
const detailProgressRef = useRef<number | null>(null);
|
||||
const hotProgressRef = useRef<number | null>(null);
|
||||
const hotMaterialInputRef = useRef<HTMLInputElement>(null);
|
||||
const countHoldTimeoutRef = useRef<number | null>(null);
|
||||
const countHoldIntervalRef = useRef<number | null>(null);
|
||||
const isAuthenticated = Boolean((_props as Record<string, unknown>).isAuthenticated);
|
||||
@@ -1403,7 +1405,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const [selectedProductSetPreview, setSelectedProductSetPreview] = useState<ProductSetPreviewSelection | null>(null);
|
||||
const [showHostingModal, setShowHostingModal] = useState(false);
|
||||
const [productImages, setProductImages] = useState<CloneImageItem[]>([]);
|
||||
const [activeQuickTool, setActiveQuickTool] = useState<"cutout" | "detail" | "watermark" | "image-edit" | "translate" | null>(null);
|
||||
const [activeQuickTool, setActiveQuickTool] = useState<"cutout" | "detail" | "watermark" | "image-edit" | "translate" | "hot" | null>(null);
|
||||
const [smartCutoutImage, setSmartCutoutImage] = useState<SmartCutoutImageItem | null>(null);
|
||||
const [smartCutoutBatchImages, setSmartCutoutBatchImages] = useState<SmartCutoutImageItem[]>([]);
|
||||
const [smartCutoutBackgroundColor, setSmartCutoutBackgroundColor] = useState("#ffffff");
|
||||
@@ -1738,24 +1740,25 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const [detailStatus, setDetailStatus] = useState<DetailStatus>("idle");
|
||||
const [detailResultUrl, setDetailResultUrl] = useState<string | null>(null);
|
||||
const [detailProgress, setDetailProgress] = useState(0);
|
||||
const [hotRequirement, setHotRequirement] = useState("");
|
||||
const [isHotMaterialDragging, setIsHotMaterialDragging] = useState(false);
|
||||
const [hotMaterialHoverZoom, setHotMaterialHoverZoom] = useState<{ src: string; x: number; y: number; placement: "above" | "below" } | null>(null);
|
||||
const [hotPlatform, setHotPlatform] = useState(platformOptions[0]);
|
||||
const [hotMarket, setHotMarket] = useState(marketOptions[0]);
|
||||
const [hotLanguage, setHotLanguage] = useState(getPlatformDefaultLanguage(platformOptions[0], marketOptions[0]));
|
||||
const [hotRatio, setHotRatio] = useState(getQuickSetRatioValue(getPlatformDefaultRatio(platformOptions[0], "detail")));
|
||||
const [hotStatus, setHotStatus] = useState<DetailStatus>("idle");
|
||||
const [hotResultUrl, setHotResultUrl] = useState<string | null>(null);
|
||||
const [hotProgress, setHotProgress] = useState(0);
|
||||
const productSetRatioOptions = useMemo(
|
||||
() => getPlatformRatioOptions(productSetPlatform, productSetOutput),
|
||||
[productSetOutput, productSetPlatform],
|
||||
);
|
||||
const hotUploadedRatioOption = useMemo(
|
||||
() => cloneOutput === "hot" ? formatUploadedImageRatio(cloneReferenceImages[0]) : null,
|
||||
[cloneOutput, cloneReferenceImages],
|
||||
);
|
||||
const baseCloneRatioOptions = useMemo(
|
||||
() => getPlatformRatioOptions(platform, cloneOutput),
|
||||
[cloneOutput, platform],
|
||||
);
|
||||
const cloneRatioOptions = useMemo(
|
||||
() => hotUploadedRatioOption
|
||||
? getUniqueRatioOptions([...baseCloneRatioOptions, hotUploadedRatioOption])
|
||||
: baseCloneRatioOptions,
|
||||
[baseCloneRatioOptions, hotUploadedRatioOption],
|
||||
);
|
||||
const cloneRatioOptions = baseCloneRatioOptions;
|
||||
const productSetLanguageOptions = useMemo(
|
||||
() => getPlatformLanguageOptions(productSetPlatform, productSetMarket),
|
||||
[productSetMarket, productSetPlatform],
|
||||
@@ -1768,6 +1771,10 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
() => getPlatformLanguageOptions(detailPlatform, detailMarket),
|
||||
[detailMarket, detailPlatform],
|
||||
);
|
||||
const hotLanguageOptions = useMemo(
|
||||
() => getPlatformLanguageOptions(hotPlatform, hotMarket),
|
||||
[hotMarket, hotPlatform],
|
||||
);
|
||||
const ecommerceMentionImages: MentionImageOption[] = [
|
||||
...productImages.map((image, index) => ({ ...image, label: `商品图 ${index + 1}` })),
|
||||
...cloneReferenceImages.map((image, index) => ({ ...image, label: `参考图 ${index + 1}` })),
|
||||
@@ -1798,6 +1805,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const canGenerate = productImages.length > 0 && status !== "generating";
|
||||
const canGenerateTryOn = garmentImages.length > 0 && tryOnStatus !== "generating" && tryOnStatus !== "modeling";
|
||||
const canGenerateDetail = detailProductImages.length > 0 && detailStatus !== "generating";
|
||||
const canGenerateHot = cloneReferenceImages.length > 0 && hotStatus !== "generating";
|
||||
const cloneVideoDurationProgress =
|
||||
((cloneVideoDuration - cloneVideoDurationMin) / (cloneVideoDurationMax - cloneVideoDurationMin)) * 100;
|
||||
const cloneVideoDurationStyle: CSSProperties = useMemo(
|
||||
@@ -2662,6 +2670,16 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
if (!selectedDetailModules.length) setSelectedDetailModules(defaultCloneDetailModuleIds);
|
||||
};
|
||||
|
||||
const openHotClonePage = () => {
|
||||
clearSmartCutoutTransition();
|
||||
setActiveQuickTool("hot");
|
||||
setComposerMenu(null);
|
||||
setIsCloneSettingsCollapsed(false);
|
||||
setIsQuickPanelCollapsed(false);
|
||||
setPreviewZoom(1);
|
||||
resetQuickSetSelectState();
|
||||
};
|
||||
|
||||
const closeSmartCutoutTool = () => {
|
||||
runSmartCutoutPageTransition(
|
||||
{
|
||||
@@ -3020,6 +3038,17 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
}
|
||||
};
|
||||
|
||||
const removeCloneReferenceImage = (imageId: string) => {
|
||||
setCloneReferenceImages((current) => {
|
||||
const next = current.filter((item) => item.id !== imageId);
|
||||
if (next.length === 0) {
|
||||
setHotStatus("idle");
|
||||
setHotResultUrl(null);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCloneReferenceUpload = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (!files?.length) return;
|
||||
@@ -3124,9 +3153,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const normalizedPlatform = normalizePlatform(nextPlatform);
|
||||
setPlatform(normalizedPlatform);
|
||||
setRatio((current) =>
|
||||
cloneOutput === "hot" && current.startsWith("上传图片") && hotUploadedRatioOption
|
||||
? hotUploadedRatioOption
|
||||
: normalizeRatioForPlatform(normalizedPlatform, current, cloneOutput),
|
||||
normalizeRatioForPlatform(normalizedPlatform, current, cloneOutput),
|
||||
);
|
||||
setLanguage(getPlatformDefaultLanguage(normalizedPlatform, market));
|
||||
};
|
||||
@@ -3135,9 +3162,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
setCloneOutput(nextOutput);
|
||||
if (nextOutput !== "video") setIsVideoWorkspaceVisible(false);
|
||||
setRatio((current) =>
|
||||
nextOutput === "hot" && current.startsWith("上传图片") && hotUploadedRatioOption
|
||||
? hotUploadedRatioOption
|
||||
: normalizeRatioForPlatform(platform, current, nextOutput),
|
||||
normalizeRatioForPlatform(platform, current, nextOutput),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3276,14 +3301,12 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
useEffect(() => {
|
||||
setRatio((current) => {
|
||||
const platformRatios = getPlatformRatioOptions(platform, cloneOutput);
|
||||
const availableRatios = hotUploadedRatioOption ? getUniqueRatioOptions([...platformRatios, hotUploadedRatioOption]) : platformRatios;
|
||||
if (current.startsWith("上传图片") && hotUploadedRatioOption) return hotUploadedRatioOption;
|
||||
if (availableRatios.includes(current)) return current;
|
||||
if (platformRatios.includes(current)) return current;
|
||||
const normalizedRatio = normalizeRatioToken(current);
|
||||
const matchedRatio = availableRatios.find((option) => normalizeRatioToken(option).includes(normalizedRatio));
|
||||
const matchedRatio = platformRatios.find((option) => normalizeRatioToken(option).includes(normalizedRatio));
|
||||
return matchedRatio ?? getPlatformDefaultRatio(platform, cloneOutput);
|
||||
});
|
||||
}, [cloneOutput, hotUploadedRatioOption, platform]);
|
||||
}, [cloneOutput, platform]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skipInitialCloneAutoSaveRef.current) {
|
||||
@@ -4015,6 +4038,133 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
);
|
||||
};
|
||||
|
||||
const handleHotPlatformChange = (nextPlatform: string) => {
|
||||
const normalizedPlatform = normalizePlatform(nextPlatform);
|
||||
setHotPlatform(normalizedPlatform);
|
||||
setHotLanguage(getPlatformDefaultLanguage(normalizedPlatform, hotMarket));
|
||||
setHotRatio((current) => getQuickSetRatioValue(current));
|
||||
};
|
||||
|
||||
const handleHotMarketChange = (nextMarket: string) => {
|
||||
const normalizedMarket = normalizeMarket(nextMarket);
|
||||
setHotMarket(normalizedMarket);
|
||||
setHotLanguage(getPlatformDefaultLanguage(hotPlatform, normalizedMarket));
|
||||
};
|
||||
|
||||
const handleHotAiWrite = () => {
|
||||
setHotRequirement(
|
||||
"1.产品名称:便携式咖啡保温杯\n2.核心卖点:316不锈钢内胆、12小时长效保温、防漏便携、大容量\n3.参考风格:极简日系、暖光氛围、生活场景\n4.期望场景:办公桌面、户外通勤、运动健身\n5.具体参数:容量500ml、口径4.5cm、高度22cm",
|
||||
);
|
||||
};
|
||||
|
||||
const stopHotProgress = () => {
|
||||
if (hotProgressRef.current !== null) {
|
||||
window.clearInterval(hotProgressRef.current);
|
||||
hotProgressRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
const startHotProgress = () => {
|
||||
stopHotProgress();
|
||||
setHotProgress(0);
|
||||
hotProgressRef.current = window.setInterval(() => {
|
||||
setHotProgress((prev) => {
|
||||
if (prev >= 90) {
|
||||
stopHotProgress();
|
||||
return 90;
|
||||
}
|
||||
return prev + (90 - prev) * 0.06;
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleHotGenerate = () => {
|
||||
if (!canGenerateHot) return;
|
||||
imageAbortRef.current = { current: false };
|
||||
lastFailedActionRef.current = null;
|
||||
startHotProgress();
|
||||
void generateEcommerceImage(
|
||||
"hot", cloneReferenceImages, hotRequirement,
|
||||
hotPlatform, hotRatio, hotLanguage, hotMarket,
|
||||
undefined,
|
||||
(s: string) => {
|
||||
setHotStatus(s as DetailStatus);
|
||||
if (s === "done") {
|
||||
stopHotProgress();
|
||||
setHotProgress(100);
|
||||
} else if (s === "failed" || s === "idle") {
|
||||
stopHotProgress();
|
||||
setHotProgress(0);
|
||||
}
|
||||
},
|
||||
(res) => setHotResultUrl(res[0]?.src ?? null),
|
||||
);
|
||||
};
|
||||
|
||||
const handleHotMaterialMouseEnter = (src: string, event: ReactMouseEvent<HTMLElement>) => {
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
const previewHalfWidth = 150;
|
||||
const previewHeight = 360;
|
||||
const gap = 12;
|
||||
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||
const x = Math.min(
|
||||
Math.max(rect.left + rect.width / 2, previewHalfWidth + gap),
|
||||
Math.max(previewHalfWidth + gap, viewportWidth - previewHalfWidth - gap),
|
||||
);
|
||||
const showAbove = rect.top > previewHeight + gap;
|
||||
const y = showAbove
|
||||
? rect.top - gap
|
||||
: Math.min(rect.bottom + gap, viewportHeight - gap);
|
||||
setHotMaterialHoverZoom({ src, x, y, placement: showAbove ? "above" : "below" });
|
||||
};
|
||||
const handleHotMaterialMouseLeave = () => setHotMaterialHoverZoom(null);
|
||||
|
||||
const renderHotMaterialThumbs = (items: CloneImageItem[], onRemove: (imageId: string) => void) => (
|
||||
<div className="ecom-quick-upload-thumbs" aria-label="已上传商品素材">
|
||||
{items.map((item) => (
|
||||
<figure
|
||||
key={item.id}
|
||||
className="ecom-command-asset-thumb ecom-quick-upload-thumb"
|
||||
onMouseEnter={(e) => handleHotMaterialMouseEnter(item.src, e)}
|
||||
onMouseLeave={handleHotMaterialMouseLeave}
|
||||
>
|
||||
<img src={item.src} alt={item.name} />
|
||||
<button
|
||||
type="button"
|
||||
className="ecom-hot-material-delete"
|
||||
aria-label={`删除${item.name || "图片"}`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setHotMaterialHoverZoom(null);
|
||||
onRemove(item.id);
|
||||
}}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
||||
<path d="M9 6V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v1" />
|
||||
<path d="M5 6h14" />
|
||||
<path d="M8 6l1 14h6l1-14" />
|
||||
<path d="M10.5 10v6" />
|
||||
<path d="M13.5 10v6" />
|
||||
</svg>
|
||||
</button>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
const closeHotClonePage = () => {
|
||||
stopHotProgress();
|
||||
setActiveQuickTool(null);
|
||||
setHotStatus("idle");
|
||||
setHotResultUrl(null);
|
||||
setHotProgress(0);
|
||||
setHotRequirement("");
|
||||
setIsHotMaterialDragging(false);
|
||||
setHotMaterialHoverZoom(null);
|
||||
setComposerMenu(null);
|
||||
};
|
||||
|
||||
const resetTask = () => {
|
||||
setSetImages([]);
|
||||
setProductSetRequirement("");
|
||||
@@ -4077,6 +4227,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const isWatermarkTool = isCloneTool && activeQuickTool === "watermark";
|
||||
const isImageEditTool = isCloneTool && activeQuickTool === "image-edit";
|
||||
const isTranslateTool = isCloneTool && activeQuickTool === "translate";
|
||||
const isHotCloneTool = isCloneTool && activeQuickTool === "hot";
|
||||
const pageLabel = isSetTool ? "商品套图" : isDetail ? "A+/详情页" : isTryOn ? "AI服饰穿戴" : activeToolMeta?.label || "商品工具";
|
||||
const setPrimaryLabel =
|
||||
setImages.length === 0
|
||||
@@ -4354,6 +4505,19 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
{ key: "ratio", label: "尺寸/比例", value: getQuickSetRatioValue(detailRatio), options: quickSetRatioOptions, onChange: setDetailRatio },
|
||||
];
|
||||
|
||||
const quickHotBasicSelects: Array<{
|
||||
key: CloneBasicSelectKey;
|
||||
label: string;
|
||||
value: string;
|
||||
options: string[];
|
||||
onChange: (value: string) => void;
|
||||
}> = [
|
||||
{ key: "platform", label: "平台", value: hotPlatform, options: platformOptions, onChange: handleHotPlatformChange },
|
||||
{ key: "market", label: "国家", value: hotMarket, options: marketOptions, onChange: handleHotMarketChange },
|
||||
{ key: "language", label: "语种", value: hotLanguage, options: hotLanguageOptions, onChange: setHotLanguage },
|
||||
{ key: "ratio", label: "尺寸/比例", value: getQuickSetRatioValue(hotRatio), options: quickSetRatioOptions, onChange: setHotRatio },
|
||||
];
|
||||
|
||||
const cloneModelSelects: Array<{
|
||||
key: CloneModelSelectKey;
|
||||
label: string;
|
||||
@@ -4633,8 +4797,6 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
? cloneModelPanelTab === "scene" ? "场景设置" : "模特设置"
|
||||
: cloneOutput === "video"
|
||||
? String(cloneVideoDuration) + "秒 " + (cloneVideoQuality === "standard" ? "720P" : "1080P")
|
||||
: cloneOutput === "hot"
|
||||
? cloneReplicateLevel === "style" ? "风格复刻" : "高度复刻"
|
||||
: "换装素材";
|
||||
|
||||
const renderComposerMenu = () => {
|
||||
@@ -4771,48 +4933,6 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
<input type="range" min={cloneVideoDurationMin} max={cloneVideoDurationMax} step={5} value={cloneVideoDuration} onChange={(event) => setCloneVideoDuration(clampCloneVideoDuration(Number(event.target.value)))} />
|
||||
</label>
|
||||
</>
|
||||
) : cloneOutput === "hot" ? (
|
||||
<>
|
||||
<header><strong>爆款复刻设置</strong><span>{cloneReferenceImages.length}/{maxCloneReferenceImages}</span></header>
|
||||
<div className="ecom-command-hot-layout">
|
||||
<button
|
||||
type="button"
|
||||
className={`ecom-command-hot-upload${isCloneReferenceDragging ? " is-dragging" : ""}${cloneReferenceImages.length ? " has-image" : ""}`}
|
||||
onClick={() => cloneReferenceInputRef.current?.click()}
|
||||
onDragOver={handleCloneReferenceDragOver}
|
||||
onDragLeave={handleCloneReferenceDragLeave}
|
||||
onDrop={handleCloneReferenceDrop}
|
||||
>
|
||||
{cloneReferenceImages[0]?.src ? (
|
||||
<>
|
||||
<span className="ecom-command-hot-thumb-grid">
|
||||
{cloneReferenceImages.map((image, index) => (
|
||||
<span key={image.id} className="ecom-command-hot-thumb">
|
||||
<img src={image.src} alt={`参考图 ${index + 1}`} />
|
||||
<span className="ecom-command-hot-zoom" aria-hidden="true">
|
||||
<img src={image.src} alt="" />
|
||||
</span>
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
<span>已上传 {cloneReferenceImages.length} 张,点击继续上传</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<strong>+ 上传参考图片</strong>
|
||||
<span>支持拖拽上传</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<div className="ecom-command-hot-levels">
|
||||
{cloneReplicateLevelOptions.map((option) => (
|
||||
<button key={option.key} type="button" className={cloneReplicateLevel === option.key ? "is-active" : ""} onClick={() => setCloneReplicateLevel(option.key)}>
|
||||
<strong>{option.title}</strong><span>{option.desc}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<header><strong>视频换装设置</strong><span>上传视频和服装参考</span></header>
|
||||
@@ -5311,6 +5431,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
<section className="ecom-command-quick-board" aria-label="快捷功能">
|
||||
{[
|
||||
{ label: "A+/详情页", tone: "detail", icon: <LayoutOutlined />, onClick: openQuickDetailPage },
|
||||
{ label: "爆款复刻", tone: "hot", icon: <FireOutlined />, onClick: openHotClonePage },
|
||||
{ label: "图片修改", tone: "edit", icon: <EditOutlined />, onClick: openImageWorkbenchPage },
|
||||
{ label: "智能抠图", tone: "cutout", icon: <ScissorOutlined />, onClick: openSmartCutoutUpload },
|
||||
{ label: "去除水印", tone: "watermark", icon: <ClearOutlined />, onClick: openWatermarkRemovalPage },
|
||||
@@ -6328,6 +6449,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
);
|
||||
|
||||
const quickDetailVisibleSelect = quickDetailBasicSelects.find((item) => item.key === visibleQuickSetSelect) ?? null;
|
||||
const quickHotVisibleSelect = quickHotBasicSelects.find((item) => item.key === visibleQuickSetSelect) ?? null;
|
||||
|
||||
const quickDetailPreview = (
|
||||
<main key="quick-detail" className={`ecom-quick-set-page ecom-quick-detail-page ecom-tool-page-enter${isQuickPanelCollapsed ? " is-panel-collapsed" : ""}`} aria-label="A+详情页生成">
|
||||
@@ -6525,6 +6647,255 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
</main>
|
||||
);
|
||||
|
||||
const hotClonePreview = (
|
||||
<main key="quick-hot" className={`ecom-quick-set-page ecom-quick-hot-page ecom-tool-page-enter${isQuickPanelCollapsed ? " is-panel-collapsed" : ""}`} aria-label="爆款复刻生成">
|
||||
<div className="ecom-quick-set-body">
|
||||
<aside className="ecom-quick-set-panel" aria-label="爆款复刻设置" onWheel={handleQuickPanelWheel}>
|
||||
<header className="ecom-quick-set-panel-head">
|
||||
<strong className="ecom-quick-set-page-title">爆款复刻</strong>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeHotClonePage}>
|
||||
首页
|
||||
</button>
|
||||
<button type="button" className="ecom-quick-set-back" onClick={closeHotClonePage}>
|
||||
上一页
|
||||
</button>
|
||||
</header>
|
||||
<section>
|
||||
<strong><FileImageOutlined /> 上传素材</strong>
|
||||
{productImages.length ? (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`ecom-quick-set-upload ecom-quick-hot-material has-images${isHotMaterialDragging ? " is-dragging" : ""}`}
|
||||
onClick={() => hotMaterialInputRef.current?.click()}
|
||||
onKeyDown={(event) => openQuickUploadWithKeyboard(event, hotMaterialInputRef)}
|
||||
onDragOver={(event) => { event.preventDefault(); event.stopPropagation(); if (event.dataTransfer.types.includes("Files")) setIsHotMaterialDragging(true); }}
|
||||
onDragLeave={(event) => { event.preventDefault(); event.stopPropagation(); if (event.currentTarget === event.target || !event.currentTarget.contains(event.relatedTarget as Node)) setIsHotMaterialDragging(false); }}
|
||||
onDrop={(event) => { event.preventDefault(); event.stopPropagation(); setIsHotMaterialDragging(false); const files = Array.from(event.dataTransfer.files); if (files.length) addProductImages(files); }}
|
||||
>
|
||||
{renderHotMaterialThumbs(productImages, removeProductImage)}
|
||||
<button
|
||||
type="button"
|
||||
className="ecom-quick-hot-add-btn"
|
||||
aria-label="添加更多素材"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
hotMaterialInputRef.current?.click();
|
||||
}}
|
||||
>
|
||||
<PlusOutlined />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`ecom-quick-set-upload ecom-quick-hot-material${isHotMaterialDragging ? " is-dragging" : ""}`}
|
||||
onClick={() => hotMaterialInputRef.current?.click()}
|
||||
onKeyDown={(event) => openQuickUploadWithKeyboard(event, hotMaterialInputRef)}
|
||||
onDragOver={(event) => { event.preventDefault(); event.stopPropagation(); if (event.dataTransfer.types.includes("Files")) setIsHotMaterialDragging(true); }}
|
||||
onDragLeave={(event) => { event.preventDefault(); event.stopPropagation(); if (event.currentTarget === event.target || !event.currentTarget.contains(event.relatedTarget as Node)) setIsHotMaterialDragging(false); }}
|
||||
onDrop={(event) => { event.preventDefault(); event.stopPropagation(); setIsHotMaterialDragging(false); const files = Array.from(event.dataTransfer.files); if (files.length) addProductImages(files); }}
|
||||
>
|
||||
<FileImageOutlined />
|
||||
<span>拖拽或点击上传</span>
|
||||
<em>上传商品素材图,最多 {maxCloneProductImages} 张</em>
|
||||
<b>+ 上传图片</b>
|
||||
</div>
|
||||
)}
|
||||
<input
|
||||
ref={hotMaterialInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
className="ecom-command-hidden-file"
|
||||
onChange={handleProductUpload}
|
||||
aria-label="上传爆款复刻素材"
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<strong><FireOutlined /> 上传参考图片</strong>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`ecom-quick-set-upload${cloneReferenceImages.length ? " has-images" : ""}${isCloneReferenceDragging ? " is-dragging" : ""}`}
|
||||
onClick={() => cloneReferenceInputRef.current?.click()}
|
||||
onKeyDown={(event) => openQuickUploadWithKeyboard(event, cloneReferenceInputRef)}
|
||||
onDragOver={(event) => { event.preventDefault(); event.stopPropagation(); if (event.dataTransfer.types.includes("Files")) setIsCloneReferenceDragging(true); }}
|
||||
onDragLeave={(event) => { event.preventDefault(); event.stopPropagation(); if (event.currentTarget === event.target || !event.currentTarget.contains(event.relatedTarget as Node)) setIsCloneReferenceDragging(false); }}
|
||||
onDrop={(event) => { event.preventDefault(); event.stopPropagation(); setIsCloneReferenceDragging(false); const files = Array.from(event.dataTransfer.files); if (files.length) addCloneReferenceImages(files); }}
|
||||
>
|
||||
<FileImageOutlined />
|
||||
<span>拖拽或点击上传</span>
|
||||
<em>参考图用于风格迁移,最多 {maxCloneReferenceImages} 张</em>
|
||||
<b>+ 上传图片</b>
|
||||
{cloneReferenceImages.length ? renderQuickUploadThumbs(cloneReferenceImages, removeCloneReferenceImage) : null}
|
||||
</div>
|
||||
<input
|
||||
ref={cloneReferenceInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
className="ecom-command-hidden-file"
|
||||
onChange={handleCloneReferenceUpload}
|
||||
aria-label="上传爆款复刻参考图"
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<strong>复刻强度</strong>
|
||||
<div className="ecom-quick-detail-modules">
|
||||
{cloneReplicateLevelOptions.map((option) => (
|
||||
<button
|
||||
key={option.key}
|
||||
type="button"
|
||||
className={cloneReplicateLevel === option.key ? "is-active" : ""}
|
||||
onClick={() => setCloneReplicateLevel(option.key)}
|
||||
>
|
||||
<strong>{option.title}</strong>
|
||||
<span>{option.desc}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
<section className="ecom-quick-set-basic-section">
|
||||
<span className="ecom-quick-set-label">基础设置</span>
|
||||
<div className="ecom-quick-set-select-anchor">
|
||||
<div className="ecom-quick-set-selects">
|
||||
{quickHotBasicSelects.map((item) => (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className={openQuickSetSelect === item.key ? "is-active" : ""}
|
||||
onClick={() => toggleQuickSetSelect(item.key)}
|
||||
>
|
||||
<span>{item.label}</span><strong>{formatRatioDisplayValue(item.value)}</strong><em>⌄</em>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{quickHotVisibleSelect ? (
|
||||
<div
|
||||
className={`ecom-quick-set-dropdown ecom-quick-set-dropdown--${quickHotVisibleSelect.key}${isQuickSetSelectClosing ? " is-closing" : ""}`}
|
||||
role="listbox"
|
||||
aria-label={quickHotVisibleSelect.label}
|
||||
>
|
||||
{quickHotVisibleSelect.options.map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
type="button"
|
||||
className={quickHotVisibleSelect.value === option ? "is-active" : ""}
|
||||
onClick={() => {
|
||||
quickHotVisibleSelect.onChange(option);
|
||||
closeQuickSetSelect();
|
||||
}}
|
||||
>
|
||||
{formatRatioDisplayValue(option)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
<section className="ecom-quick-hot-requirement">
|
||||
<div className="ecom-quick-hot-requirement__head">
|
||||
<strong>商品卖点 & 需求</strong>
|
||||
<button type="button" className="ecom-quick-hot-requirement__ai" onClick={handleHotAiWrite}>AI 帮写</button>
|
||||
</div>
|
||||
<div className="ecom-quick-hot-requirement__input">
|
||||
<textarea
|
||||
value={hotRequirement}
|
||||
onChange={(event) => setHotRequirement(event.target.value.slice(0, 500))}
|
||||
placeholder="建议包含以下信息:产品名称、核心卖点、参考风格、期望场景、具体参数"
|
||||
maxLength={500}
|
||||
/>
|
||||
<span>{hotRequirement.length}/500</span>
|
||||
</div>
|
||||
</section>
|
||||
<div className="ecom-quick-hot-actions">
|
||||
<button type="button" className="ecom-quick-set-primary ecom-quick-hot-generate" onClick={handleHotGenerate} disabled={!canGenerateHot}>
|
||||
{hotStatus === "generating" ? <LoadingOutlined /> : "✦"} 开始复刻
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`ecom-quick-set-primary ecom-quick-set-primary--cancel${hotStatus !== "generating" ? " is-disabled" : ""}`}
|
||||
onClick={hotStatus === "generating" ? handleCancelGenerate : undefined}
|
||||
disabled={hotStatus !== "generating"}
|
||||
>
|
||||
取消复刻
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
{hotMaterialHoverZoom && typeof document !== "undefined"
|
||||
? createPortal(
|
||||
<div
|
||||
className={`ecom-hot-material-zoom-portal is-${hotMaterialHoverZoom.placement}`}
|
||||
style={{ left: hotMaterialHoverZoom.x, top: hotMaterialHoverZoom.y }}
|
||||
>
|
||||
<img src={hotMaterialHoverZoom.src} alt="" />
|
||||
</div>,
|
||||
document.body,
|
||||
)
|
||||
: null}
|
||||
<section className="ecom-quick-set-stage">
|
||||
<header className="ecom-quick-set-preview-head">
|
||||
<h1>预览</h1>
|
||||
<p>上传参考图,AI 按选定风格强度 <span>复刻同款视觉表现</span>,快速产出高转化素材。</p>
|
||||
<div>
|
||||
<button type="button" onClick={() => setPreviewZoom((value) => Math.max(0.25, value - 0.1))}>-</button>
|
||||
<strong>{Math.round(previewZoom * 100)}%</strong>
|
||||
<button type="button" onClick={() => setPreviewZoom((value) => Math.min(2, value + 0.1))}>+</button>
|
||||
</div>
|
||||
</header>
|
||||
<div className="ecom-quick-set-canvas" onWheel={handleQuickPreviewWheel}>
|
||||
{hotStatus === "done" && hotResultUrl ? (
|
||||
<section className="ecom-quick-detail-result" style={{ transform: `scale(${previewZoom})` }}>
|
||||
<img src={hotResultUrl} alt="爆款复刻结果" />
|
||||
<button
|
||||
type="button"
|
||||
className="ecom-quick-detail-download"
|
||||
onClick={() => {
|
||||
const link = document.createElement("a");
|
||||
link.href = hotResultUrl;
|
||||
link.download = `爆款复刻-${Date.now()}.png`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
}}
|
||||
>
|
||||
<CloudUploadOutlined />
|
||||
保存本地
|
||||
</button>
|
||||
</section>
|
||||
) : hotStatus === "generating" ? (
|
||||
<section className="ecom-quick-set-generating">
|
||||
<LoadingOutlined />
|
||||
<strong>正在生成爆款复刻</strong>
|
||||
<span>AI 正在根据参考图和复刻强度生成同款素材,请稍候...</span>
|
||||
<div className="ecom-quick-set-progress">
|
||||
<div className="ecom-quick-set-progress-bar" style={{ width: `${Math.round(hotProgress)}%` }} />
|
||||
</div>
|
||||
<em className="ecom-quick-set-progress-text">{Math.round(hotProgress)}%</em>
|
||||
</section>
|
||||
) : hotStatus === "failed" ? (
|
||||
<section className="ecom-quick-set-failed">
|
||||
<FrownOutlined />
|
||||
<strong>生成失败</strong>
|
||||
<span>请检查网络或重试,如余额不足请先充值。</span>
|
||||
<button type="button" onClick={handleHotGenerate} disabled={!canGenerateHot}>重新生成</button>
|
||||
</section>
|
||||
) : (
|
||||
<section className="ecom-quick-set-empty">
|
||||
<FileImageOutlined />
|
||||
<strong>等待生成</strong>
|
||||
<span>上传参考图片并选择复刻强度后,AI 将在这里展示生成结果。</span>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<button type="button" className="ecom-quick-set-help" aria-label="帮助" onClick={() => toast.info("上传参考图后,选择复刻强度和平台即可生成爆款同款。")}>?</button>
|
||||
</main>
|
||||
);
|
||||
|
||||
const detailPreview = (
|
||||
<main className="product-clone-preview product-clone-preview--detail" aria-label="A+详情预览" onWheel={handlePreviewWheel}>
|
||||
<div className="product-clone-preview__headline">
|
||||
@@ -6641,12 +7012,18 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
{quickDetailPreview}
|
||||
</div>
|
||||
)
|
||||
: isHotCloneTool
|
||||
? (
|
||||
<div key={`quick-${activeQuickTool}`} className="ecom-quick-page-wrap ecom-tool-page-enter">
|
||||
{hotClonePreview}
|
||||
</div>
|
||||
)
|
||||
: clonePreview
|
||||
: placeholderPreview;
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`product-clone-page page-motion${isCloneTool && isCloneSettingsCollapsed ? " is-settings-collapsed" : ""}${isCloneTool && isCommandHistoryCollapsed ? " is-history-collapsed" : ""}${isCloneTool && activeHistoryRecordId ? " is-history-detail" : ""}${isSmartCutoutTool ? " is-smart-cutout-page" : ""}${isQuickDetailTool ? " is-quick-set-page" : ""}${isWatermarkTool ? " is-watermark-page" : ""}${isTranslateTool ? " is-translate-page" : ""}${isImageEditTool ? " is-image-workbench-page" : ""}`}
|
||||
className={`product-clone-page page-motion${isCloneTool && isCloneSettingsCollapsed ? " is-settings-collapsed" : ""}${isCloneTool && isCommandHistoryCollapsed ? " is-history-collapsed" : ""}${isCloneTool && activeHistoryRecordId ? " is-history-detail" : ""}${isSmartCutoutTool ? " is-smart-cutout-page" : ""}${isQuickDetailTool ? " is-quick-set-page" : ""}${isWatermarkTool ? " is-watermark-page" : ""}${isTranslateTool ? " is-translate-page" : ""}${isImageEditTool ? " is-image-workbench-page" : ""}${isHotCloneTool ? " is-hot-clone-page" : ""}`}
|
||||
data-tool={activeTool}
|
||||
aria-label={pageLabel}
|
||||
>
|
||||
@@ -6670,7 +7047,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
{isSetTool ? setPanel : isDetail ? detailPanel : isTryOn ? tryOnPanel : isCloneTool ? clonePanel : placeholderPanel}
|
||||
</aside>
|
||||
|
||||
{isCloneTool && !isSmartCutoutTool && !isQuickDetailTool && !isWatermarkTool && !isTranslateTool && !isImageEditTool ? (
|
||||
{isCloneTool && !isSmartCutoutTool && !isQuickDetailTool && !isWatermarkTool && !isTranslateTool && !isImageEditTool && !isHotCloneTool ? (
|
||||
<button
|
||||
type="button"
|
||||
className="clone-ai-settings-toggle"
|
||||
|
||||
@@ -381,108 +381,6 @@ export default function EcommerceClonePanel({
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{cloneOutput === "hot" ? (
|
||||
<section className="clone-ai-replicate-panel" aria-label="爆款图复刻设置">
|
||||
<div className="clone-ai-dynamic-head">
|
||||
<strong>爆款图参考设置</strong>
|
||||
<span>随生成模式切换</span>
|
||||
</div>
|
||||
<div className="clone-ai-replicate-section">
|
||||
<span className="clone-ai-replicate-title">参考内容</span>
|
||||
<div className="clone-ai-replicate-tabs" role="tablist" aria-label="参考内容来源">
|
||||
<button
|
||||
type="button"
|
||||
className={cloneReferenceMode === "upload" ? "is-active" : ""}
|
||||
aria-selected={cloneReferenceMode === "upload"}
|
||||
onClick={() => setCloneReferenceMode("upload")}
|
||||
>
|
||||
上传参考图
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={cloneReferenceMode === "link" ? "is-active" : ""}
|
||||
aria-selected={cloneReferenceMode === "link"}
|
||||
onClick={() => setCloneReferenceMode("link")}
|
||||
>
|
||||
导入链接
|
||||
</button>
|
||||
</div>
|
||||
{cloneReferenceMode === "upload" ? (
|
||||
<button
|
||||
type="button"
|
||||
className={`clone-ai-replicate-upload${isCloneReferenceDragging ? " is-dragging" : ""}${cloneReferenceImages.length ? " has-files" : ""}`}
|
||||
onClick={() => cloneReferenceInputRef.current?.click()}
|
||||
onDragOver={handleCloneReferenceDragOver}
|
||||
onDragLeave={handleCloneReferenceDragLeave}
|
||||
onDrop={handleCloneReferenceDrop}
|
||||
>
|
||||
{cloneReferenceImages.length ? (
|
||||
<>
|
||||
<div className="clone-ai-replicate-files">
|
||||
{cloneReferenceImages.map((item) => (
|
||||
<figure
|
||||
key={item.id}
|
||||
className="clone-ai-replicate-file"
|
||||
onMouseEnter={(e) => handleFileMouseEnter(item.src, e)}
|
||||
onMouseLeave={handleFileMouseLeave}
|
||||
>
|
||||
<img src={item.src} alt="" />
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
<span className="clone-ai-replicate-add-more">
|
||||
<CloudUploadOutlined />
|
||||
点击继续上传文件
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<span>
|
||||
<CloudUploadOutlined />
|
||||
<span className="clone-ai-replicate-upload-text">拖拽或点击上传参考图</span>
|
||||
</span>
|
||||
)}
|
||||
<em>{cloneReferenceImages.length ? `已选 ${cloneReferenceImages.length}/${maxCloneReferenceImages}` : `最多 ${maxCloneReferenceImages} 张`}</em>
|
||||
{isCloneReferenceDragging ? (
|
||||
<div className="clone-ai-replicate-upload-overlay">
|
||||
<CloudUploadOutlined />
|
||||
<span>释放文件以上传</span>
|
||||
</div>
|
||||
) : null}
|
||||
</button>
|
||||
) : (
|
||||
<label className="clone-ai-replicate-link">
|
||||
<input placeholder="粘贴商品图或详情页链接" />
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
ref={cloneReferenceInputRef}
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/webp"
|
||||
multiple
|
||||
onChange={handleCloneReferenceUpload}
|
||||
aria-label="上传参考图片"
|
||||
/>
|
||||
</div>
|
||||
<div className="clone-ai-replicate-section">
|
||||
<span className="clone-ai-replicate-title">复刻程度</span>
|
||||
<div className="clone-ai-replicate-levels" role="toolbar" aria-label="复刻程度">
|
||||
{cloneReplicateLevelOptions.map((option) => (
|
||||
<button
|
||||
key={option.key}
|
||||
type="button"
|
||||
className={cloneReplicateLevel === option.key ? "is-active" : ""}
|
||||
aria-pressed={cloneReplicateLevel === option.key}
|
||||
onClick={() => setCloneReplicateLevel(option.key)}
|
||||
>
|
||||
<strong>{option.title}</strong>
|
||||
<span>{option.desc}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{cloneOutput === "set" ? (
|
||||
<section className="clone-ai-count-panel" aria-label="套图图片数量">
|
||||
<div className="clone-ai-dynamic-head">
|
||||
|
||||
@@ -4537,6 +4537,275 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page {
|
||||
display: block !important;
|
||||
height: 100% !important;
|
||||
min-height: calc(100vh - 58px) !important;
|
||||
overflow: hidden !important;
|
||||
background: #f3f5f8 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .product-clone-shell {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .product-clone-rail,
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .product-clone-panel,
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .clone-ai-settings-toggle,
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-command-history {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* ── Hot Clone: requirement input in left panel ── */
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 8px !important;
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__head {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: space-between !important;
|
||||
gap: 8px !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__head > strong {
|
||||
font-size: 13px !important;
|
||||
font-weight: 800 !important;
|
||||
color: #1a2b3c !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__input {
|
||||
position: relative !important;
|
||||
min-height: 158px !important;
|
||||
border: 1px dashed rgba(30, 189, 219, 0.34) !important;
|
||||
border-radius: 8px !important;
|
||||
background: linear-gradient(180deg, rgba(237, 248, 255, 0.72), rgba(255, 255, 255, 0.94)) !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__input textarea {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
min-height: 140px !important;
|
||||
max-height: 240px !important;
|
||||
resize: none !important;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
padding: 14px 14px 24px !important;
|
||||
color: #172636 !important;
|
||||
background: transparent !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__input textarea::placeholder {
|
||||
color: #9badb9 !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__input > span {
|
||||
position: absolute !important;
|
||||
right: 12px !important;
|
||||
bottom: 6px !important;
|
||||
color: #9badb9 !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 600 !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__ai {
|
||||
padding: 3px 12px !important;
|
||||
border: 1.5px solid rgba(16, 115, 204, 0.18) !important;
|
||||
border-radius: 20px !important;
|
||||
background: linear-gradient(135deg, rgba(16, 115, 204, 0.06), rgba(25, 173, 200, 0.06)) !important;
|
||||
color: #1073cc !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 800 !important;
|
||||
cursor: pointer !important;
|
||||
white-space: nowrap !important;
|
||||
flex-shrink: 0 !important;
|
||||
transition: background 160ms ease, border-color 160ms ease !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-requirement__ai:hover {
|
||||
background: linear-gradient(135deg, rgba(16, 115, 204, 0.12), rgba(25, 173, 200, 0.12)) !important;
|
||||
border-color: rgba(16, 115, 204, 0.3) !important;
|
||||
}
|
||||
|
||||
/* ── Hot Clone: material upload with images ── */
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
align-items: flex-start !important;
|
||||
justify-content: flex-start !important;
|
||||
gap: 10px !important;
|
||||
padding: 12px !important;
|
||||
place-items: unset !important;
|
||||
background: #f9fafa !important;
|
||||
border: 1px solid rgba(30, 189, 219, 0.22) !important;
|
||||
border-style: solid !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs {
|
||||
display: contents !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs figure {
|
||||
position: relative !important;
|
||||
width: 80px !important;
|
||||
height: 80px !important;
|
||||
margin: 0 !important;
|
||||
border: 1px solid #e8edf0 !important;
|
||||
border-radius: 10px !important;
|
||||
overflow: hidden !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs figure > img {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 9px !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs figure > button {
|
||||
position: absolute !important;
|
||||
top: 4px !important;
|
||||
right: 4px !important;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
border: none !important;
|
||||
border-radius: 50% !important;
|
||||
background: rgba(0, 0, 0, 0.48) !important;
|
||||
color: #fff !important;
|
||||
font-size: 11px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 0 !important;
|
||||
transition: opacity 140ms ease, background 140ms ease !important;
|
||||
padding: 0 !important;
|
||||
z-index: 3 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs figure:hover > button {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs figure > button:hover {
|
||||
background: rgba(220, 53, 69, 0.85) !important;
|
||||
}
|
||||
|
||||
/* Hide old CSS zoom in material section (portal replaces it) */
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-zoom {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-add-btn {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 80px !important;
|
||||
height: 80px !important;
|
||||
border: 1px solid #e8edf0 !important;
|
||||
border-radius: 10px !important;
|
||||
color: #3a4555 !important;
|
||||
background: #f5f5f5 !important;
|
||||
font-size: 22px !important;
|
||||
cursor: pointer !important;
|
||||
transition: background 160ms ease, border-color 160ms ease, color 160ms ease !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-add-btn:hover {
|
||||
color: #ffffff !important;
|
||||
background: linear-gradient(135deg, #1073cc, #1ebddb) !important;
|
||||
border-color: #1073cc !important;
|
||||
}
|
||||
|
||||
/* ── Hot Clone: sticky bottom action buttons ── */
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-actions {
|
||||
position: sticky !important;
|
||||
bottom: 0 !important;
|
||||
z-index: 5 !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 8px !important;
|
||||
margin: 0 -14px -86px -14px !important;
|
||||
padding: 14px 14px 16px !important;
|
||||
background: linear-gradient(to top, #feffff 60%, rgba(254, 255, 255, 0.92) 80%, transparent) !important;
|
||||
backdrop-filter: blur(6px) !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-actions .ecom-quick-set-primary {
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
bottom: auto !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-actions .ecom-quick-set-primary--cancel.is-disabled {
|
||||
color: #c0ccd4 !important;
|
||||
background: #f0f3f5 !important;
|
||||
border-color: #e4e9ec !important;
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.55 !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-hot-actions .ecom-quick-set-primary--cancel.is-disabled:hover {
|
||||
color: #c0ccd4 !important;
|
||||
background: #f0f3f5 !important;
|
||||
border-color: #e4e9ec !important;
|
||||
}
|
||||
|
||||
/* ── Hot Clone: stage fills space without prompt ── */
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-stage {
|
||||
grid-template-rows: auto minmax(0, 1fr) !important;
|
||||
}
|
||||
|
||||
/* ── Hot Clone: portal zoom preview (avoids overflow clipping) ── */
|
||||
.ecom-hot-material-zoom-portal {
|
||||
position: fixed !important;
|
||||
z-index: 2147483647 !important;
|
||||
width: min(280px, calc(100vw - 24px)) !important;
|
||||
max-height: 340px !important;
|
||||
border: 1px solid rgba(30, 189, 219, 0.2) !important;
|
||||
border-radius: 14px !important;
|
||||
background: #ffffff !important;
|
||||
padding: 8px !important;
|
||||
box-shadow: 0 22px 48px rgba(20, 80, 100, 0.22) !important;
|
||||
pointer-events: none !important;
|
||||
isolation: isolate !important;
|
||||
}
|
||||
|
||||
.ecom-hot-material-zoom-portal.is-above {
|
||||
transform: translate(-50%, -100%) !important;
|
||||
}
|
||||
|
||||
.ecom-hot-material-zoom-portal.is-below {
|
||||
transform: translate(-50%, 0) !important;
|
||||
}
|
||||
|
||||
.ecom-hot-material-zoom-portal img {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
max-height: 324px !important;
|
||||
border-radius: 8px !important;
|
||||
object-fit: contain !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .product-clone-page[data-tool="clone"].is-watermark-page {
|
||||
display: block !important;
|
||||
height: 100% !important;
|
||||
@@ -6783,31 +7052,36 @@
|
||||
background: rgba(16, 115, 204, 0.28) !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel {
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel,
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-panel {
|
||||
overflow-y: auto !important;
|
||||
padding-bottom: 16px !important;
|
||||
scrollbar-width: auto !important;
|
||||
scrollbar-color: rgba(16, 115, 204, 0.56) rgba(16, 115, 204, 0.08) !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar {
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar,
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-panel::-webkit-scrollbar {
|
||||
display: block !important;
|
||||
width: 14px !important;
|
||||
height: 14px !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-track {
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-track,
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-panel::-webkit-scrollbar-track {
|
||||
border-radius: 999px !important;
|
||||
background: rgba(16, 115, 204, 0.08) !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-thumb {
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-thumb,
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-panel::-webkit-scrollbar-thumb {
|
||||
border: 3px solid rgba(248, 249, 250, 0.95) !important;
|
||||
border-radius: 999px !important;
|
||||
background: rgba(16, 115, 204, 0.56) !important;
|
||||
}
|
||||
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-thumb:hover {
|
||||
.ecommerce-standalone .ecom-quick-detail-page .ecom-quick-set-panel::-webkit-scrollbar-thumb:hover,
|
||||
.ecommerce-standalone .ecom-quick-hot-page .ecom-quick-set-panel::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(16, 115, 204, 0.72) !important;
|
||||
}
|
||||
|
||||
@@ -11773,6 +12047,15 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
||||
--quick-text: #164e63;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--hot {
|
||||
--quick-accent: #e8590c;
|
||||
--quick-bg: #fff4e6;
|
||||
--quick-text: #5c2d0e;
|
||||
--quick-icon: #d9480f;
|
||||
--quick-border: rgba(232, 89, 12, 0.12);
|
||||
--quick-shadow: rgba(232, 89, 12, 0.1);
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board button,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board button > span,
|
||||
@@ -13172,6 +13455,7 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--detail,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--hot,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--edit,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--cutout,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--watermark {
|
||||
@@ -13397,6 +13681,16 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
||||
--quick-shadow: rgba(122, 90, 248, 0.1) !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--hot {
|
||||
--quick-accent: #e8590c !important;
|
||||
--quick-bg: #fff4e6 !important;
|
||||
--quick-text: #5c2d0e !important;
|
||||
--quick-icon: #d9480f !important;
|
||||
--quick-icon-bg: rgba(232, 89, 12, 0.13) !important;
|
||||
--quick-border: rgba(232, 89, 12, 0.12) !important;
|
||||
--quick-shadow: rgba(232, 89, 12, 0.1) !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-quick-board .ecom-command-quick-card--edit {
|
||||
--quick-accent: #cc6b14 !important;
|
||||
--quick-bg: #fff2e5 !important;
|
||||
@@ -14081,3 +14375,251 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
|
||||
margin: 0 !important;
|
||||
font-size: 22px !important;
|
||||
}
|
||||
|
||||
/* Hot clone uploaded material thumbnails: compact grid and consistent delete control. */
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
align-items: flex-start !important;
|
||||
justify-content: flex-start !important;
|
||||
align-content: flex-start !important;
|
||||
gap: 10px !important;
|
||||
width: 100% !important;
|
||||
min-height: 0 !important;
|
||||
height: auto !important;
|
||||
padding: 10px !important;
|
||||
border: 1px solid #e8edf0 !important;
|
||||
border-radius: 8px !important;
|
||||
background: #ffffff !important;
|
||||
box-shadow: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images:hover,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images:focus-visible,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images.is-dragging {
|
||||
border-color: rgba(30, 189, 219, 0.42) !important;
|
||||
background: #fbfdff !important;
|
||||
box-shadow: 0 10px 24px rgba(16, 115, 204, 0.08) !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-quick-upload-thumbs {
|
||||
display: contents !important;
|
||||
width: auto !important;
|
||||
max-width: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb {
|
||||
position: relative !important;
|
||||
flex: 0 0 64px !important;
|
||||
width: 64px !important;
|
||||
height: 64px !important;
|
||||
min-width: 64px !important;
|
||||
min-height: 64px !important;
|
||||
margin: 0 !important;
|
||||
overflow: hidden !important;
|
||||
border: 1px solid #e8edf0 !important;
|
||||
border-radius: 8px !important;
|
||||
background: #f6f8fa !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > img {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border-radius: 7px !important;
|
||||
object-fit: cover !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button {
|
||||
position: absolute !important;
|
||||
top: 4px !important;
|
||||
right: 4px !important;
|
||||
z-index: 6 !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 22px !important;
|
||||
height: 22px !important;
|
||||
min-width: 22px !important;
|
||||
min-height: 22px !important;
|
||||
padding: 0 !important;
|
||||
border: 1px solid rgba(239, 68, 68, 0.42) !important;
|
||||
border-radius: 999px !important;
|
||||
color: #ef4444 !important;
|
||||
background: rgba(255, 255, 255, 0.92) !important;
|
||||
box-shadow: 0 8px 18px rgba(239, 68, 68, 0.16) !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 0 !important;
|
||||
pointer-events: none !important;
|
||||
transform: scale(0.92) !important;
|
||||
visibility: hidden !important;
|
||||
transition:
|
||||
opacity 150ms ease,
|
||||
transform 150ms ease,
|
||||
background 150ms ease,
|
||||
box-shadow 150ms ease,
|
||||
visibility 150ms ease !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb:hover > button,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb:focus-within > button {
|
||||
opacity: 1 !important;
|
||||
pointer-events: auto !important;
|
||||
transform: scale(1) !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button:hover {
|
||||
border-color: rgba(220, 38, 38, 0.72) !important;
|
||||
color: #dc2626 !important;
|
||||
background: #fff1f2 !important;
|
||||
box-shadow: 0 10px 22px rgba(220, 38, 38, 0.22) !important;
|
||||
transform: scale(1.04) !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button .anticon {
|
||||
display: inline-flex !important;
|
||||
font-size: 13px !important;
|
||||
line-height: 1 !important;
|
||||
color: currentColor !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-set-upload.has-images .ecom-quick-hot-add-btn {
|
||||
flex: 0 0 64px !important;
|
||||
width: 64px !important;
|
||||
height: 64px !important;
|
||||
min-width: 64px !important;
|
||||
min-height: 64px !important;
|
||||
border: 1px solid #e8edf0 !important;
|
||||
border-radius: 8px !important;
|
||||
color: #111827 !important;
|
||||
background: #f3f4f6 !important;
|
||||
box-shadow: none !important;
|
||||
font-size: 22px !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* Keep hot material upload controls visible after files are added. */
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
align-items: flex-start !important;
|
||||
justify-content: flex-start !important;
|
||||
gap: 10px !important;
|
||||
min-height: 0 !important;
|
||||
height: auto !important;
|
||||
padding: 10px !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-upload-thumbs {
|
||||
display: contents !important;
|
||||
width: auto !important;
|
||||
max-width: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb {
|
||||
flex: 0 0 64px !important;
|
||||
width: 64px !important;
|
||||
height: 64px !important;
|
||||
min-width: 64px !important;
|
||||
min-height: 64px !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > img {
|
||||
overflow: hidden !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button {
|
||||
top: -7px !important;
|
||||
right: -7px !important;
|
||||
width: 22px !important;
|
||||
height: 22px !important;
|
||||
min-width: 22px !important;
|
||||
min-height: 22px !important;
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
pointer-events: auto !important;
|
||||
transform: none !important;
|
||||
color: #ef4444 !important;
|
||||
background: #ffffff !important;
|
||||
border: 1px solid rgba(239, 68, 68, 0.5) !important;
|
||||
box-shadow: 0 8px 18px rgba(239, 68, 68, 0.16) !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button .anticon,
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button svg {
|
||||
display: block !important;
|
||||
width: 12px !important;
|
||||
height: 12px !important;
|
||||
color: currentColor !important;
|
||||
fill: none !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-quick-hot-add-btn {
|
||||
display: inline-flex !important;
|
||||
flex: 0 0 64px !important;
|
||||
width: 64px !important;
|
||||
height: 64px !important;
|
||||
min-width: 64px !important;
|
||||
min-height: 64px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button.ecom-hot-material-delete {
|
||||
position: absolute !important;
|
||||
top: -8px !important;
|
||||
right: -8px !important;
|
||||
z-index: 20 !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 24px !important;
|
||||
height: 24px !important;
|
||||
min-width: 24px !important;
|
||||
min-height: 24px !important;
|
||||
padding: 0 !important;
|
||||
overflow: visible !important;
|
||||
border: 1px solid rgba(239, 68, 68, 0.62) !important;
|
||||
border-radius: 999px !important;
|
||||
color: #ef4444 !important;
|
||||
background: #ffffff !important;
|
||||
box-shadow: 0 8px 18px rgba(239, 68, 68, 0.16) !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 1 !important;
|
||||
pointer-events: auto !important;
|
||||
transform: none !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button.ecom-hot-material-delete:hover {
|
||||
border-color: #dc2626 !important;
|
||||
color: #dc2626 !important;
|
||||
background: #fff1f2 !important;
|
||||
box-shadow: 0 10px 22px rgba(220, 38, 38, 0.24) !important;
|
||||
transform: scale(1.04) !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material.has-images .ecom-command-asset-thumb.ecom-quick-upload-thumb > button.ecom-hot-material-delete svg {
|
||||
display: block !important;
|
||||
width: 14px !important;
|
||||
height: 14px !important;
|
||||
stroke: currentColor !important;
|
||||
stroke-width: 1.9 !important;
|
||||
stroke-linecap: round !important;
|
||||
stroke-linejoin: round !important;
|
||||
fill: none !important;
|
||||
}
|
||||
|
||||
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"].is-hot-clone-page .ecom-quick-hot-page .ecom-quick-hot-material:not(.has-images) {
|
||||
min-height: 94px !important;
|
||||
padding: 12px 14px !important;
|
||||
gap: 6px !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user