레이아웃 추가기능

This commit is contained in:
kjs
2025-09-10 18:36:28 +09:00
parent f7aa71ec30
commit 083f053851
69 changed files with 10218 additions and 3 deletions

View 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

View 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>
);
};

View 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();
});
}
}

View 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"],
},
};

View 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";

View 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: 존별 전용 속성 정의
}