fix: show psd image loading placeholder
This commit is contained in:
parent
6f4a881238
commit
5e896b8e56
@ -579,6 +579,7 @@ function AssignedPsdLayerPreviewImage({
|
||||
width,
|
||||
quality,
|
||||
style,
|
||||
onLoadComplete,
|
||||
}: {
|
||||
sourceUrl: string;
|
||||
alt: string;
|
||||
@ -586,6 +587,7 @@ function AssignedPsdLayerPreviewImage({
|
||||
width?: number;
|
||||
quality?: number;
|
||||
style?: CSSProperties;
|
||||
onLoadComplete?: (sourceUrl: string) => void;
|
||||
}) {
|
||||
const fallbackUrls = useMemo(
|
||||
() => buildAssignedPsdLayerPreviewFallbackUrls(sourceUrl, { width, quality }),
|
||||
@ -631,13 +633,48 @@ function AssignedPsdLayerPreviewImage({
|
||||
current + 1 < fallbackUrls.length ? current + 1 : current
|
||||
)
|
||||
}
|
||||
onLoad={() => setHasLoaded(true)}
|
||||
onLoad={() => {
|
||||
setHasLoaded(true);
|
||||
onLoadComplete?.(sourceUrl);
|
||||
}}
|
||||
src={src}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function PsdAssignedImageLoadingOverlay({
|
||||
pendingCount,
|
||||
zIndex,
|
||||
}: {
|
||||
pendingCount: number;
|
||||
zIndex: number;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="pointer-events-none absolute inset-0 overflow-hidden rounded-[20px] border border-emerald-300/15 bg-[#e9edf2] shadow-[inset_0_0_0_1px_rgba(255,255,255,0.75)]"
|
||||
style={{ zIndex }}
|
||||
>
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_22%_18%,rgba(255,255,255,0.95),transparent_35%),linear-gradient(135deg,#eef2f6_0%,#dce4ec_45%,#f5f7fa_100%)]" />
|
||||
<div className="psd-assigned-preview-shimmer absolute inset-y-0 w-1/2 bg-[linear-gradient(105deg,transparent_0%,rgba(255,255,255,0.68)_48%,transparent_100%)]" />
|
||||
<div className="absolute inset-0 opacity-45 [background-image:linear-gradient(rgba(15,23,42,0.045)_1px,transparent_1px),linear-gradient(90deg,rgba(15,23,42,0.04)_1px,transparent_1px)] [background-size:44px_44px]" />
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center px-10 text-center">
|
||||
<div className="mb-4 flex h-14 w-14 items-center justify-center rounded-2xl border border-white/70 bg-white/60 shadow-[0_18px_50px_rgba(15,23,42,0.12)] backdrop-blur">
|
||||
<Loader2 className="h-7 w-7 animate-spin text-emerald-500" />
|
||||
</div>
|
||||
<div className="rounded-full border border-emerald-500/15 bg-white/70 px-4 py-1.5 font-semibold text-[13px] text-slate-700 shadow-sm backdrop-blur">
|
||||
正在套入商品图
|
||||
</div>
|
||||
<div className="mt-3 max-w-[360px] text-[12px] text-slate-500 leading-relaxed">
|
||||
{pendingCount > 1
|
||||
? `正在加载 ${pendingCount} 个图片图层,完成后自动显示模板预览。`
|
||||
: "原图加载中,完成后自动显示模板预览。"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getScrollAreaViewportElement(root: HTMLDivElement | null) {
|
||||
return (
|
||||
(root?.querySelector(
|
||||
@ -1851,6 +1888,9 @@ export function AgentPsdTemplateEditorDialog({
|
||||
const [imageSizes, setImageSizes] = useState<
|
||||
Record<string, AgentPsdImageSize>
|
||||
>({});
|
||||
const [loadedAssignedPreviewUrls, setLoadedAssignedPreviewUrls] = useState<
|
||||
Record<string, string>
|
||||
>({});
|
||||
const [layerOrderIds, setLayerOrderIds] = useState<string[]>([]);
|
||||
const [layerPositionOffsets, setLayerPositionOffsets] = useState<
|
||||
Record<string, AgentPsdLayerPositionOffset>
|
||||
@ -2255,6 +2295,33 @@ export function AgentPsdTemplateEditorDialog({
|
||||
|
||||
return nextAssignments;
|
||||
}, [editableImageLayers, imageAssignments, selectedTemplate, sourceImageUrl]);
|
||||
const pendingAssignedPreviewLayerIds = useMemo(
|
||||
() =>
|
||||
orderedVisiblePreviewLayers
|
||||
.filter((layer): layer is AgentPsdTemplateImageLayerSlot =>
|
||||
isAgentPsdImageLayerSlot(layer)
|
||||
)
|
||||
.map((layer) => {
|
||||
const assignedUrl = String(
|
||||
effectiveImageAssignments[layer.id] || ""
|
||||
).trim();
|
||||
if (!assignedUrl) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return loadedAssignedPreviewUrls[layer.id] === assignedUrl
|
||||
? ""
|
||||
: layer.id;
|
||||
})
|
||||
.filter(Boolean),
|
||||
[
|
||||
effectiveImageAssignments,
|
||||
loadedAssignedPreviewUrls,
|
||||
orderedVisiblePreviewLayers,
|
||||
]
|
||||
);
|
||||
const assignedPreviewLoadingOverlayZIndex =
|
||||
(orderedPreviewLayers.length + 12) * PSD_LAYER_Z_INDEX_STEP;
|
||||
|
||||
const effectiveTextAssignments = useMemo(() => {
|
||||
const nextAssignments: Record<string, string> = {};
|
||||
@ -2872,6 +2939,7 @@ export function AgentPsdTemplateEditorDialog({
|
||||
setImageAssignments({});
|
||||
setImagePlacements({});
|
||||
setImageSizes({});
|
||||
setLoadedAssignedPreviewUrls({});
|
||||
setTextAssignments({});
|
||||
setTextColorAssignments({});
|
||||
setTextPositionOffsets({});
|
||||
@ -2915,6 +2983,7 @@ export function AgentPsdTemplateEditorDialog({
|
||||
setImageAssignments(initialState.imageAssignments);
|
||||
setImagePlacements(initialState.imagePlacements);
|
||||
setLayerOrderIds(initialState.layerOrderIds);
|
||||
setLoadedAssignedPreviewUrls({});
|
||||
setLayerPositionOffsets(initialState.layerPositionOffsets);
|
||||
setTextAssignments(initialState.textAssignments);
|
||||
setTextColorAssignments(initialState.textColorAssignments);
|
||||
@ -3966,6 +4035,18 @@ export function AgentPsdTemplateEditorDialog({
|
||||
.psd-layer-visibility-scroll::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(16, 185, 129, 0.75);
|
||||
}
|
||||
.psd-assigned-preview-shimmer {
|
||||
transform: translateX(-110%);
|
||||
animation: psd-assigned-preview-shimmer 1.55s ease-in-out infinite;
|
||||
}
|
||||
@keyframes psd-assigned-preview-shimmer {
|
||||
0% {
|
||||
transform: translateX(-110%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(210%);
|
||||
}
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
@ -4398,6 +4479,22 @@ export function AgentPsdTemplateEditorDialog({
|
||||
{assignedUrl ? (
|
||||
<AssignedPsdLayerPreviewImage
|
||||
alt={layer.layerName}
|
||||
onLoadComplete={(loadedUrl) => {
|
||||
setLoadedAssignedPreviewUrls(
|
||||
(current) => {
|
||||
if (
|
||||
current[layer.id] === loadedUrl
|
||||
) {
|
||||
return current;
|
||||
}
|
||||
|
||||
return {
|
||||
...current,
|
||||
[layer.id]: loadedUrl,
|
||||
};
|
||||
}
|
||||
);
|
||||
}}
|
||||
quality={74}
|
||||
sourceUrl={layerImageUrl}
|
||||
style={
|
||||
@ -4911,6 +5008,13 @@ export function AgentPsdTemplateEditorDialog({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{pendingAssignedPreviewLayerIds.length > 0 ? (
|
||||
<PsdAssignedImageLoadingOverlay
|
||||
pendingCount={pendingAssignedPreviewLayerIds.length}
|
||||
zIndex={assignedPreviewLoadingOverlayZIndex}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user