jskim-node #421
|
|
@ -592,10 +592,10 @@ const RealtimePreviewDynamicComponent: React.FC<RealtimePreviewProps> = ({
|
||||||
isResizing ? "none" :
|
isResizing ? "none" :
|
||||||
isOnSplitPanel ? (isDraggingSplitPanel ? "none" : "left 0.15s ease-out, width 0.15s ease-out") : undefined,
|
isOnSplitPanel ? (isDraggingSplitPanel ? "none" : "left 0.15s ease-out, width 0.15s ease-out") : undefined,
|
||||||
} : {
|
} : {
|
||||||
// 런타임 모드: 부모(ResponsiveGridRenderer)가 위치/너비 관리
|
// 런타임 모드: CSS scale 기반 - 캔버스 픽셀 크기 그대로 사용, 부모가 scale()로 축소
|
||||||
...safeComponentStyle,
|
...safeComponentStyle,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: displayHeight,
|
height: "100%",
|
||||||
position: "relative" as const,
|
position: "relative" as const,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,9 @@ function getComponentTypeId(component: ComponentData): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 디자이너 절대좌표를 캔버스 대비 비율로 변환하여 렌더링.
|
* CSS transform scale 기반 렌더링.
|
||||||
* 화면이 줄어들면 비율에 맞게 축소, 늘어나면 확대.
|
* 디자이너와 동일하게 캔버스 해상도(px)로 레이아웃 후 CSS scale로 축소/확대.
|
||||||
|
* 텍스트, 패딩, 버튼 등 모든 요소가 균일하게 스케일링되어 WYSIWYG 보장.
|
||||||
*/
|
*/
|
||||||
function ProportionalRenderer({
|
function ProportionalRenderer({
|
||||||
components,
|
components,
|
||||||
|
|
@ -47,7 +48,7 @@ function ProportionalRenderer({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const topLevel = components.filter((c) => !c.parentId);
|
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 maxBottom = topLevel.reduce((max, c) => {
|
||||||
const bottom = c.position.y + (c.size?.height || 40);
|
const bottom = c.position.y + (c.size?.height || 40);
|
||||||
|
|
@ -58,11 +59,20 @@ function ProportionalRenderer({
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
data-screen-runtime="true"
|
data-screen-runtime="true"
|
||||||
className="bg-background relative w-full overflow-x-hidden"
|
className="bg-background w-full overflow-hidden"
|
||||||
style={{ minHeight: containerW > 0 ? `${maxBottom * ratio}px` : "200px" }}
|
style={{ height: containerW > 0 ? `${maxBottom * scale}px` : "200px" }}
|
||||||
>
|
>
|
||||||
{containerW > 0 &&
|
{containerW > 0 && (
|
||||||
topLevel.map((component) => {
|
<div
|
||||||
|
style={{
|
||||||
|
width: `${canvasWidth}px`,
|
||||||
|
height: `${maxBottom}px`,
|
||||||
|
transform: `scale(${scale})`,
|
||||||
|
transformOrigin: "top left",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{topLevel.map((component) => {
|
||||||
const typeId = getComponentTypeId(component);
|
const typeId = getComponentTypeId(component);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -71,10 +81,10 @@ function ProportionalRenderer({
|
||||||
data-component-type={typeId}
|
data-component-type={typeId}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: `${(component.position.x / canvasWidth) * 100}%`,
|
left: `${component.position.x}px`,
|
||||||
top: `${component.position.y * ratio}px`,
|
top: `${component.position.y}px`,
|
||||||
width: `${((component.size?.width || 100) / canvasWidth) * 100}%`,
|
width: `${component.size?.width || 100}px`,
|
||||||
height: `${(component.size?.height || 40) * ratio}px`,
|
height: `${component.size?.height || 40}px`,
|
||||||
zIndex: component.position.z || 1,
|
zIndex: component.position.z || 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -83,6 +93,8 @@ function ProportionalRenderer({
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2522,9 +2522,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
|
|
||||||
// 우측 패널 컬럼 헤더 드래그 (디자인 모드에서 컬럼 순서 변경)
|
// 우측 패널 컬럼 헤더 드래그 (디자인 모드에서 컬럼 순서 변경)
|
||||||
const handleRightColumnDragStart = useCallback(
|
const handleRightColumnDragStart = useCallback(
|
||||||
(columnIndex: number, source: "main" | number) => {
|
(e: React.DragEvent, columnIndex: number, source: "main" | number) => {
|
||||||
setRightDraggedColumnIndex(columnIndex);
|
setRightDraggedColumnIndex(columnIndex);
|
||||||
setRightDragSource(source);
|
setRightDragSource(source);
|
||||||
|
e.dataTransfer.effectAllowed = "move";
|
||||||
|
e.dataTransfer.setData("text/plain", `col-${source}-${columnIndex}`);
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
@ -4181,7 +4183,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
isDragging && "opacity-50",
|
isDragging && "opacity-50",
|
||||||
)}
|
)}
|
||||||
draggable={canDragTabColumns}
|
draggable={canDragTabColumns}
|
||||||
onDragStart={() => canDragTabColumns && handleRightColumnDragStart(idx, tabIndex)}
|
onDragStart={(e) => canDragTabColumns && handleRightColumnDragStart(e, idx, tabIndex)}
|
||||||
onDragOver={(e) => canDragTabColumns && handleRightColumnDragOver(e, idx)}
|
onDragOver={(e) => canDragTabColumns && handleRightColumnDragOver(e, idx)}
|
||||||
onDragEnd={handleRightColumnDragEnd}
|
onDragEnd={handleRightColumnDragEnd}
|
||||||
onDrop={(e) => canDragTabColumns && handleRightColumnDrop(e, idx, tabIndex)}
|
onDrop={(e) => canDragTabColumns && handleRightColumnDrop(e, idx, tabIndex)}
|
||||||
|
|
@ -4318,7 +4320,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
isDragging && "opacity-50",
|
isDragging && "opacity-50",
|
||||||
)}
|
)}
|
||||||
draggable={canDragListTabColumns}
|
draggable={canDragListTabColumns}
|
||||||
onDragStart={() => canDragListTabColumns && handleRightColumnDragStart(idx, listTabIndex)}
|
onDragStart={(e) => canDragListTabColumns && handleRightColumnDragStart(e, idx, listTabIndex)}
|
||||||
onDragOver={(e) => canDragListTabColumns && handleRightColumnDragOver(e, idx)}
|
onDragOver={(e) => canDragListTabColumns && handleRightColumnDragOver(e, idx)}
|
||||||
onDragEnd={handleRightColumnDragEnd}
|
onDragEnd={handleRightColumnDragEnd}
|
||||||
onDrop={(e) => canDragListTabColumns && handleRightColumnDrop(e, idx, listTabIndex)}
|
onDrop={(e) => canDragListTabColumns && handleRightColumnDrop(e, idx, listTabIndex)}
|
||||||
|
|
@ -4745,7 +4747,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
textAlign: col.align || "left",
|
textAlign: col.align || "left",
|
||||||
}}
|
}}
|
||||||
draggable={isDraggable}
|
draggable={isDraggable}
|
||||||
onDragStart={() => isDraggable && handleRightColumnDragStart(configColIndex, "main")}
|
onDragStart={(e) => isDraggable && handleRightColumnDragStart(e, configColIndex, "main")}
|
||||||
onDragOver={(e) => isDraggable && handleRightColumnDragOver(e, configColIndex)}
|
onDragOver={(e) => isDraggable && handleRightColumnDragOver(e, configColIndex)}
|
||||||
onDragEnd={handleRightColumnDragEnd}
|
onDragEnd={handleRightColumnDragEnd}
|
||||||
onDrop={(e) => isDraggable && handleRightColumnDrop(e, configColIndex, "main")}
|
onDrop={(e) => isDraggable && handleRightColumnDrop(e, configColIndex, "main")}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue