스타일 적용안되던 문제 수정
This commit is contained in:
@@ -633,7 +633,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
// 격자 스냅 적용
|
||||
const snappedPosition =
|
||||
layout.gridSettings?.snapToGrid && gridInfo
|
||||
? snapToGrid({ x: dropX, y: dropY, z: 1 }, gridInfo, layout.gridSettings)
|
||||
? snapToGrid({ x: dropX, y: dropY, z: 1 }, gridInfo, layout.gridSettings as GridUtilSettings)
|
||||
: { x: dropX, y: dropY, z: 1 };
|
||||
|
||||
console.log("🎨 템플릿 드롭:", {
|
||||
@@ -644,8 +644,19 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
});
|
||||
|
||||
// 템플릿의 모든 컴포넌트들을 생성
|
||||
// 먼저 ID 매핑을 생성 (parentId 참조를 위해)
|
||||
const idMapping: Record<string, string> = {};
|
||||
template.components.forEach((templateComp, index) => {
|
||||
const newId = generateComponentId();
|
||||
if (index === 0) {
|
||||
// 첫 번째 컴포넌트(컨테이너)는 "form-container"로 매핑
|
||||
idMapping["form-container"] = newId;
|
||||
}
|
||||
idMapping[templateComp.parentId || `temp_${index}`] = newId;
|
||||
});
|
||||
|
||||
const newComponents: ComponentData[] = template.components.map((templateComp, index) => {
|
||||
const componentId = generateComponentId();
|
||||
const componentId = index === 0 ? idMapping["form-container"] : generateComponentId();
|
||||
|
||||
// 템플릿 컴포넌트의 상대 위치를 드롭 위치 기준으로 조정
|
||||
const absoluteX = snappedPosition.x + templateComp.position.x;
|
||||
@@ -654,17 +665,38 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
// 격자 스냅 적용
|
||||
const finalPosition =
|
||||
layout.gridSettings?.snapToGrid && gridInfo
|
||||
? snapToGrid({ x: absoluteX, y: absoluteY, z: 1 }, gridInfo, layout.gridSettings)
|
||||
? snapToGrid({ x: absoluteX, y: absoluteY, z: 1 }, gridInfo, layout.gridSettings as GridUtilSettings)
|
||||
: { x: absoluteX, y: absoluteY, z: 1 };
|
||||
|
||||
if (templateComp.type === "container") {
|
||||
// 그리드 컬럼 기반 크기 계산
|
||||
const gridColumns =
|
||||
typeof templateComp.size.width === "number" && templateComp.size.width <= 12 ? templateComp.size.width : 4; // 기본 4컬럼
|
||||
|
||||
const calculatedSize =
|
||||
gridInfo && layout.gridSettings?.snapToGrid
|
||||
? (() => {
|
||||
const newWidth = calculateWidthFromColumns(
|
||||
gridColumns,
|
||||
gridInfo,
|
||||
layout.gridSettings as GridUtilSettings,
|
||||
);
|
||||
return {
|
||||
width: newWidth,
|
||||
height: templateComp.size.height,
|
||||
};
|
||||
})()
|
||||
: { width: 400, height: templateComp.size.height }; // 폴백 크기
|
||||
|
||||
return {
|
||||
id: componentId,
|
||||
type: "container",
|
||||
label: templateComp.label,
|
||||
tableName: selectedScreen?.tableName || "",
|
||||
title: templateComp.title || templateComp.label,
|
||||
position: finalPosition,
|
||||
size: templateComp.size,
|
||||
size: calculatedSize,
|
||||
gridColumns,
|
||||
style: {
|
||||
labelDisplay: true,
|
||||
labelFontSize: "14px",
|
||||
@@ -817,6 +849,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
label: templateComp.label,
|
||||
placeholder: templateComp.placeholder,
|
||||
columnName: `field_${index + 1}`,
|
||||
parentId: templateComp.parentId ? idMapping[templateComp.parentId] : undefined,
|
||||
position: finalPosition,
|
||||
size: templateComp.size,
|
||||
required: templateComp.required || false,
|
||||
@@ -878,6 +911,11 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
|
||||
// 기존 테이블/컬럼 드래그 처리
|
||||
const { type, table, column } = parsedData;
|
||||
|
||||
// 드롭 대상이 폼 컨테이너인지 확인
|
||||
const dropTarget = e.target as HTMLElement;
|
||||
const formContainer = dropTarget.closest('[data-form-container="true"]');
|
||||
|
||||
const rect = canvasRef.current?.getBoundingClientRect();
|
||||
if (!rect) return;
|
||||
|
||||
@@ -1031,29 +1069,65 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
}
|
||||
};
|
||||
|
||||
// 컬럼 위젯 생성
|
||||
newComponent = {
|
||||
id: generateComponentId(),
|
||||
type: "widget",
|
||||
label: column.columnName,
|
||||
tableName: table.tableName,
|
||||
columnName: column.columnName,
|
||||
widgetType: column.widgetType,
|
||||
// dataType: column.dataType, // WidgetComponent에 dataType 속성이 없음
|
||||
required: column.required,
|
||||
readonly: false, // 누락된 속성 추가
|
||||
position: { x, y, z: 1 } as Position,
|
||||
size: { width: columnWidth, height: 40 },
|
||||
gridColumns: 1, // 기본 그리드 컬럼 수
|
||||
style: {
|
||||
labelDisplay: true,
|
||||
labelFontSize: "12px",
|
||||
labelColor: "#374151",
|
||||
labelFontWeight: "500",
|
||||
labelMarginBottom: "6px",
|
||||
},
|
||||
webTypeConfig: getDefaultWebTypeConfig(column.widgetType),
|
||||
};
|
||||
// 폼 컨테이너에 드롭한 경우
|
||||
if (formContainer) {
|
||||
const formContainerId = formContainer.getAttribute("data-component-id");
|
||||
const formContainerComponent = layout.components.find((c) => c.id === formContainerId);
|
||||
|
||||
if (formContainerComponent) {
|
||||
// 폼 내부에서의 상대적 위치 계산
|
||||
const containerRect = formContainer.getBoundingClientRect();
|
||||
const relativeX = e.clientX - containerRect.left;
|
||||
const relativeY = e.clientY - containerRect.top;
|
||||
|
||||
newComponent = {
|
||||
id: generateComponentId(),
|
||||
type: "widget",
|
||||
label: column.columnName,
|
||||
tableName: table.tableName,
|
||||
columnName: column.columnName,
|
||||
widgetType: column.widgetType,
|
||||
required: column.required,
|
||||
readonly: false,
|
||||
parentId: formContainerId, // 폼 컨테이너의 자식으로 설정
|
||||
position: { x: relativeX, y: relativeY, z: 1 } as Position,
|
||||
size: { width: 200, height: 40 },
|
||||
style: {
|
||||
labelDisplay: true,
|
||||
labelFontSize: "12px",
|
||||
labelColor: "#374151",
|
||||
labelFontWeight: "500",
|
||||
labelMarginBottom: "6px",
|
||||
},
|
||||
webTypeConfig: getDefaultWebTypeConfig(column.widgetType),
|
||||
};
|
||||
} else {
|
||||
return; // 폼 컨테이너를 찾을 수 없으면 드롭 취소
|
||||
}
|
||||
} else {
|
||||
// 일반 캔버스에 드롭한 경우 (기존 로직)
|
||||
newComponent = {
|
||||
id: generateComponentId(),
|
||||
type: "widget",
|
||||
label: column.columnName,
|
||||
tableName: table.tableName,
|
||||
columnName: column.columnName,
|
||||
widgetType: column.widgetType,
|
||||
required: column.required,
|
||||
readonly: false,
|
||||
position: { x, y, z: 1 } as Position,
|
||||
size: { width: columnWidth, height: 40 },
|
||||
gridColumns: 1,
|
||||
style: {
|
||||
labelDisplay: true,
|
||||
labelFontSize: "12px",
|
||||
labelColor: "#374151",
|
||||
labelFontWeight: "500",
|
||||
labelMarginBottom: "6px",
|
||||
},
|
||||
webTypeConfig: getDefaultWebTypeConfig(column.widgetType),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -2273,79 +2347,106 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
}
|
||||
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={`${component.id}-${component.type === "widget" ? JSON.stringify((component as any).webTypeConfig) : ""}`}
|
||||
component={displayComponent}
|
||||
isSelected={
|
||||
selectedComponent?.id === component.id || groupState.selectedComponents.includes(component.id)
|
||||
}
|
||||
onClick={(e) => handleComponentClick(component, e)}
|
||||
onDragStart={(e) => startComponentDrag(component, e)}
|
||||
onDragEnd={endDrag}
|
||||
<div
|
||||
key={component.id}
|
||||
className="absolute"
|
||||
style={{
|
||||
left: `${displayComponent.position.x}px`,
|
||||
top: `${displayComponent.position.y}px`,
|
||||
width: displayComponent.style?.width || `${displayComponent.size.width}px`,
|
||||
height: displayComponent.style?.height || `${displayComponent.size.height}px`,
|
||||
zIndex: displayComponent.position.z || 1,
|
||||
}}
|
||||
>
|
||||
{children.map((child) => {
|
||||
// 자식 컴포넌트에도 드래그 피드백 적용
|
||||
const isChildDraggingThis = dragState.isDragging && dragState.draggedComponent?.id === child.id;
|
||||
const isChildBeingDragged =
|
||||
dragState.isDragging && dragState.draggedComponents.some((dragComp) => dragComp.id === child.id);
|
||||
|
||||
let displayChild = child;
|
||||
|
||||
if (isChildBeingDragged) {
|
||||
if (isChildDraggingThis) {
|
||||
// 주 드래그 자식 컴포넌트
|
||||
displayChild = {
|
||||
...child,
|
||||
position: dragState.currentPosition,
|
||||
style: {
|
||||
...child.style,
|
||||
opacity: 0.8,
|
||||
transform: "scale(1.02)",
|
||||
transition: "none",
|
||||
zIndex: 9999,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// 다른 선택된 자식 컴포넌트들
|
||||
const originalChildComponent = dragState.draggedComponents.find(
|
||||
(dragComp) => dragComp.id === child.id,
|
||||
);
|
||||
if (originalChildComponent) {
|
||||
const deltaX = dragState.currentPosition.x - dragState.originalPosition.x;
|
||||
const deltaY = dragState.currentPosition.y - dragState.originalPosition.y;
|
||||
|
||||
displayChild = {
|
||||
...child,
|
||||
position: {
|
||||
x: originalChildComponent.position.x + deltaX,
|
||||
y: originalChildComponent.position.y + deltaY,
|
||||
z: originalChildComponent.position.z || 1,
|
||||
} as Position,
|
||||
style: {
|
||||
...child.style,
|
||||
opacity: 0.8,
|
||||
transition: "none",
|
||||
zIndex: 8888,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
<RealtimePreview
|
||||
component={displayComponent}
|
||||
isSelected={
|
||||
selectedComponent?.id === component.id || groupState.selectedComponents.includes(component.id)
|
||||
}
|
||||
onClick={(e) => handleComponentClick(component, e)}
|
||||
onDragStart={(e) => startComponentDrag(component, e)}
|
||||
onDragEnd={endDrag}
|
||||
>
|
||||
{/* 컨테이너 및 그룹의 자식 컴포넌트들 렌더링 */}
|
||||
{(component.type === "group" || component.type === "container") &&
|
||||
layout.components
|
||||
.filter((child) => child.parentId === component.id)
|
||||
.map((child) => {
|
||||
// 자식 컴포넌트에도 드래그 피드백 적용
|
||||
const isChildDraggingThis = dragState.isDragging && dragState.draggedComponent?.id === child.id;
|
||||
const isChildBeingDragged =
|
||||
dragState.isDragging &&
|
||||
dragState.draggedComponents.some((dragComp) => dragComp.id === child.id);
|
||||
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={`${child.id}-${child.type === "widget" ? JSON.stringify((child as any).webTypeConfig) : ""}`}
|
||||
component={displayChild}
|
||||
isSelected={
|
||||
selectedComponent?.id === child.id || groupState.selectedComponents.includes(child.id)
|
||||
}
|
||||
onClick={(e) => handleComponentClick(child, e)}
|
||||
onDragStart={(e) => startComponentDrag(child, e)}
|
||||
onDragEnd={endDrag}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RealtimePreview>
|
||||
let displayChild = child;
|
||||
|
||||
if (isChildBeingDragged) {
|
||||
if (isChildDraggingThis) {
|
||||
// 주 드래그 자식 컴포넌트
|
||||
displayChild = {
|
||||
...child,
|
||||
position: dragState.currentPosition,
|
||||
style: {
|
||||
...child.style,
|
||||
opacity: 0.8,
|
||||
transform: "scale(1.02)",
|
||||
transition: "none",
|
||||
zIndex: 9999,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// 다른 선택된 자식 컴포넌트들
|
||||
const originalChildComponent = dragState.draggedComponents.find(
|
||||
(dragComp) => dragComp.id === child.id,
|
||||
);
|
||||
if (originalChildComponent) {
|
||||
const deltaX = dragState.currentPosition.x - dragState.originalPosition.x;
|
||||
const deltaY = dragState.currentPosition.y - dragState.originalPosition.y;
|
||||
|
||||
displayChild = {
|
||||
...child,
|
||||
position: {
|
||||
x: originalChildComponent.position.x + deltaX,
|
||||
y: originalChildComponent.position.y + deltaY,
|
||||
z: originalChildComponent.position.z || 1,
|
||||
} as Position,
|
||||
style: {
|
||||
...child.style,
|
||||
opacity: 0.8,
|
||||
transition: "none",
|
||||
zIndex: 8888,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={child.id}
|
||||
className="absolute"
|
||||
style={{
|
||||
left: `${displayChild.position.x - component.position.x}px`,
|
||||
top: `${displayChild.position.y - component.position.y}px`,
|
||||
width: `${displayChild.size.width}px`,
|
||||
height: `${displayChild.size.height}px`, // 순수 컴포넌트 높이만 사용
|
||||
zIndex: displayChild.position.z || 1,
|
||||
}}
|
||||
>
|
||||
<RealtimePreview
|
||||
component={displayChild}
|
||||
isSelected={
|
||||
selectedComponent?.id === child.id || groupState.selectedComponents.includes(child.id)
|
||||
}
|
||||
onClick={(e) => handleComponentClick(child, e)}
|
||||
onDragStart={(e) => startComponentDrag(child, e)}
|
||||
onDragEnd={endDrag}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</RealtimePreview>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -2475,7 +2576,40 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
<div className="p-4">
|
||||
<StyleEditor
|
||||
style={selectedComponent.style || {}}
|
||||
onStyleChange={(newStyle) => updateComponentProperty(selectedComponent.id, "style", newStyle)}
|
||||
onStyleChange={(newStyle) => {
|
||||
console.log("🔧 StyleEditor 크기 변경:", {
|
||||
componentId: selectedComponent.id,
|
||||
newStyle,
|
||||
currentSize: selectedComponent.size,
|
||||
hasWidth: !!newStyle.width,
|
||||
hasHeight: !!newStyle.height,
|
||||
});
|
||||
|
||||
// 스타일 업데이트
|
||||
updateComponentProperty(selectedComponent.id, "style", newStyle);
|
||||
|
||||
// 크기가 변경된 경우 component.size도 업데이트
|
||||
if (newStyle.width || newStyle.height) {
|
||||
const width = newStyle.width
|
||||
? parseInt(newStyle.width.replace("px", ""))
|
||||
: selectedComponent.size.width;
|
||||
const height = newStyle.height
|
||||
? parseInt(newStyle.height.replace("px", ""))
|
||||
: selectedComponent.size.height;
|
||||
|
||||
console.log("📏 크기 업데이트:", {
|
||||
originalWidth: selectedComponent.size.width,
|
||||
originalHeight: selectedComponent.size.height,
|
||||
newWidth: width,
|
||||
newHeight: height,
|
||||
styleWidth: newStyle.width,
|
||||
styleHeight: newStyle.height,
|
||||
});
|
||||
|
||||
updateComponentProperty(selectedComponent.id, "size.width", width);
|
||||
updateComponentProperty(selectedComponent.id, "size.height", height);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user