From e2f4b475888daa06111882e65adc42d5d67839a1 Mon Sep 17 00:00:00 2001 From: kjs Date: Mon, 10 Nov 2025 09:33:29 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EC=9E=98=20=EB=B3=B4?= =?UTF-8?q?=EC=9D=B4=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/common/ScreenModal.tsx | 10 ++- .../screen/InteractiveScreenViewer.tsx | 15 ++-- .../screen/InteractiveScreenViewerDynamic.tsx | 15 ++-- frontend/components/screen/SaveModal.tsx | 69 +++++++++++++++---- frontend/components/ui/resizable-dialog.tsx | 8 ++- 5 files changed, 85 insertions(+), 32 deletions(-) diff --git a/frontend/components/common/ScreenModal.tsx b/frontend/components/common/ScreenModal.tsx index 50423460..609c2b43 100644 --- a/frontend/components/common/ScreenModal.tsx +++ b/frontend/components/common/ScreenModal.tsx @@ -364,7 +364,7 @@ export const ScreenModal: React.FC = ({ className }) => { -
+
{loading ? (
@@ -374,13 +374,11 @@ export const ScreenModal: React.FC = ({ className }) => {
) : screenData ? (
{screenData.components.map((component) => { diff --git a/frontend/components/screen/InteractiveScreenViewer.tsx b/frontend/components/screen/InteractiveScreenViewer.tsx index 9c0076ee..472049ff 100644 --- a/frontend/components/screen/InteractiveScreenViewer.tsx +++ b/frontend/components/screen/InteractiveScreenViewer.tsx @@ -401,15 +401,14 @@ export const InteractiveScreenViewer: React.FC = ( const applyStyles = (element: React.ReactElement) => { if (!comp.style) return element; + // ✅ 격자 시스템 잔재 제거: style.width, style.height는 무시 + // size.width, size.height가 부모 컨테이너에서 적용되므로 + const { width, height, ...styleWithoutSize } = comp.style; + return React.cloneElement(element, { style: { ...element.props.style, // 기존 스타일 유지 - ...comp.style, - // 크기는 부모 컨테이너에서 처리하므로 제거 (하지만 다른 스타일은 유지) - width: "100%", - height: "100%", - minHeight: "100%", - maxHeight: "100%", + ...styleWithoutSize, // width/height 제외한 스타일만 적용 boxSizing: "border-box", }, }); @@ -1887,7 +1886,7 @@ export const InteractiveScreenViewer: React.FC = ( return ( <> -
+
{/* 라벨이 있는 경우 표시 (데이터 테이블 제외) */} {shouldShowLabel && (
{/* 개선된 검증 패널 (선택적 표시) */} diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index 7ad86f9c..1fb10716 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -343,10 +343,14 @@ export const InteractiveScreenViewerDynamic: React.FC { if (!comp.style) return element; + // ✅ 격자 시스템 잔재 제거: style.width, style.height는 무시 + // size.width, size.height가 부모 컨테이너에서 적용되므로 + const { width, height, ...styleWithoutSize } = comp.style; + return React.cloneElement(element, { style: { ...element.props.style, - ...comp.style, + ...styleWithoutSize, // width/height 제외한 스타일만 적용 width: "100%", height: "100%", minHeight: "100%", @@ -676,14 +680,17 @@ export const InteractiveScreenViewerDynamic: React.FC = ({ const calculateDynamicSize = () => { if (!components.length) return { width: 800, height: 600 }; - const maxX = Math.max(...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200))); - const maxY = Math.max(...components.map((c) => (c.position?.y || 0) + (c.size?.height || 40))); + const maxX = Math.max(...components.map((c) => { + const x = c.position?.x || 0; + const width = typeof c.size?.width === 'number' + ? c.size.width + : parseInt(String(c.size?.width || 200), 10); + return x + width; + })); + + const maxY = Math.max(...components.map((c) => { + const y = c.position?.y || 0; + const height = typeof c.size?.height === 'number' + ? c.size.height + : parseInt(String(c.size?.height || 40), 10); + return y + height; + })); const padding = 40; return { @@ -214,8 +227,15 @@ export const SaveModal: React.FC = ({ return ( !isSaving && !open && onClose()}> - - + +
{initialData ? "데이터 수정" : "데이터 등록"}
@@ -239,29 +259,51 @@ export const SaveModal: React.FC = ({
-
+
{loading ? (
) : screenData && components.length > 0 ? (
-
- {components.map((component, index) => ( +
+ {components.map((component, index) => { + // ✅ 격자 시스템 잔재 제거: size의 픽셀 값만 사용 + const widthPx = typeof component.size?.width === 'number' + ? component.size.width + : parseInt(String(component.size?.width || 200), 10); + const heightPx = typeof component.size?.height === 'number' + ? component.size.height + : parseInt(String(component.size?.height || 40), 10); + + // 디버깅: 실제 크기 확인 + if (index === 0) { + console.log('🔍 SaveModal 컴포넌트 크기:', { + componentId: component.id, + 'size.width (원본)': component.size?.width, + 'size.width 타입': typeof component.size?.width, + 'widthPx (계산)': widthPx, + 'style.width': component.style?.width, + }); + } + + return (
@@ -306,7 +348,8 @@ export const SaveModal: React.FC = ({ /> )}
- ))} + ); + })}
) : ( diff --git a/frontend/components/ui/resizable-dialog.tsx b/frontend/components/ui/resizable-dialog.tsx index facb07ca..9e953784 100644 --- a/frontend/components/ui/resizable-dialog.tsx +++ b/frontend/components/ui/resizable-dialog.tsx @@ -55,6 +55,7 @@ interface ResizableDialogContentProps modalId?: string; // localStorage 저장용 고유 ID userId?: string; // 사용자별 저장용 open?: boolean; // 🆕 모달 열림/닫힘 상태 (외부에서 전달) + disableFlexLayout?: boolean; // 🆕 flex 레이아웃 비활성화 (absolute 레이아웃용) } const ResizableDialogContent = React.forwardRef< @@ -74,6 +75,7 @@ const ResizableDialogContent = React.forwardRef< modalId, userId = "guest", open: externalOpen, // 🆕 외부에서 전달받은 open 상태 + disableFlexLayout = false, // 🆕 flex 레이아웃 비활성화 style: userStyle, ...props }, @@ -373,7 +375,11 @@ const ResizableDialogContent = React.forwardRef< minHeight: `${minHeight}px`, }} > -
+
{children}