Files
invyone/frontend/types/layout.ts
T

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;
min_width?: number;
min_height?: number;
max_width?: number;
max_height?: number;
};
style?: ComponentStyle;
allowed_components?: ComponentType[];
is_resizable?: boolean;
is_required?: boolean; // 필수 영역 여부
}
// 레이아웃 설정
export interface LayoutConfig {
// 그리드 레이아웃 설정
grid?: {
rows: number;
columns: number;
gap: number;
row_gap?: number;
column_gap?: number;
auto_rows?: string;
auto_columns?: 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]
min_size: number[]; // 각 영역의 최소 크기
resizable: boolean; // 크기 조절 가능 여부
splitter_size: number; // 분할선 두께
};
// 탭 레이아웃 설정
tabs?: {
position: "top" | "bottom" | "left" | "right";
variant: "default" | "pills" | "underline";
size: "sm" | "md" | "lg";
default_tab: string; // 기본 선택 탭
closable: boolean; // 탭 닫기 가능 여부
};
// 아코디언 설정
accordion?: {
multiple: boolean; // 다중 확장 허용
default_expanded: string[]; // 기본 확장 항목
collapsible: boolean; // 모두 닫기 허용
};
// 사이드바 설정
sidebar?: {
position: "left" | "right";
width: number | string;
collapsible: boolean;
collapsed: boolean;
overlay: boolean; // 오버레이 모드
};
// 헤더-푸터 설정
header_footer?: {
header_height: number | string;
footer_height: number | string;
sticky_header: boolean;
sticky_footer: boolean;
};
// 대시보드 설정
dashboard?: {
columns: number;
row_height: number;
margin: [number, number];
padding: [number, number];
is_draggable: boolean;
is_resizable: boolean;
};
// 커스텀 설정
custom?: {
css_properties: Record<string, string>;
class_name: string;
template: string; // HTML 템플릿
};
// 카드 레이아웃 설정
card?: {
// 테이블 컬럼 매핑 설정
column_mapping?: {
title_column?: string; // 카드 타이틀로 사용할 컬럼
subtitle_column?: string; // 카드 서브타이틀로 사용할 컬럼
image_column?: string; // 카드 이미지로 사용할 컬럼
description_column?: string; // 카드 설명으로 사용할 컬럼
display_columns?: string[]; // 카드에 표시할 추가 컬럼들
action_columns?: string[]; // 액션 버튼으로 표시할 컬럼들
};
// 카드 스타일 설정
card_style?: {
show_image?: boolean;
show_title?: boolean;
show_subtitle?: boolean;
show_description?: boolean;
max_description_length?: number;
image_position?: "top" | "left" | "right";
image_size?: "small" | "medium" | "large";
};
// 그리드 설정
cards_per_row?: number; // 한 행에 표시할 카드 수
card_spacing?: number; // 카드 간격
auto_height?: boolean; // 자동 높이 조정
};
}
// 드롭존 설정
export interface DropZoneConfig {
show_drop_zones: boolean;
drop_zone_style?: ComponentStyle;
highlight_on_drag_over: boolean;
allowed_types?: ComponentType[];
}
// 레이아웃 컴포넌트 인터페이스 (기존 screen.ts에 추가될 예정)
export interface LayoutComponent {
id: string;
type: "layout";
layout_type: LayoutType;
layout_config: LayoutConfig;
children: ComponentData[];
zones: LayoutZone[]; // 레이아웃 영역 정의
allowed_component_types?: ComponentType[]; // 허용된 자식 컴포넌트 타입
drop_zone_config?: DropZoneConfig; // 드롭존 설정
position: { x: number; y: number };
size: { width: number; height: number };
parent_id?: string;
style?: ComponentStyle;
table_name?: string;
label?: string;
}
// 레이아웃 표준 정의 (데이터베이스에서 조회)
export interface LayoutStandard {
layout_code: string;
layout_name: string;
layout_name_eng?: string;
description?: string;
layout_type: LayoutType;
category: LayoutCategory;
icon_name?: string;
default_size?: { width: number; height: number };
layout_config: LayoutConfig;
zones_config: LayoutZone[];
preview_image?: string;
sort_order?: number;
is_active?: string;
is_public?: string;
company_code: string;
created_date?: Date;
created_by?: string;
updated_date?: Date;
updated_by?: string;
}
// 레이아웃 생성 요청
export interface CreateLayoutRequest {
layout_name: string;
layout_name_eng?: string;
description?: string;
layout_type: LayoutType;
category: LayoutCategory;
icon_name?: string;
default_size?: { width: number; height: number };
layout_config: LayoutConfig;
zones_config: LayoutZone[];
is_public?: boolean;
}
// 레이아웃 수정 요청
export interface UpdateLayoutRequest extends Partial<CreateLayoutRequest> {
layout_code: string;
}
// 레이아웃 정의 (레지스트리에서 사용)
export interface LayoutDefinition {
id: string;
name: string;
name_eng?: string;
description?: string;
category: LayoutCategory;
icon?: string;
component: React.ComponentType<any>;
default_config: LayoutConfig;
default_zones: LayoutZone[];
tags?: string[];
is_active?: boolean;
metadata?: {
version?: string;
author?: string;
documentation?: string;
created_at?: string;
last_updated?: string;
[key: string]: any;
};
}
// 사전 정의 레이아웃 템플릿
export const PREDEFINED_LAYOUTS: Omit<
LayoutStandard,
"layout_code" | "company_code" | "created_date" | "created_by" | "updated_date" | "updated_by"
>[] = [
// 기본 레이아웃
{
layout_name: "2x2 그리드",
layout_name_eng: "2x2 Grid",
layout_type: "grid",
category: "basic",
icon_name: "grid",
default_size: { width: 800, height: 600 },
layout_config: {
grid: { rows: 2, columns: 2, gap: 16 },
},
zones_config: [
{
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%" },
},
],
sort_order: 1,
},
// 폼 레이아웃
{
layout_name: "2단 폼 레이아웃",
layout_name_eng: "Two Column Form",
layout_type: "grid",
category: "form",
icon_name: "columns",
default_size: { width: 800, height: 400 },
layout_config: {
grid: { rows: 1, columns: 2, gap: 24 },
},
zones_config: [
{
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%" },
},
],
sort_order: 2,
},
// 대시보드 레이아웃
{
layout_name: "메인 대시보드",
layout_name_eng: "Main Dashboard",
layout_type: "grid",
category: "dashboard",
icon_name: "layout-dashboard",
default_size: { width: 1200, height: 800 },
layout_config: {
grid: { rows: 2, columns: 4, gap: 16 },
},
zones_config: [
{
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%" },
},
],
sort_order: 3,
},
// 테이블 레이아웃
{
layout_name: "필터가 있는 테이블",
layout_name_eng: "Table with Filters",
layout_type: "flexbox",
category: "table",
icon_name: "table",
default_size: { width: 1000, height: 600 },
layout_config: {
flexbox: { direction: "column", justify: "flex-start", align: "stretch", wrap: "nowrap", gap: 16 },
},
zones_config: [
{
id: "filters",
name: "검색 필터",
position: {},
size: { width: "100%", height: "auto" },
},
{
id: "table",
name: "데이터 테이블",
position: {},
size: { width: "100%", height: "1fr" },
},
],
sort_order: 4,
},
// 분할 레이아웃
{
layout_name: "수평 분할",
layout_name_eng: "Horizontal Split",
layout_type: "split",
category: "basic",
icon_name: "separator-horizontal",
default_size: { width: 800, height: 400 },
layout_config: {
split: { direction: "horizontal", ratio: [50, 50], min_size: [200, 200], resizable: true, splitter_size: 4 },
},
zones_config: [
{
id: "left",
name: "좌측 영역",
position: {},
size: { width: "50%", height: "100%" },
is_resizable: true,
},
{
id: "right",
name: "우측 영역",
position: {},
size: { width: "50%", height: "100%" },
is_resizable: true,
},
],
sort_order: 5,
},
// 탭 레이아웃
{
layout_name: "수평 탭",
layout_name_eng: "Horizontal Tabs",
layout_type: "tabs",
category: "navigation",
icon_name: "tabs",
default_size: { width: 800, height: 500 },
layout_config: {
tabs: { position: "top", variant: "default", size: "md", default_tab: "tab1", closable: false },
},
zones_config: [
{
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%" },
},
],
sort_order: 6,
},
];