diff --git a/frontend/components/screen/ScreenList.tsx b/frontend/components/screen/ScreenList.tsx index eff55312..8e5ba1d2 100644 --- a/frontend/components/screen/ScreenList.tsx +++ b/frontend/components/screen/ScreenList.tsx @@ -48,6 +48,8 @@ import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRendere import { DynamicWebTypeRenderer } from "@/lib/registry"; import { isFileComponent, getComponentWebType } from "@/lib/utils/componentTypeUtils"; import { TableOptionsProvider } from "@/contexts/TableOptionsContext"; +import { RealtimePreview } from "./RealtimePreviewDynamic"; +import { ScreenPreviewProvider } from "@/contexts/ScreenPreviewContext"; // InteractiveScreenViewer를 동적으로 import (SSR 비활성화) const InteractiveScreenViewer = dynamic( @@ -1316,8 +1318,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr 화면 미리보기 - {screenToPreview?.screenName} - -
+ + +
{isLoadingPreview ? (
@@ -1331,10 +1334,24 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr const screenHeight = previewLayout.screenResolution?.height || 800; // 모달 내부 가용 공간 계산 (헤더, 푸터, 패딩 제외) - const availableWidth = typeof window !== "undefined" ? window.innerWidth * 0.95 - 100 : 1800; // 95vw - 패딩 + const modalPadding = 100; // 헤더 + 푸터 + 패딩 + const availableWidth = typeof window !== "undefined" ? window.innerWidth * 0.95 - modalPadding : 1700; + const availableHeight = typeof window !== "undefined" ? window.innerHeight * 0.95 - modalPadding : 900; - // 가로폭 기준으로 스케일 계산 (가로폭에 맞춤) - const scale = availableWidth / screenWidth; + // 가로/세로 비율을 모두 고려하여 작은 쪽에 맞춤 (화면이 잘리지 않도록) + const scaleX = availableWidth / screenWidth; + const scaleY = availableHeight / screenHeight; + const scale = Math.min(scaleX, scaleY, 1); // 최대 1배율 (확대 방지) + + console.log("📐 미리보기 스케일 계산:", { + screenWidth, + screenHeight, + availableWidth, + availableHeight, + scaleX, + scaleY, + finalScale: scale, + }); return (
- {/* 라벨을 외부에 별도로 렌더링 */} - {shouldShowLabel && ( -
- {labelText} - {component.required && *} -
- )} + {}} + screenId={screenToPreview!.screenId} + tableName={screenToPreview?.tableName} + formData={previewFormData} + onFormDataChange={(fieldName, value) => { + setPreviewFormData((prev) => ({ + ...prev, + [fieldName]: value, + })); + }} + > + {/* 자식 컴포넌트들 */} + {(component.type === "group" || + component.type === "container" || + component.type === "area") && + previewLayout.components + .filter((child: any) => child.parentId === component.id) + .map((child: any) => { + // 자식 컴포넌트의 위치를 부모 기준 상대 좌표로 조정 + const relativeChildComponent = { + ...child, + position: { + x: child.position.x - component.position.x, + y: child.position.y - component.position.y, + z: child.position.z || 1, + }, + }; - {/* 실제 컴포넌트 */} -
{ - const style = { - position: "absolute" as const, - left: `${component.position.x}px`, - top: `${component.position.y}px`, - width: component.style?.width || `${component.size.width}px`, - height: component.style?.height || `${component.size.height}px`, - zIndex: component.position.z || 1, - }; - - return style; - })()} - > - {/* 위젯 컴포넌트가 아닌 경우 DynamicComponentRenderer 사용 */} - {component.type !== "widget" ? ( - { - setPreviewFormData((prev) => ({ - ...prev, - [fieldName]: value, - })); - }} - screenId={screenToPreview!.screenId} - tableName={screenToPreview?.tableName} - /> - ) : ( - { - // 유틸리티 함수로 파일 컴포넌트 감지 - if (isFileComponent(component)) { - return "file"; - } - // 다른 컴포넌트는 유틸리티 함수로 webType 결정 - return getComponentWebType(component) || "text"; - })()} - config={component.webTypeConfig} - props={{ - component: component, - value: previewFormData[component.columnName || component.id] || "", - onChange: (value: any) => { - const fieldName = component.columnName || component.id; - setPreviewFormData((prev) => ({ - ...prev, - [fieldName]: value, - })); - }, - onFormDataChange: (fieldName, value) => { - setPreviewFormData((prev) => ({ - ...prev, - [fieldName]: value, - })); - }, - isInteractive: true, - formData: previewFormData, - readonly: component.readonly, - required: component.required, - placeholder: component.placeholder, - className: "w-full h-full", - }} - /> - )} -
-
+ return ( + {}} + screenId={screenToPreview!.screenId} + tableName={screenToPreview?.tableName} + formData={previewFormData} + onFormDataChange={(fieldName, value) => { + setPreviewFormData((prev) => ({ + ...prev, + [fieldName]: value, + })); + }} + /> + ); + })} + ); })}
@@ -1538,8 +1501,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
)} -
-
+ + +