diff --git a/frontend/components/screen/RealtimePreviewDynamic.tsx b/frontend/components/screen/RealtimePreviewDynamic.tsx index 14314a61..6330b8d4 100644 --- a/frontend/components/screen/RealtimePreviewDynamic.tsx +++ b/frontend/components/screen/RealtimePreviewDynamic.tsx @@ -592,10 +592,10 @@ const RealtimePreviewDynamicComponent: React.FC = ({ isResizing ? "none" : isOnSplitPanel ? (isDraggingSplitPanel ? "none" : "left 0.15s ease-out, width 0.15s ease-out") : undefined, } : { - // 런타임 모드: 부모(ResponsiveGridRenderer)가 위치/너비 관리 + // 런타임 모드: CSS scale 기반 - 캔버스 픽셀 크기 그대로 사용, 부모가 scale()로 축소 ...safeComponentStyle, width: "100%", - height: displayHeight, + height: "100%", position: "relative" as const, }; diff --git a/frontend/components/screen/ResponsiveGridRenderer.tsx b/frontend/components/screen/ResponsiveGridRenderer.tsx index 1322ee99..d90a0667 100644 --- a/frontend/components/screen/ResponsiveGridRenderer.tsx +++ b/frontend/components/screen/ResponsiveGridRenderer.tsx @@ -23,8 +23,9 @@ function getComponentTypeId(component: ComponentData): string { } /** - * 디자이너 절대좌표를 캔버스 대비 비율로 변환하여 렌더링. - * 화면이 줄어들면 비율에 맞게 축소, 늘어나면 확대. + * CSS transform scale 기반 렌더링. + * 디자이너와 동일하게 캔버스 해상도(px)로 레이아웃 후 CSS scale로 축소/확대. + * 텍스트, 패딩, 버튼 등 모든 요소가 균일하게 스케일링되어 WYSIWYG 보장. */ function ProportionalRenderer({ components, @@ -47,7 +48,7 @@ function ProportionalRenderer({ }, []); const topLevel = components.filter((c) => !c.parentId); - const ratio = containerW > 0 ? containerW / canvasWidth : 1; + const scale = containerW > 0 ? containerW / canvasWidth : 1; const maxBottom = topLevel.reduce((max, c) => { const bottom = c.position.y + (c.size?.height || 40); @@ -58,30 +59,41 @@ function ProportionalRenderer({
0 ? `${maxBottom * ratio}px` : "200px" }} + className="bg-background w-full overflow-hidden" + style={{ height: containerW > 0 ? `${maxBottom * scale}px` : "200px" }} > - {containerW > 0 && - topLevel.map((component) => { - const typeId = getComponentTypeId(component); - return ( -
- {renderComponent(component)} -
- ); - })} + {containerW > 0 && ( +
+ {topLevel.map((component) => { + const typeId = getComponentTypeId(component); + return ( +
+ {renderComponent(component)} +
+ ); + })} +
+ )}
); } diff --git a/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx b/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx index 8467154a..fc244a3d 100644 --- a/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx +++ b/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx @@ -2522,9 +2522,11 @@ export const SplitPanelLayoutComponent: React.FC // 우측 패널 컬럼 헤더 드래그 (디자인 모드에서 컬럼 순서 변경) const handleRightColumnDragStart = useCallback( - (columnIndex: number, source: "main" | number) => { + (e: React.DragEvent, columnIndex: number, source: "main" | number) => { setRightDraggedColumnIndex(columnIndex); setRightDragSource(source); + e.dataTransfer.effectAllowed = "move"; + e.dataTransfer.setData("text/plain", `col-${source}-${columnIndex}`); }, [], ); @@ -4181,7 +4183,7 @@ export const SplitPanelLayoutComponent: React.FC isDragging && "opacity-50", )} draggable={canDragTabColumns} - onDragStart={() => canDragTabColumns && handleRightColumnDragStart(idx, tabIndex)} + onDragStart={(e) => canDragTabColumns && handleRightColumnDragStart(e, idx, tabIndex)} onDragOver={(e) => canDragTabColumns && handleRightColumnDragOver(e, idx)} onDragEnd={handleRightColumnDragEnd} onDrop={(e) => canDragTabColumns && handleRightColumnDrop(e, idx, tabIndex)} @@ -4318,7 +4320,7 @@ export const SplitPanelLayoutComponent: React.FC isDragging && "opacity-50", )} draggable={canDragListTabColumns} - onDragStart={() => canDragListTabColumns && handleRightColumnDragStart(idx, listTabIndex)} + onDragStart={(e) => canDragListTabColumns && handleRightColumnDragStart(e, idx, listTabIndex)} onDragOver={(e) => canDragListTabColumns && handleRightColumnDragOver(e, idx)} onDragEnd={handleRightColumnDragEnd} onDrop={(e) => canDragListTabColumns && handleRightColumnDrop(e, idx, listTabIndex)} @@ -4745,7 +4747,7 @@ export const SplitPanelLayoutComponent: React.FC textAlign: col.align || "left", }} draggable={isDraggable} - onDragStart={() => isDraggable && handleRightColumnDragStart(configColIndex, "main")} + onDragStart={(e) => isDraggable && handleRightColumnDragStart(e, configColIndex, "main")} onDragOver={(e) => isDraggable && handleRightColumnDragOver(e, configColIndex)} onDragEnd={handleRightColumnDragEnd} onDrop={(e) => isDraggable && handleRightColumnDrop(e, configColIndex, "main")}