This commit is contained in:
@@ -4,7 +4,8 @@ import {
|
||||
ThunderboltOutlined,
|
||||
VideoCameraOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useMemo, useRef, useState, type ChangeEvent, type DragEvent, type KeyboardEvent, type RefObject } from "react";
|
||||
import { useMemo, useRef, useState, type ChangeEvent, type DragEvent, type KeyboardEvent, type MouseEvent as ReactMouseEvent, type RefObject } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import EcommerceVideoWorkspace from "../EcommerceVideoWorkspace";
|
||||
|
||||
interface CloneImageItem {
|
||||
@@ -97,6 +98,7 @@ export default function EcommerceOneClickVideoPanel({
|
||||
}: EcommerceOneClickVideoPanelProps) {
|
||||
const [openSelect, setOpenSelect] = useState<"platform" | "ratio" | null>(null);
|
||||
const [planTrigger, setPlanTrigger] = useState(0);
|
||||
const [hoverZoom, setHoverZoom] = useState<{ src: string; x: number; y: number; placement: "right" | "left" } | null>(null);
|
||||
const selectAnchorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const productImageDataUrls = useMemo(() => productImages.map((img) => img.src), [productImages]);
|
||||
@@ -126,19 +128,40 @@ export default function EcommerceOneClickVideoPanel({
|
||||
setOpenSelect((current) => (current === key ? null : key));
|
||||
};
|
||||
|
||||
const handleThumbMouseEnter = (src: string, event: ReactMouseEvent<HTMLElement>) => {
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 190;
|
||||
const gap = 12;
|
||||
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||
const canShowRight = rect.right + gap + previewWidth <= viewportWidth - gap;
|
||||
const placement: "right" | "left" = canShowRight ? "right" : "left";
|
||||
const x = placement === "right" ? rect.right + gap : Math.max(gap, rect.left - gap);
|
||||
const y = Math.min(
|
||||
Math.max(rect.top + rect.height / 2, previewHeight / 2 + gap),
|
||||
Math.max(previewHeight / 2 + gap, viewportHeight - previewHeight / 2 - gap),
|
||||
);
|
||||
setHoverZoom({ src, x, y, placement });
|
||||
};
|
||||
|
||||
const renderThumbs = () => (
|
||||
<div className="ecom-quick-upload-thumbs" aria-label="已上传商品原图">
|
||||
{productImages.map((item) => (
|
||||
<figure key={item.id} className="ecom-command-asset-thumb ecom-quick-upload-thumb">
|
||||
<figure
|
||||
key={item.id}
|
||||
className="ecom-command-asset-thumb ecom-quick-upload-thumb"
|
||||
onMouseEnter={(event) => handleThumbMouseEnter(item.src, event)}
|
||||
onMouseLeave={() => setHoverZoom(null)}
|
||||
>
|
||||
<img src={item.src} alt={item.name} />
|
||||
<span className="ecom-command-asset-zoom" aria-hidden="true">
|
||||
<img src={item.src} alt="" />
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="ecom-hot-material-delete"
|
||||
aria-label="删除图片"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setHoverZoom(null);
|
||||
removeProductImage(item.id);
|
||||
}}
|
||||
>
|
||||
@@ -386,6 +409,17 @@ export default function EcommerceOneClickVideoPanel({
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
{hoverZoom && typeof document !== "undefined"
|
||||
? createPortal(
|
||||
<div
|
||||
className={`ecom-hot-material-zoom-portal is-${hoverZoom.placement}`}
|
||||
style={{ left: hoverZoom.x, top: hoverZoom.y }}
|
||||
>
|
||||
<img src={hoverZoom.src} alt="" />
|
||||
</div>,
|
||||
document.body,
|
||||
)
|
||||
: null}
|
||||
|
||||
<section className="ecom-quick-set-stage">
|
||||
<EcommerceVideoWorkspace
|
||||
|
||||
Reference in New Issue
Block a user