From 2c099feea0644b7e8ff546900ccb490f43449e67 Mon Sep 17 00:00:00 2001 From: kjs Date: Mon, 17 Nov 2025 10:09:02 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A1=B0=EA=B1=B4=EB=B6=80=20=EC=BB=A8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=84=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConditionalContainerComponent.tsx | 34 ++++++- .../ConditionalSectionViewer.tsx | 90 ++++++++++++------- .../components/conditional-container/index.ts | 8 +- .../components/conditional-container/types.ts | 4 + 4 files changed, 97 insertions(+), 39 deletions(-) diff --git a/frontend/lib/registry/components/conditional-container/ConditionalContainerComponent.tsx b/frontend/lib/registry/components/conditional-container/ConditionalContainerComponent.tsx index 66c7b698..ea50c849 100644 --- a/frontend/lib/registry/components/conditional-container/ConditionalContainerComponent.tsx +++ b/frontend/lib/registry/components/conditional-container/ConditionalContainerComponent.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { Label } from "@/components/ui/label"; import { Select, @@ -34,6 +34,8 @@ export function ConditionalContainerComponent({ onDeleteComponent, onSelectComponent, selectedComponentId, + onHeightChange, + componentId, style, className, }: ConditionalContainerProps) { @@ -70,6 +72,33 @@ export function ConditionalContainerComponent({ } }; + // 컨테이너 높이 측정용 ref + const containerRef = useRef(null); + const previousHeightRef = useRef(0); + + // 높이 변화 감지 및 콜백 호출 + useEffect(() => { + if (!containerRef.current || isDesignMode || !onHeightChange) return; + + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const newHeight = entry.contentRect.height; + + // 높이가 실제로 변경되었을 때만 콜백 호출 + if (Math.abs(newHeight - previousHeightRef.current) > 5) { + console.log(`📏 조건부 컨테이너 높이 변화: ${previousHeightRef.current}px → ${newHeight}px`); + previousHeightRef.current = newHeight; + onHeightChange(newHeight); + } + } + }); + + resizeObserver.observe(containerRef.current); + + return () => { + resizeObserver.disconnect(); + }; + }, [isDesignMode, onHeightChange, selectedValue]); // selectedValue 변경 시에도 감지 // 간격 스타일 const spacingClass = { @@ -80,6 +109,7 @@ export function ConditionalContainerComponent({ return (
@@ -106,7 +136,7 @@ export function ConditionalContainerComponent({
{/* 조건별 섹션들 */} -
+
{isDesignMode ? ( // 디자인 모드: 모든 섹션 표시
diff --git a/frontend/lib/registry/components/conditional-container/ConditionalSectionViewer.tsx b/frontend/lib/registry/components/conditional-container/ConditionalSectionViewer.tsx index 9f17c5eb..229f52f2 100644 --- a/frontend/lib/registry/components/conditional-container/ConditionalSectionViewer.tsx +++ b/frontend/lib/registry/components/conditional-container/ConditionalSectionViewer.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { ConditionalSectionViewerProps } from "./types"; -import { InteractiveScreenViewer } from "@/components/screen/InteractiveScreenViewer"; +import { RealtimePreview } from "@/components/screen/RealtimePreviewDynamic"; import { cn } from "@/lib/utils"; import { Loader2 } from "lucide-react"; import { screenApi } from "@/lib/api/screen"; @@ -27,32 +27,33 @@ export function ConditionalSectionViewer({ const [isLoading, setIsLoading] = useState(false); const [components, setComponents] = useState([]); const [screenInfo, setScreenInfo] = useState<{ id: number; tableName?: string } | null>(null); + const [screenResolution, setScreenResolution] = useState<{ width: number; height: number } | null>(null); // 화면 로드 useEffect(() => { if (!screenId) { setComponents([]); setScreenInfo(null); + setScreenResolution(null); return; } const loadScreen = async () => { setIsLoading(true); try { - const [layout, screen] = await Promise.all([ - screenApi.getLayout(screenId), - screenApi.getScreen(screenId), - ]); + const [layout, screen] = await Promise.all([screenApi.getLayout(screenId), screenApi.getScreen(screenId)]); setComponents(layout.components || []); setScreenInfo({ id: screenId, tableName: screen.tableName, }); + setScreenResolution(layout.screenResolution || null); } catch (error) { console.error("화면 로드 실패:", error); setComponents([]); setScreenInfo(null); + setScreenResolution(null); } finally { setIsLoading(false); } @@ -69,20 +70,18 @@ export function ConditionalSectionViewer({ return (
{/* 섹션 라벨 (디자인 모드에서만 표시) */} {isDesignMode && ( -
+
{label} {isActive && "(활성)"} {screenId && ` - 화면 ID: ${screenId}`}
@@ -91,40 +90,65 @@ export function ConditionalSectionViewer({ {/* 화면 미선택 안내 (디자인 모드 + 화면 없을 때) */} {isDesignMode && !screenId && (
-
+

설정 패널에서 화면을 선택하세요

-

조건: {condition}

+

조건: {condition}

)} {/* 로딩 중 */} {isLoading && ( -
+
- -

화면 로드 중...

+ +

화면 로드 중...

)} {/* 화면 렌더링 */} {screenId && components.length > 0 && ( -
- {components.map((component) => ( - - ))} -
+ <> + {isDesignMode ? ( + /* 디자인 모드: 화면 정보만 표시 */ +
+
+

{screenName || `화면 ID: ${screenId}`}

+

+ {screenResolution?.width} x {screenResolution?.height} +

+

컴포넌트 {components.length}개

+
+
+ ) : ( + /* 실행 모드: 실제 화면 렌더링 */ +
+ {/* 화면 크기만큼의 절대 위치 캔버스 */} +
+ {components.map((component) => ( + {}} + screenId={screenInfo?.id} + tableName={screenInfo?.tableName} + /> + ))} +
+
+ )} + )}
); } - diff --git a/frontend/lib/registry/components/conditional-container/index.ts b/frontend/lib/registry/components/conditional-container/index.ts index 82592305..e4e31feb 100644 --- a/frontend/lib/registry/components/conditional-container/index.ts +++ b/frontend/lib/registry/components/conditional-container/index.ts @@ -20,8 +20,8 @@ export const ConditionalContainerDefinition: Omit< tags: ["조건부", "분기", "동적", "레이아웃"], defaultSize: { - width: 800, - height: 600, + width: 1400, + height: 800, }, defaultConfig: { @@ -48,8 +48,8 @@ export const ConditionalContainerDefinition: Omit< defaultProps: { style: { - width: "800px", - height: "600px", + width: "1400px", + height: "800px", }, }, diff --git a/frontend/lib/registry/components/conditional-container/types.ts b/frontend/lib/registry/components/conditional-container/types.ts index b0893c5e..6f1964e9 100644 --- a/frontend/lib/registry/components/conditional-container/types.ts +++ b/frontend/lib/registry/components/conditional-container/types.ts @@ -53,6 +53,10 @@ export interface ConditionalContainerProps { onSelectComponent?: (componentId: string) => void; selectedComponentId?: string; + // 높이 변화 알림 (아래 컴포넌트 재배치용) + onHeightChange?: (newHeight: number) => void; + componentId?: string; // 자신의 컴포넌트 ID + // 스타일 style?: React.CSSProperties; className?: string;