merge: resolve conflicts with main branch

This commit is contained in:
Codex
2026-06-11 14:04:03 +08:00
14 changed files with 1963 additions and 15 deletions
+28 -8
View File
@@ -2,6 +2,7 @@
AppstoreOutlined,
CloudUploadOutlined,
CloseOutlined,
DeleteOutlined,
FileImageOutlined,
FolderOpenOutlined,
FrownOutlined,
@@ -16,6 +17,7 @@
TableOutlined,
} from "@ant-design/icons";
import { useEffect, useMemo, useRef, useState, type CSSProperties, type ChangeEvent, type DragEvent, type KeyboardEvent as ReactKeyboardEvent, type MouseEvent as ReactMouseEvent, type PointerEvent as ReactPointerEvent, type ReactNode } from "react";
import { useTypewriter } from "../../hooks/useTypewriter";
import "../../styles/pages/ecommerce.css";
import "../../styles/pages/local-theme-parity.css";
import { ossAssets } from "../../data/ossAssets";
@@ -1253,7 +1255,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
const [visibleComposerMenu, setVisibleComposerMenu] = useState<ComposerMenuKey | null>(null);
const [isComposerMenuClosing, setIsComposerMenuClosing] = useState(false);
const [composerPopoverLeft, setComposerPopoverLeft] = useState(0);
const [isCommandHistoryCollapsed, setIsCommandHistoryCollapsed] = useState(false);
const [isCommandHistoryCollapsed, setIsCommandHistoryCollapsed] = useState(() => (typeof window !== "undefined" ? window.innerWidth <= 1180 : false));
const [isQuickPanelCollapsed, setIsQuickPanelCollapsed] = useState(false);
const [openCloneModelSelect, setOpenCloneModelSelect] = useState<CloneModelSelectKey | null>(null);
const [cloneModelSelectDropUp, setCloneModelSelectDropUp] = useState(false);
@@ -1297,6 +1299,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
offsetY: 0,
});
const [isCommandComposerCompact, setIsCommandComposerCompact] = useState(false);
const typewriterText = useTypewriter("万物皆可AI,广告素材一键生成");
useEffect(() => {
return () => {
@@ -1312,6 +1315,16 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
previewOffsetRef.current = previewOffset;
}, [previewOffset]);
useEffect(() => {
if (typeof window === "undefined") return undefined;
const syncHistoryPanel = () => {
setIsCommandHistoryCollapsed(window.innerWidth <= 1180);
};
syncHistoryPanel();
window.addEventListener("resize", syncHistoryPanel);
return () => window.removeEventListener("resize", syncHistoryPanel);
}, []);
const previewTransformStyle = useMemo<CSSProperties>(
() => ({
transform: `translate3d(${previewOffset.x}px, ${previewOffset.y}px, 0) scale(${previewZoom})`,
@@ -4361,7 +4374,10 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
if (isCommandComposerCompact) setIsCommandComposerCompact(false);
}}
>
<h1 className={`ecom-command-title${status === "done" ? " is-after-generate" : ""}`}>AI广</h1>
<h1 className={`ecom-command-title${status === "done" ? " is-after-generate" : ""}`}>
{typewriterText}
<span className="typewriter-cursor" aria-hidden="true">|</span>
</h1>
<input
ref={cloneReferenceInputRef}
type="file"
@@ -4404,8 +4420,8 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
if (files.length) addComposerAssets(files);
}}
>
<span aria-hidden="true">+</span>
<strong></strong>
<span aria-hidden="true"><CloudUploadOutlined /></span>
<strong></strong>
</button>
{productImages.length || videoOutfitVideoFile ? (
<div className="ecom-command-asset-popover" aria-label="宸蹭笂浼犵礌鏉?">
@@ -4415,7 +4431,9 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
<span className="ecom-command-asset-zoom" aria-hidden="true">
<img src={image.src} alt="" />
</span>
<button type="button" onClick={() => removeProductImage(image.id)} aria-label="删除图片">×</button>
<button type="button" onClick={() => removeProductImage(image.id)} aria-label="删除图片">
<DeleteOutlined />
</button>
</figure>
))}
{videoOutfitVideoFile && videoOutfitPreviewUrl ? (
@@ -4424,7 +4442,9 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
<span className="ecom-command-asset-zoom" aria-hidden="true">
<video src={videoOutfitPreviewUrl} muted playsInline />
</span>
<button type="button" onClick={() => setVideoOutfitVideoFile(null)} aria-label="删除视频">×</button>
<button type="button" onClick={() => setVideoOutfitVideoFile(null)} aria-label="删除视频">
<DeleteOutlined />
</button>
</figure>
) : null}
<button type="button" className="ecom-command-asset-add" onClick={() => productInputRef.current?.click()} aria-label="继续上传">+</button>
@@ -4468,8 +4488,8 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
if (files.length) addComposerAssets(files);
}}
>
<span aria-hidden="true">+</span>
<strong></strong>
<span aria-hidden="true"><CloudUploadOutlined /></span>
<strong></strong>
</button>
<button type="button" className={composerMenu === "mode" ? "is-active" : ""} onClick={(event) => toggleComposerMenu("mode", event)}>
<span className="ecom-command-option-icon" aria-hidden="true"><AppstoreOutlined /></span>