ERP-node/frontend/types/layout.ts

457 lines
12 KiB
TypeScript

// 레이아웃 기능 타입 정의
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<string, string>;
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<CreateLayoutRequest> {
layoutCode: string;
}
// 레이아웃 정의 (레지스트리에서 사용)
export interface LayoutDefinition {
id: string;
name: string;
nameEng?: string;
description?: string;
category: LayoutCategory;
icon?: string;
component: React.ComponentType<any>;
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,
},
];