feat: redesign psd scale control and fix >100% scaling behavior
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-01 19:41:13 +08:00
parent ae254d7bc5
commit c202dd48a8

View File

@ -83,6 +83,15 @@ const PREVIEW_VIEWPORT_PADDING = 56;
const PREVIEW_STAGE_MAX_SCALE = 0.82;
const PREVIEW_STAGE_TARGET_WIDTH = 760;
const PREVIEW_STAGE_TARGET_HEIGHT = 760;
const MIN_IMAGE_SCALE = 0.4;
const MAX_IMAGE_SCALE = 3;
function clampImageScale(value: number) {
if (!Number.isFinite(value)) {
return 1;
}
return Math.max(MIN_IMAGE_SCALE, Math.min(MAX_IMAGE_SCALE, value));
}
function createInitialState(template: AgentPsdTemplate | null, sourceImageUrl: string) {
const imageAssignments: Record<string, string> = {};
@ -692,7 +701,7 @@ export function AgentPsdTemplateEditorDialog({
function nudgeImageScale(layerId: string, delta: number) {
updateImagePlacement(layerId, (current) => ({
...current,
scale: Math.max(0.4, Math.min(3, Number((current.scale + delta).toFixed(2)))),
scale: Number(clampImageScale(current.scale + delta).toFixed(2)),
}));
}
@ -1291,26 +1300,55 @@ export function AgentPsdTemplateEditorDialog({
<ZoomIn className="h-3.5 w-3.5" />
缩放
</div>
<span>{Math.round(selectedImagePlacement.scale * 100)}%</span>
<span className="rounded-full border border-orange-300/35 bg-orange-500/15 px-2 py-0.5 font-medium text-orange-100">
{Math.round(selectedImagePlacement.scale * 100)}%
</span>
</div>
<div className="rounded-xl border border-white/12 bg-black/45 p-2.5">
<div className="grid grid-cols-[34px_minmax(0,1fr)_34px] items-center gap-2">
<button
type="button"
className="flex h-8 w-8 items-center justify-center rounded-full border border-white/18 bg-white/[0.04] text-white transition-colors hover:bg-white/[0.12]"
onClick={() => nudgeImageScale(selectedImageLayer.id, -0.05)}
aria-label="缩小图片"
title="缩小"
>
<ZoomOut className="h-4 w-4" />
</button>
<Slider
min={MIN_IMAGE_SCALE}
max={MAX_IMAGE_SCALE}
step={0.01}
value={[selectedImagePlacement.scale]}
className="py-1"
trackClassName="h-2.5 rounded-full border border-white/20 bg-[#0f1014]"
rangeClassName="bg-gradient-to-r from-amber-300 via-orange-400 to-rose-400 shadow-[0_0_12px_rgba(251,146,60,0.45)]"
thumbClassName="h-5 w-5 border-2 border-orange-100 bg-[#0a0a0d] shadow-[0_0_0_5px_rgba(251,146,60,0.22)]"
onValueChange={(value) => {
const newScale = clampImageScale(value[0] || 1);
// offset 本身就是相对中心位移,缩放时不应按比例放大,否则会导致画面偏移看起来像“变形”。
updateImagePlacement(selectedImageLayer.id, (current) => ({
...current,
scale: newScale,
}));
}}
/>
<button
type="button"
className="flex h-8 w-8 items-center justify-center rounded-full border border-white/18 bg-white/[0.04] text-white transition-colors hover:bg-white/[0.12]"
onClick={() => nudgeImageScale(selectedImageLayer.id, 0.05)}
aria-label="放大图片"
title="放大"
>
<ZoomIn className="h-4 w-4" />
</button>
</div>
<div className="mt-2 flex items-center justify-between px-0.5 text-[10px] text-white/45">
<span>40%</span>
<span className="text-orange-200">100%</span>
<span>300%</span>
</div>
</div>
<Slider
min={0.4}
max={3}
step={0.01}
value={[selectedImagePlacement.scale]}
onValueChange={(value) => {
const newScale = value[0] || 1;
updateImagePlacement(selectedImageLayer.id, (current) => {
// 以中心点缩放,调整偏移量保持中心位置不变
const scaleDiff = newScale / current.scale;
return {
scale: newScale,
offsetX: current.offsetX * scaleDiff,
offsetY: current.offsetY * scaleDiff,
};
});
}}
/>
</div>
<div className="flex flex-wrap gap-2">
<Button