2025-10-16 18:16:57 +09:00
|
|
|
/**
|
|
|
|
|
* 반응형 스마트 기본값 생성 유틸리티
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { ComponentData } from "@/types/screen-management";
|
|
|
|
|
import { ResponsiveComponentConfig, BREAKPOINTS } from "@/types/responsive";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 컴포넌트 크기에 따른 스마트 기본값 생성
|
|
|
|
|
*
|
|
|
|
|
* 로직:
|
|
|
|
|
* - 작은 컴포넌트 (너비 25% 이하): 모바일에서도 같은 너비 유지
|
|
|
|
|
* - 중간 컴포넌트 (너비 25-50%): 모바일에서 전체 너비로 확장
|
|
|
|
|
* - 큰 컴포넌트 (너비 50% 이상): 모든 디바이스에서 전체 너비
|
|
|
|
|
*/
|
|
|
|
|
export function generateSmartDefaults(
|
|
|
|
|
component: ComponentData,
|
|
|
|
|
screenWidth: number = 1920,
|
|
|
|
|
rowComponentCount: number = 1, // 같은 행에 있는 컴포넌트 개수
|
|
|
|
|
): ResponsiveComponentConfig["responsive"] {
|
2025-10-17 15:31:23 +09:00
|
|
|
// 특정 컴포넌트는 항상 전체 너비 (datatable, table-list 등)
|
|
|
|
|
const fullWidthComponents = ["datatable", "data-table", "table-list", "repeater-field-group"];
|
|
|
|
|
const componentId = (component as any).componentId || (component as any).id;
|
2025-10-16 18:16:57 +09:00
|
|
|
const componentType = (component as any).componentType || component.type;
|
|
|
|
|
|
2025-10-17 15:31:23 +09:00
|
|
|
if (fullWidthComponents.includes(componentId) || fullWidthComponents.includes(componentType)) {
|
2025-10-16 18:16:57 +09:00
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: 12, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: 8, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: 4, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const componentWidthPercent = (component.size.width / screenWidth) * 100;
|
|
|
|
|
|
|
|
|
|
// 같은 행에 여러 컴포넌트가 있으면 컬럼을 나눔
|
|
|
|
|
if (rowComponentCount > 1) {
|
|
|
|
|
const desktopColumns = Math.round(12 / rowComponentCount);
|
|
|
|
|
const tabletColumns = Math.round(8 / rowComponentCount);
|
|
|
|
|
const mobileColumns = 4; // 모바일에서는 항상 전체 너비
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: desktopColumns,
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: tabletColumns,
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: mobileColumns,
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-10-17 09:32:46 +09:00
|
|
|
// 매우 작은 컴포넌트 (10% 이하, 예: 버튼)
|
|
|
|
|
else if (componentWidthPercent <= 10) {
|
|
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: 1, // 12컬럼 중 1개 (~8%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: 1, // 8컬럼 중 1개 (~12.5%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: 1, // 4컬럼 중 1개 (25%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
// 작은 컴포넌트 (10-25%)
|
2025-10-16 18:16:57 +09:00
|
|
|
else if (componentWidthPercent <= 25) {
|
|
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: 3, // 12컬럼 중 3개 (25%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: 2, // 8컬럼 중 2개 (25%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: 1, // 4컬럼 중 1개 (25%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
// 중간 컴포넌트 (25-50%)
|
|
|
|
|
else if (componentWidthPercent <= 50) {
|
|
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: 6, // 12컬럼 중 6개 (50%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: 4, // 8컬럼 중 4개 (50%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: 4, // 4컬럼 전체 (100%)
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
// 큰 컴포넌트 (50% 이상)
|
|
|
|
|
else {
|
|
|
|
|
return {
|
|
|
|
|
desktop: {
|
|
|
|
|
gridColumns: 12, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
tablet: {
|
|
|
|
|
gridColumns: 8, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
mobile: {
|
|
|
|
|
gridColumns: 4, // 전체 너비
|
|
|
|
|
order: 1,
|
|
|
|
|
hide: false,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 컴포넌트에 반응형 설정이 없을 경우 자동 생성
|
|
|
|
|
*/
|
|
|
|
|
export function ensureResponsiveConfig(component: ComponentData, screenWidth?: number): ComponentData {
|
|
|
|
|
if (component.responsiveConfig) {
|
|
|
|
|
return component;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...component,
|
|
|
|
|
responsiveConfig: {
|
|
|
|
|
designerPosition: {
|
|
|
|
|
x: component.position.x,
|
|
|
|
|
y: component.position.y,
|
|
|
|
|
width: component.size.width,
|
|
|
|
|
height: component.size.height,
|
|
|
|
|
},
|
|
|
|
|
useSmartDefaults: true,
|
|
|
|
|
responsive: generateSmartDefaults(component, screenWidth),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|