레이아웃 추가기능
This commit is contained in:
42
frontend/lib/registry/layouts/split/README.md
Normal file
42
frontend/lib/registry/layouts/split/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# split
|
||||
|
||||
크기 조절이 가능한 분할된 영역의 레이아웃입니다.
|
||||
|
||||
## 사용법
|
||||
|
||||
이 레이아웃은 자동으로 등록되어 화면편집기에서 사용할 수 있습니다.
|
||||
|
||||
## 구성
|
||||
|
||||
- `SplitLayout.tsx`: 메인 레이아웃 컴포넌트
|
||||
- `SplitLayoutRenderer.tsx`: 렌더러 (자동 등록)
|
||||
- `config.ts`: 기본 설정
|
||||
- `types.ts`: 타입 정의
|
||||
- `index.ts`: 진입점
|
||||
|
||||
## 개발
|
||||
|
||||
1. `SplitLayout.tsx`에서 레이아웃 로직 구현
|
||||
2. `config.ts`에서 기본 설정 조정
|
||||
3. `types.ts`에서 타입 정의 추가
|
||||
|
||||
## 설정
|
||||
|
||||
```typescript
|
||||
{
|
||||
split: {
|
||||
// TODO: 설정 옵션 문서화
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 존 구성
|
||||
|
||||
- **존 1** (`zone1`): 기본 영역
|
||||
- **존 2** (`zone2`): 기본 영역
|
||||
|
||||
---
|
||||
|
||||
생성일: 2025. 9. 10.
|
||||
버전: 1.0.0
|
||||
작성자: Developer
|
||||
98
frontend/lib/registry/layouts/split/SplitLayout.tsx
Normal file
98
frontend/lib/registry/layouts/split/SplitLayout.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { LayoutRendererProps } from "../BaseLayoutRenderer";
|
||||
|
||||
/**
|
||||
* split 컴포넌트
|
||||
*/
|
||||
export interface SplitLayoutProps extends LayoutRendererProps {
|
||||
renderer: any; // SplitLayoutRenderer 타입
|
||||
}
|
||||
|
||||
export const SplitLayout: React.FC<SplitLayoutProps> = ({
|
||||
layout,
|
||||
isDesignMode = false,
|
||||
isSelected = false,
|
||||
onClick,
|
||||
className = "",
|
||||
renderer,
|
||||
...props
|
||||
}) => {
|
||||
if (!layout.layoutConfig.split) {
|
||||
return (
|
||||
<div className="error-layout flex items-center justify-center p-4 border-2 border-red-300 bg-red-50 rounded">
|
||||
<div className="text-center text-red-600">
|
||||
<div className="font-medium">split 설정이 없습니다.</div>
|
||||
<div className="text-sm mt-1">layoutConfig.split가 필요합니다.</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const splitConfig = layout.layoutConfig.split;
|
||||
const containerStyle = renderer.getLayoutContainerStyle();
|
||||
|
||||
// split 컨테이너 스타일
|
||||
const splitStyle: React.CSSProperties = {
|
||||
...containerStyle,
|
||||
// TODO: 레이아웃 전용 스타일 정의
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
};
|
||||
|
||||
// 디자인 모드 스타일
|
||||
if (isDesignMode) {
|
||||
splitStyle.border = isSelected ? "2px solid #3b82f6" : "1px solid #e2e8f0";
|
||||
splitStyle.borderRadius = "8px";
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`split-layout ${isDesignMode ? "design-mode" : ""} ${className}`}
|
||||
style={splitStyle}
|
||||
onClick={onClick}
|
||||
draggable={isDesignMode}
|
||||
onDragStart={props.onDragStart}
|
||||
onDragEnd={props.onDragEnd}
|
||||
{...props}
|
||||
>
|
||||
{layout.zones.map((zone: any) => {
|
||||
const zoneChildren = renderer.getZoneChildren(zone.id);
|
||||
|
||||
// TODO: 존별 스타일 정의
|
||||
const zoneStyle: React.CSSProperties = {
|
||||
// 레이아웃별 존 스타일 구현
|
||||
};
|
||||
|
||||
return renderer.renderZone(zone, zoneChildren, {
|
||||
style: zoneStyle,
|
||||
className: "split-zone",
|
||||
});
|
||||
})}
|
||||
|
||||
{/* 디자인 모드에서 빈 영역 표시 */}
|
||||
{isDesignMode && layout.zones.length === 0 && (
|
||||
<div
|
||||
className="empty-split-container"
|
||||
style={{
|
||||
flex: 1,
|
||||
border: "2px dashed #cbd5e1",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "rgba(148, 163, 184, 0.05)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: "14px",
|
||||
color: "#64748b",
|
||||
minHeight: "100px",
|
||||
padding: "20px",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
split에 존을 추가하세요
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
49
frontend/lib/registry/layouts/split/SplitLayoutRenderer.tsx
Normal file
49
frontend/lib/registry/layouts/split/SplitLayoutRenderer.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { AutoRegisteringLayoutRenderer } from "../AutoRegisteringLayoutRenderer";
|
||||
import { LayoutRendererProps } from "../BaseLayoutRenderer";
|
||||
import { SplitLayoutDefinition } from "./index";
|
||||
import { SplitLayout } from "./SplitLayout";
|
||||
|
||||
/**
|
||||
* split 렌더러 (새 구조)
|
||||
*/
|
||||
export class SplitLayoutRenderer extends AutoRegisteringLayoutRenderer {
|
||||
/**
|
||||
* 레이아웃 정의 (자동 등록용)
|
||||
*/
|
||||
static readonly layoutDefinition = SplitLayoutDefinition;
|
||||
|
||||
/**
|
||||
* 클래스 로드 시 자동 등록 실행
|
||||
*/
|
||||
static {
|
||||
this.registerSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* 렌더링 실행
|
||||
*/
|
||||
render(): React.ReactElement {
|
||||
return <SplitLayout {...this.props} renderer={this} />;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* React 함수 컴포넌트로 래핑 (외부 사용용)
|
||||
*/
|
||||
export const SplitLayoutComponent: React.FC<LayoutRendererProps> = (props) => {
|
||||
const renderer = new SplitLayoutRenderer(props);
|
||||
return renderer.render();
|
||||
};
|
||||
|
||||
// 개발 모드에서 Hot Reload 지원
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// HMR API 등록
|
||||
if ((module as any).hot) {
|
||||
(module as any).hot.accept();
|
||||
(module as any).hot.dispose(() => {
|
||||
SplitLayoutRenderer.unregisterSelf();
|
||||
});
|
||||
}
|
||||
}
|
||||
44
frontend/lib/registry/layouts/split/config.ts
Normal file
44
frontend/lib/registry/layouts/split/config.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* split 기본 설정
|
||||
*/
|
||||
export const SplitLayoutConfig = {
|
||||
defaultConfig: {
|
||||
split: {
|
||||
// TODO: 레이아웃 전용 설정 정의
|
||||
// 예시:
|
||||
// spacing: 16,
|
||||
// orientation: "vertical",
|
||||
// allowResize: true,
|
||||
},
|
||||
},
|
||||
|
||||
defaultZones: [
|
||||
{
|
||||
id: "zone1",
|
||||
name: "존 1",
|
||||
position: {},
|
||||
size: { width: "100%", height: "100%" },
|
||||
},
|
||||
{
|
||||
id: "zone2",
|
||||
name: "존 2",
|
||||
position: {},
|
||||
size: { width: "100%", height: "100%" },
|
||||
}
|
||||
],
|
||||
|
||||
// 설정 스키마 (검증용)
|
||||
configSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
split: {
|
||||
type: "object",
|
||||
properties: {
|
||||
// TODO: 설정 스키마 정의
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
required: ["split"],
|
||||
},
|
||||
};
|
||||
61
frontend/lib/registry/layouts/split/index.ts
Normal file
61
frontend/lib/registry/layouts/split/index.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import { createLayoutDefinition } from "../../utils/createLayoutDefinition";
|
||||
import { SplitLayout } from "./SplitLayout";
|
||||
import { SplitLayoutRenderer } from "./SplitLayoutRenderer";
|
||||
import { LayoutRendererProps } from "../BaseLayoutRenderer";
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* 분할 레이아웃 래퍼 컴포넌트 (DynamicLayoutRenderer용)
|
||||
*/
|
||||
const SplitLayoutWrapper: React.FC<LayoutRendererProps> = (props) => {
|
||||
const renderer = new SplitLayoutRenderer(props);
|
||||
return renderer.render();
|
||||
};
|
||||
|
||||
/**
|
||||
* split 레이아웃 정의
|
||||
*/
|
||||
export const SplitLayoutDefinition = createLayoutDefinition({
|
||||
id: "split",
|
||||
name: "분할 레이아웃",
|
||||
nameEng: "Split Layout",
|
||||
description: "크기 조절이 가능한 분할된 영역의 레이아웃입니다.",
|
||||
category: "basic",
|
||||
icon: "split",
|
||||
component: SplitLayoutWrapper,
|
||||
defaultConfig: {
|
||||
split: {
|
||||
direction: "horizontal",
|
||||
ratio: [50, 50],
|
||||
minSize: [200, 200],
|
||||
resizable: true,
|
||||
splitterSize: 4,
|
||||
},
|
||||
},
|
||||
defaultZones: [
|
||||
{
|
||||
id: "left",
|
||||
name: "좌측 패널",
|
||||
position: {},
|
||||
size: { width: "50%", height: "100%" },
|
||||
isResizable: true,
|
||||
},
|
||||
{
|
||||
id: "right",
|
||||
name: "우측 패널",
|
||||
position: {},
|
||||
size: { width: "50%", height: "100%" },
|
||||
isResizable: true,
|
||||
},
|
||||
],
|
||||
tags: ["split", "basic", "layout"],
|
||||
version: "1.0.0",
|
||||
author: "Developer",
|
||||
documentation: "크기 조절이 가능한 분할된 영역의 레이아웃입니다.",
|
||||
});
|
||||
|
||||
// 자동 등록을 위한 export
|
||||
export { SplitLayout } from "./SplitLayout";
|
||||
export { SplitLayoutRenderer } from "./SplitLayoutRenderer";
|
||||
28
frontend/lib/registry/layouts/split/types.ts
Normal file
28
frontend/lib/registry/layouts/split/types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { LayoutRendererProps } from "../BaseLayoutRenderer";
|
||||
|
||||
/**
|
||||
* split 설정 타입
|
||||
*/
|
||||
export interface SplitConfig {
|
||||
// TODO: 레이아웃 전용 설정 타입 정의
|
||||
// 예시:
|
||||
// spacing?: number;
|
||||
// orientation?: "vertical" | "horizontal";
|
||||
// allowResize?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* split Props 타입
|
||||
*/
|
||||
export interface SplitLayoutProps extends LayoutRendererProps {
|
||||
renderer: any; // SplitLayoutRenderer 타입
|
||||
}
|
||||
|
||||
/**
|
||||
* split 존 타입
|
||||
*/
|
||||
export interface SplitZone {
|
||||
id: string;
|
||||
name: string;
|
||||
// TODO: 존별 전용 속성 정의
|
||||
}
|
||||
Reference in New Issue
Block a user