// 레이아웃 기능 타입 정의 import { ComponentStyle, ComponentData, ComponentType } from "./screen"; // 레이아웃 타입 정의 export type LayoutType = | "grid" // 그리드 레이아웃 (n x m 격자) | "flexbox" // 플렉스박스 레이아웃 | "split" // 분할 레이아웃 (수직/수평) | "card" // 카드 레이아웃 | "tabs" // 탭 레이아웃 | "accordion" // 아코디언 레이아웃 | "sidebar" // 사이드바 레이아웃 | "header-footer" // 헤더-푸터 레이아웃 | "three-column" // 3단 레이아웃 | "dashboard" // 대시보드 레이아웃 | "form" // 폼 레이아웃 | "table" // 테이블 레이아웃 | "custom"; // 커스텀 레이아웃 // 레이아웃 카테고리 export const LAYOUT_CATEGORIES = { BASIC: "basic", // 기본 레이아웃 FORM: "form", // 폼 레이아웃 TABLE: "table", // 테이블 레이아웃 DASHBOARD: "dashboard", // 대시보드 레이아웃 NAVIGATION: "navigation", // 네비게이션 레이아웃 CONTENT: "content", // 컨텐츠 레이아웃 BUSINESS: "business", // 업무용 레이아웃 } as const; export type LayoutCategory = (typeof LAYOUT_CATEGORIES)[keyof typeof LAYOUT_CATEGORIES]; // 레이아웃 존 정의 export interface LayoutZone { id: string; name: string; position: { row?: number; column?: number; x?: number; y?: number; }; size: { width: number | string; height: number | string; minWidth?: number; minHeight?: number; maxWidth?: number; maxHeight?: number; }; style?: ComponentStyle; allowedComponents?: ComponentType[]; isResizable?: boolean; isRequired?: boolean; // 필수 영역 여부 } // 레이아웃 설정 export interface LayoutConfig { // 그리드 레이아웃 설정 grid?: { rows: number; columns: number; gap: number; rowGap?: number; columnGap?: number; autoRows?: string; autoColumns?: string; }; // 플렉스박스 설정 flexbox?: { direction: "row" | "column" | "row-reverse" | "column-reverse"; justify: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly"; align: "flex-start" | "flex-end" | "center" | "stretch" | "baseline"; wrap: "nowrap" | "wrap" | "wrap-reverse"; gap: number; }; // 분할 레이아웃 설정 split?: { direction: "horizontal" | "vertical"; ratio: number[]; // 각 영역의 비율 [30, 70] minSize: number[]; // 각 영역의 최소 크기 resizable: boolean; // 크기 조절 가능 여부 splitterSize: number; // 분할선 두께 }; // 탭 레이아웃 설정 tabs?: { position: "top" | "bottom" | "left" | "right"; variant: "default" | "pills" | "underline"; size: "sm" | "md" | "lg"; defaultTab: string; // 기본 선택 탭 closable: boolean; // 탭 닫기 가능 여부 }; // 아코디언 설정 accordion?: { multiple: boolean; // 다중 확장 허용 defaultExpanded: string[]; // 기본 확장 항목 collapsible: boolean; // 모두 닫기 허용 }; // 사이드바 설정 sidebar?: { position: "left" | "right"; width: number | string; collapsible: boolean; collapsed: boolean; overlay: boolean; // 오버레이 모드 }; // 헤더-푸터 설정 headerFooter?: { headerHeight: number | string; footerHeight: number | string; stickyHeader: boolean; stickyFooter: boolean; }; // 대시보드 설정 dashboard?: { columns: number; rowHeight: number; margin: [number, number]; padding: [number, number]; isDraggable: boolean; isResizable: boolean; }; // 커스텀 설정 custom?: { cssProperties: Record; className: string; template: string; // HTML 템플릿 }; // 카드 레이아웃 설정 card?: { // 테이블 컬럼 매핑 설정 columnMapping?: { titleColumn?: string; // 카드 타이틀로 사용할 컬럼 subtitleColumn?: string; // 카드 서브타이틀로 사용할 컬럼 imageColumn?: string; // 카드 이미지로 사용할 컬럼 descriptionColumn?: string; // 카드 설명으로 사용할 컬럼 displayColumns?: string[]; // 카드에 표시할 추가 컬럼들 actionColumns?: string[]; // 액션 버튼으로 표시할 컬럼들 }; // 카드 스타일 설정 cardStyle?: { showImage?: boolean; showTitle?: boolean; showSubtitle?: boolean; showDescription?: boolean; maxDescriptionLength?: number; imagePosition?: "top" | "left" | "right"; imageSize?: "small" | "medium" | "large"; }; // 그리드 설정 cardsPerRow?: number; // 한 행에 표시할 카드 수 cardSpacing?: number; // 카드 간격 autoHeight?: boolean; // 자동 높이 조정 }; } // 드롭존 설정 export interface DropZoneConfig { showDropZones: boolean; dropZoneStyle?: ComponentStyle; highlightOnDragOver: boolean; allowedTypes?: ComponentType[]; } // 레이아웃 컴포넌트 인터페이스 (기존 screen.ts에 추가될 예정) export interface LayoutComponent { id: string; type: "layout"; layoutType: LayoutType; layoutConfig: LayoutConfig; children: ComponentData[]; zones: LayoutZone[]; // 레이아웃 영역 정의 allowedComponentTypes?: ComponentType[]; // 허용된 자식 컴포넌트 타입 dropZoneConfig?: DropZoneConfig; // 드롭존 설정 position: { x: number; y: number }; size: { width: number; height: number }; parentId?: string; style?: ComponentStyle; tableName?: string; label?: string; } // 레이아웃 표준 정의 (데이터베이스에서 조회) export interface LayoutStandard { layoutCode: string; layoutName: string; layoutNameEng?: string; description?: string; layoutType: LayoutType; category: LayoutCategory; iconName?: string; defaultSize?: { width: number; height: number }; layoutConfig: LayoutConfig; zonesConfig: LayoutZone[]; previewImage?: string; sortOrder?: number; isActive?: string; isPublic?: string; companyCode: string; createdDate?: Date; createdBy?: string; updatedDate?: Date; updatedBy?: string; } // 레이아웃 생성 요청 export interface CreateLayoutRequest { layoutName: string; layoutNameEng?: string; description?: string; layoutType: LayoutType; category: LayoutCategory; iconName?: string; defaultSize?: { width: number; height: number }; layoutConfig: LayoutConfig; zonesConfig: LayoutZone[]; isPublic?: boolean; } // 레이아웃 수정 요청 export interface UpdateLayoutRequest extends Partial { layoutCode: string; } // 레이아웃 정의 (레지스트리에서 사용) export interface LayoutDefinition { id: string; name: string; nameEng?: string; description?: string; category: LayoutCategory; icon?: string; component: React.ComponentType; defaultConfig: LayoutConfig; defaultZones: LayoutZone[]; tags?: string[]; isActive?: boolean; metadata?: { version?: string; author?: string; documentation?: string; createdAt?: string; lastUpdated?: string; [key: string]: any; }; } // 사전 정의 레이아웃 템플릿 export const PREDEFINED_LAYOUTS: Omit< LayoutStandard, "layoutCode" | "companyCode" | "createdDate" | "createdBy" | "updatedDate" | "updatedBy" >[] = [ // 기본 레이아웃 { layoutName: "2x2 그리드", layoutNameEng: "2x2 Grid", layoutType: "grid", category: "basic", iconName: "grid", defaultSize: { width: 800, height: 600 }, layoutConfig: { grid: { rows: 2, columns: 2, gap: 16 }, }, zonesConfig: [ { id: "zone1", name: "상단 좌측", position: { row: 0, column: 0 }, size: { width: "50%", height: "50%" }, }, { id: "zone2", name: "상단 우측", position: { row: 0, column: 1 }, size: { width: "50%", height: "50%" }, }, { id: "zone3", name: "하단 좌측", position: { row: 1, column: 0 }, size: { width: "50%", height: "50%" }, }, { id: "zone4", name: "하단 우측", position: { row: 1, column: 1 }, size: { width: "50%", height: "50%" }, }, ], sortOrder: 1, }, // 폼 레이아웃 { layoutName: "2단 폼 레이아웃", layoutNameEng: "Two Column Form", layoutType: "grid", category: "form", iconName: "columns", defaultSize: { width: 800, height: 400 }, layoutConfig: { grid: { rows: 1, columns: 2, gap: 24 }, }, zonesConfig: [ { id: "left", name: "좌측 입력 영역", position: { row: 0, column: 0 }, size: { width: "50%", height: "100%" }, }, { id: "right", name: "우측 입력 영역", position: { row: 0, column: 1 }, size: { width: "50%", height: "100%" }, }, ], sortOrder: 2, }, // 대시보드 레이아웃 { layoutName: "메인 대시보드", layoutNameEng: "Main Dashboard", layoutType: "grid", category: "dashboard", iconName: "layout-dashboard", defaultSize: { width: 1200, height: 800 }, layoutConfig: { grid: { rows: 2, columns: 4, gap: 16 }, }, zonesConfig: [ { id: "header", name: "헤더", position: { row: 0, column: 0 }, size: { width: "100%", height: "80px" }, }, { id: "sidebar", name: "사이드바", position: { row: 1, column: 0 }, size: { width: "250px", height: "100%" }, }, { id: "main", name: "메인 컨텐츠", position: { row: 1, column: 1 }, size: { width: "calc(100% - 250px)", height: "100%" }, }, ], sortOrder: 3, }, // 테이블 레이아웃 { layoutName: "필터가 있는 테이블", layoutNameEng: "Table with Filters", layoutType: "flexbox", category: "table", iconName: "table", defaultSize: { width: 1000, height: 600 }, layoutConfig: { flexbox: { direction: "column", justify: "flex-start", align: "stretch", wrap: "nowrap", gap: 16 }, }, zonesConfig: [ { id: "filters", name: "검색 필터", position: {}, size: { width: "100%", height: "auto" }, }, { id: "table", name: "데이터 테이블", position: {}, size: { width: "100%", height: "1fr" }, }, ], sortOrder: 4, }, // 분할 레이아웃 { layoutName: "수평 분할", layoutNameEng: "Horizontal Split", layoutType: "split", category: "basic", iconName: "separator-horizontal", defaultSize: { width: 800, height: 400 }, layoutConfig: { split: { direction: "horizontal", ratio: [50, 50], minSize: [200, 200], resizable: true, splitterSize: 4 }, }, zonesConfig: [ { id: "left", name: "좌측 영역", position: {}, size: { width: "50%", height: "100%" }, isResizable: true, }, { id: "right", name: "우측 영역", position: {}, size: { width: "50%", height: "100%" }, isResizable: true, }, ], sortOrder: 5, }, // 탭 레이아웃 { layoutName: "수평 탭", layoutNameEng: "Horizontal Tabs", layoutType: "tabs", category: "navigation", iconName: "tabs", defaultSize: { width: 800, height: 500 }, layoutConfig: { tabs: { position: "top", variant: "default", size: "md", defaultTab: "tab1", closable: false }, }, zonesConfig: [ { id: "tab1", name: "첫 번째 탭", position: {}, size: { width: "100%", height: "100%" }, }, { id: "tab2", name: "두 번째 탭", position: {}, size: { width: "100%", height: "100%" }, }, { id: "tab3", name: "세 번째 탭", position: {}, size: { width: "100%", height: "100%" }, }, ], sortOrder: 6, }, ];