구분선 리사이즈 개선

This commit is contained in:
dohyeons 2025-12-19 18:19:29 +09:00
parent 8d34b73a45
commit 8789b2b864
3 changed files with 62 additions and 28 deletions

View File

@ -310,11 +310,26 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
const boundedWidth = Math.min(newWidth, maxWidth);
const boundedHeight = Math.min(newHeight, maxHeight);
// Grid Snap 적용
updateComponent(component.id, {
width: snapValueToGrid(boundedWidth),
height: snapValueToGrid(boundedHeight),
});
// 구분선은 방향에 따라 한 축만 조절 가능
if (component.type === "divider") {
if (component.orientation === "vertical") {
// 세로 구분선: 높이만 조절
updateComponent(component.id, {
height: snapValueToGrid(boundedHeight),
});
} else {
// 가로 구분선: 너비만 조절
updateComponent(component.id, {
width: snapValueToGrid(boundedWidth),
});
}
} else {
// Grid Snap 적용
updateComponent(component.id, {
width: snapValueToGrid(boundedWidth),
height: snapValueToGrid(boundedHeight),
});
}
}
};
@ -546,21 +561,23 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
);
case "divider":
const lineWidth = component.lineWidth || 1;
const lineColor = component.lineColor || "#000000";
// 구분선 (가로: 너비만 조절, 세로: 높이만 조절)
const dividerLineWidth = component.lineWidth || 1;
const dividerLineColor = component.lineColor || "#000000";
const isHorizontal = component.orientation !== "vertical";
return (
<div className="flex h-full w-full items-center justify-center">
<div className={`flex h-full w-full ${isHorizontal ? "items-center" : "justify-center"}`}>
<div
style={{
width: component.orientation === "horizontal" ? "100%" : `${lineWidth}px`,
height: component.orientation === "vertical" ? "100%" : `${lineWidth}px`,
backgroundColor: lineColor,
width: isHorizontal ? "100%" : `${dividerLineWidth}px`,
height: isHorizontal ? `${dividerLineWidth}px` : "100%",
backgroundColor: dividerLineColor,
...(component.lineStyle === "dashed" && {
backgroundImage: `repeating-linear-gradient(
${component.orientation === "horizontal" ? "90deg" : "0deg"},
${lineColor} 0px,
${lineColor} 10px,
${isHorizontal ? "90deg" : "0deg"},
${dividerLineColor} 0px,
${dividerLineColor} 10px,
transparent 10px,
transparent 20px
)`,
@ -568,19 +585,18 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
}),
...(component.lineStyle === "dotted" && {
backgroundImage: `repeating-linear-gradient(
${component.orientation === "horizontal" ? "90deg" : "0deg"},
${lineColor} 0px,
${lineColor} 3px,
${isHorizontal ? "90deg" : "0deg"},
${dividerLineColor} 0px,
${dividerLineColor} 3px,
transparent 3px,
transparent 10px
)`,
backgroundColor: "transparent",
}),
...(component.lineStyle === "double" && {
boxShadow:
component.orientation === "horizontal"
? `0 ${lineWidth * 2}px 0 0 ${lineColor}`
: `${lineWidth * 2}px 0 0 0 ${lineColor}`,
boxShadow: isHorizontal
? `0 ${dividerLineWidth * 2}px 0 0 ${dividerLineColor}`
: `${dividerLineWidth * 2}px 0 0 0 ${dividerLineColor}`,
}),
}}
/>
@ -1093,7 +1109,7 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
return (
<div
ref={componentRef}
className={`absolute p-2 shadow-sm ${isLocked ? "cursor-not-allowed opacity-80" : "cursor-move"} ${
className={`absolute ${component.type === "divider" ? "p-0" : "p-2"} shadow-sm ${isLocked ? "cursor-not-allowed opacity-80" : "cursor-move"} ${
isSelected
? isLocked
? "ring-2 ring-red-500"
@ -1132,8 +1148,20 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
{/* 리사이즈 핸들 (선택된 경우만, 잠금 안 된 경우만) */}
{isSelected && !isLocked && (
<div
className="resize-handle absolute right-0 bottom-0 h-3 w-3 cursor-se-resize rounded-full bg-blue-500"
style={{ transform: "translate(50%, 50%)" }}
className={`resize-handle absolute h-3 w-3 rounded-full bg-blue-500 ${
component.type === "divider"
? component.orientation === "vertical"
? "bottom-0 left-1/2 cursor-s-resize" // 세로 구분선: 하단 중앙
: "right-0 top-1/2 cursor-e-resize" // 가로 구분선: 우측 중앙
: "right-0 bottom-0 cursor-se-resize" // 일반 컴포넌트: 우하단
}`}
style={{
transform: component.type === "divider"
? component.orientation === "vertical"
? "translate(-50%, 50%)" // 세로 구분선
: "translate(50%, -50%)" // 가로 구분선
: "translate(50%, 50%)" // 일반 컴포넌트
}}
onMouseDown={handleResizeStart}
/>
)}

View File

@ -58,7 +58,7 @@ export function ReportDesignerCanvas() {
height = 150;
} else if (item.componentType === "divider") {
width = 300;
height = 2;
height = 10; // 선 두께 + 여백 (선택/드래그를 위한 최소 높이)
} else if (item.componentType === "signature") {
width = 120;
height = 70;

View File

@ -562,11 +562,17 @@ export function ReportDesignerRightPanel() {
<Label className="text-xs"></Label>
<Select
value={selectedComponent.orientation || "horizontal"}
onValueChange={(value) =>
onValueChange={(value) => {
// 방향 변경 시 너비/높이 스왑
const isToVertical = value === "vertical";
const currentWidth = selectedComponent.width;
const currentHeight = selectedComponent.height;
updateComponent(selectedComponent.id, {
orientation: value as "horizontal" | "vertical",
})
}
width: isToVertical ? 10 : currentWidth > 50 ? currentWidth : 300,
height: isToVertical ? currentWidth > 50 ? currentWidth : 300 : 10,
});
}}
>
<SelectTrigger className="h-8">
<SelectValue />