926 lines
23 KiB
Markdown
926 lines
23 KiB
Markdown
|
|
# POP 파일 상세 목록
|
||
|
|
|
||
|
|
**최종 업데이트: 2026-02-04**
|
||
|
|
|
||
|
|
이 문서는 POP 화면 시스템과 관련된 모든 파일을 나열하고 각 파일의 역할을 설명합니다.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 목차
|
||
|
|
|
||
|
|
1. [App Router 파일](#1-app-router-파일)
|
||
|
|
2. [Designer 파일](#2-designer-파일)
|
||
|
|
3. [Panels 파일](#3-panels-파일)
|
||
|
|
4. [Renderers 파일](#4-renderers-파일)
|
||
|
|
5. [Types 파일](#5-types-파일)
|
||
|
|
6. [Management 파일](#6-management-파일)
|
||
|
|
7. [Dashboard 파일](#7-dashboard-파일)
|
||
|
|
8. [Library 파일](#8-library-파일)
|
||
|
|
9. [루트 컴포넌트 파일](#9-루트-컴포넌트-파일)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. App Router 파일
|
||
|
|
|
||
|
|
### `frontend/app/(pop)/layout.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 전용 레이아웃 래퍼 |
|
||
|
|
| 라우트 그룹 | `(pop)` - URL에 포함되지 않음 |
|
||
|
|
| 특징 | 데스크톱과 분리된 터치 최적화 환경 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/app/(pop)/pop/page.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 메인 대시보드 |
|
||
|
|
| 경로 | `/pop` |
|
||
|
|
| 사용 컴포넌트 | `PopDashboard` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/app/(pop)/pop/screens/[screenId]/page.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 개별 POP 화면 뷰어 |
|
||
|
|
| 경로 | `/pop/screens/:screenId` |
|
||
|
|
| 라인 수 | 468줄 |
|
||
|
|
|
||
|
|
**핵심 코드 구조**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 상태
|
||
|
|
const [popLayoutV3, setPopLayoutV3] = useState<PopLayoutDataV3 | null>(null);
|
||
|
|
const [popLayoutV4, setPopLayoutV4] = useState<PopLayoutDataV4 | null>(null);
|
||
|
|
|
||
|
|
// 레이아웃 로드
|
||
|
|
useEffect(() => {
|
||
|
|
const popLayout = await screenApi.getLayoutPop(screenId);
|
||
|
|
|
||
|
|
if (isPopLayoutV4(popLayout)) {
|
||
|
|
setPopLayoutV4(popLayout);
|
||
|
|
} else if (isPopLayout(popLayout)) {
|
||
|
|
const v3Layout = ensureV3Layout(popLayout);
|
||
|
|
setPopLayoutV3(v3Layout);
|
||
|
|
}
|
||
|
|
}, [screenId]);
|
||
|
|
|
||
|
|
// 렌더링 분기
|
||
|
|
{popLayoutV4 ? (
|
||
|
|
<PopFlexRenderer layout={popLayoutV4} viewportWidth={...} />
|
||
|
|
) : popLayoutV3 ? (
|
||
|
|
<PopLayoutV3Renderer layout={popLayoutV3} modeKey={currentModeKey} />
|
||
|
|
) : (
|
||
|
|
// 빈 화면
|
||
|
|
)}
|
||
|
|
```
|
||
|
|
|
||
|
|
**제공 기능**:
|
||
|
|
- 반응형 모드 감지 (useResponsiveModeWithOverride)
|
||
|
|
- 프리뷰 모드 (`?preview=true`)
|
||
|
|
- 디바이스/방향 수동 전환 (프리뷰 모드)
|
||
|
|
- v1/v2/v3/v4 레이아웃 자동 감지
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/app/(pop)/pop/test-v4/page.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v4 렌더러 테스트 페이지 |
|
||
|
|
| 경로 | `/pop/test-v4` |
|
||
|
|
| 라인 수 | 150줄 |
|
||
|
|
|
||
|
|
**핵심 코드 구조**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export default function TestV4Page() {
|
||
|
|
const [layout, setLayout] = useState<PopLayoutDataV4>(createEmptyPopLayoutV4());
|
||
|
|
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);
|
||
|
|
const [selectedContainerId, setSelectedContainerId] = useState<string | null>(null);
|
||
|
|
const [idCounter, setIdCounter] = useState(1);
|
||
|
|
|
||
|
|
// 컴포넌트 CRUD
|
||
|
|
const handleDropComponent = useCallback(...);
|
||
|
|
const handleDeleteComponent = useCallback(...);
|
||
|
|
const handleUpdateComponent = useCallback(...);
|
||
|
|
const handleUpdateContainer = useCallback(...);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<DndProvider backend={HTML5Backend}>
|
||
|
|
{/* 3-column 레이아웃 */}
|
||
|
|
<PopPanel />
|
||
|
|
<PopCanvasV4 ... />
|
||
|
|
<ComponentEditorPanelV4 ... />
|
||
|
|
</DndProvider>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/app/(pop)/pop/work/page.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 작업 화면 (샘플) |
|
||
|
|
| 경로 | `/pop/work` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Designer 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/PopDesigner.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 화면 디자이너 메인 |
|
||
|
|
| 라인 수 | 524줄 |
|
||
|
|
| 의존성 | react-dnd, ResizablePanelGroup |
|
||
|
|
|
||
|
|
**핵심 Props**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface PopDesignerProps {
|
||
|
|
selectedScreen: ScreenDefinition;
|
||
|
|
onBackToList: () => void;
|
||
|
|
onScreenUpdate?: (updatedScreen: Partial<ScreenDefinition>) => void;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**상태 관리**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 레이아웃 모드
|
||
|
|
const [layoutMode, setLayoutMode] = useState<"v3" | "v4">("v3");
|
||
|
|
|
||
|
|
// v3 레이아웃
|
||
|
|
const [layoutV3, setLayoutV3] = useState<PopLayoutDataV3>(createEmptyPopLayoutV3());
|
||
|
|
|
||
|
|
// v4 레이아웃
|
||
|
|
const [layoutV4, setLayoutV4] = useState<PopLayoutDataV4>(createEmptyPopLayoutV4());
|
||
|
|
|
||
|
|
// 선택 상태
|
||
|
|
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);
|
||
|
|
const [selectedContainerId, setSelectedContainerId] = useState<string | null>(null);
|
||
|
|
|
||
|
|
// UI 상태
|
||
|
|
const [isLoading, setIsLoading] = useState(true);
|
||
|
|
const [isSaving, setIsSaving] = useState(false);
|
||
|
|
const [hasChanges, setHasChanges] = useState(false);
|
||
|
|
|
||
|
|
// v3용 상태
|
||
|
|
const [activeDevice, setActiveDevice] = useState<DeviceType>("tablet");
|
||
|
|
const [activeModeKey, setActiveModeKey] = useState<PopLayoutModeKey>("tablet_landscape");
|
||
|
|
```
|
||
|
|
|
||
|
|
**주요 핸들러**:
|
||
|
|
|
||
|
|
| 핸들러 | 역할 |
|
||
|
|
|--------|------|
|
||
|
|
| `handleDropComponentV3` | v3 컴포넌트 드롭 |
|
||
|
|
| `handleDropComponentV4` | v4 컴포넌트 드롭 |
|
||
|
|
| `handleUpdateComponentDefinitionV3` | v3 컴포넌트 정의 수정 |
|
||
|
|
| `handleUpdateComponentV4` | v4 컴포넌트 수정 |
|
||
|
|
| `handleUpdateContainerV4` | v4 컨테이너 수정 |
|
||
|
|
| `handleDeleteComponentV3` | v3 컴포넌트 삭제 |
|
||
|
|
| `handleDeleteComponentV4` | v4 컴포넌트 삭제 |
|
||
|
|
| `handleSave` | 레이아웃 저장 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/PopCanvas.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v3 CSS Grid 기반 캔버스 |
|
||
|
|
| 렌더링 | CSS Grid |
|
||
|
|
| 모드 | 4개 (태블릿/모바일 x 가로/세로) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/PopCanvasV4.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v4 Flexbox 기반 캔버스 |
|
||
|
|
| 라인 수 | 309줄 |
|
||
|
|
| 렌더링 | Flexbox (via PopFlexRenderer) |
|
||
|
|
|
||
|
|
**핵심 Props**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface PopCanvasV4Props {
|
||
|
|
layout: PopLayoutDataV4;
|
||
|
|
selectedComponentId: string | null;
|
||
|
|
selectedContainerId: string | null;
|
||
|
|
onSelectComponent: (id: string | null) => void;
|
||
|
|
onSelectContainer: (id: string | null) => void;
|
||
|
|
onDropComponent: (type: PopComponentType, containerId: string) => void;
|
||
|
|
onUpdateComponent: (componentId: string, updates: Partial<PopComponentDefinitionV4>) => void;
|
||
|
|
onUpdateContainer: (containerId: string, updates: Partial<PopContainerV4>) => void;
|
||
|
|
onDeleteComponent: (componentId: string) => void;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**뷰포트 프리셋**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const VIEWPORT_PRESETS = [
|
||
|
|
{ id: "mobile", label: "모바일", width: 375, height: 667, icon: Smartphone },
|
||
|
|
{ id: "tablet", label: "태블릿", width: 768, height: 1024, icon: Tablet },
|
||
|
|
{ id: "desktop", label: "데스크톱", width: 1024, height: 768, icon: Monitor },
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
**제공 기능**:
|
||
|
|
- 뷰포트 프리셋 전환
|
||
|
|
- 너비 슬라이더 (320px ~ 1440px)
|
||
|
|
- 줌 컨트롤 (30% ~ 150%)
|
||
|
|
- 패닝 (Space + 드래그 또는 휠 클릭)
|
||
|
|
- 컴포넌트 드롭
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export { default as PopDesigner } from "./PopDesigner";
|
||
|
|
export { PopCanvas } from "./PopCanvas";
|
||
|
|
export { PopCanvasV4 } from "./PopCanvasV4";
|
||
|
|
export * from "./panels";
|
||
|
|
export * from "./renderers";
|
||
|
|
export * from "./types";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Panels 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/panels/PopPanel.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 왼쪽 패널 (컴포넌트 팔레트 + 편집) |
|
||
|
|
| 라인 수 | 369줄 |
|
||
|
|
|
||
|
|
**탭 구성**:
|
||
|
|
1. `components` - 컴포넌트 팔레트
|
||
|
|
2. `edit` - 선택된 컴포넌트 편집
|
||
|
|
|
||
|
|
**컴포넌트 팔레트**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const COMPONENT_PALETTE = [
|
||
|
|
{ type: "pop-field", label: "필드", icon: Type, description: "텍스트, 숫자 등 데이터 입력" },
|
||
|
|
{ type: "pop-button", label: "버튼", icon: MousePointer, description: "저장, 삭제 등 액션 실행" },
|
||
|
|
{ type: "pop-list", label: "리스트", icon: List, description: "데이터 목록 (카드 템플릿 지원)" },
|
||
|
|
{ type: "pop-indicator", label: "인디케이터", icon: Activity, description: "KPI, 상태 표시" },
|
||
|
|
{ type: "pop-scanner", label: "스캐너", icon: ScanLine, description: "바코드/QR 스캔" },
|
||
|
|
{ type: "pop-numpad", label: "숫자패드", icon: Calculator, description: "숫자 입력 전용" },
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
**내보내기 (exports)**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export const DND_ITEM_TYPES = { COMPONENT: "component" };
|
||
|
|
export interface DragItemComponent { ... }
|
||
|
|
export function PopPanel({ ... }: PopPanelProps) { ... }
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/panels/ComponentEditorPanel.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v3 컴포넌트 편집 패널 |
|
||
|
|
| 용도 | PopPanel 내부에서 사용 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/panels/ComponentEditorPanelV4.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v4 오른쪽 속성 패널 |
|
||
|
|
| 라인 수 | 609줄 |
|
||
|
|
|
||
|
|
**핵심 Props**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface ComponentEditorPanelV4Props {
|
||
|
|
component: PopComponentDefinitionV4 | null;
|
||
|
|
container: PopContainerV4 | null;
|
||
|
|
onUpdateComponent?: (updates: Partial<PopComponentDefinitionV4>) => void;
|
||
|
|
onUpdateContainer?: (updates: Partial<PopContainerV4>) => void;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**3개 탭**:
|
||
|
|
|
||
|
|
| 탭 | 아이콘 | 내용 |
|
||
|
|
|----|--------|------|
|
||
|
|
| `size` | Maximize2 | 크기 제약 (fixed/fill/hug) |
|
||
|
|
| `settings` | Settings | 라벨, 타입별 설정 |
|
||
|
|
| `data` | Database | 데이터 바인딩 (미구현) |
|
||
|
|
|
||
|
|
**내부 컴포넌트**:
|
||
|
|
|
||
|
|
| 컴포넌트 | 역할 |
|
||
|
|
|----------|------|
|
||
|
|
| `SizeConstraintForm` | 너비/높이 제약 편집 |
|
||
|
|
| `SizeButton` | fixed/fill/hug 선택 버튼 |
|
||
|
|
| `ContainerSettingsForm` | 컨테이너 방향/정렬/간격 편집 |
|
||
|
|
| `ComponentSettingsForm` | 라벨 편집 |
|
||
|
|
| `DataBindingPlaceholder` | 데이터 바인딩 플레이스홀더 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/panels/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export { PopPanel, DND_ITEM_TYPES } from "./PopPanel";
|
||
|
|
export type { DragItemComponent } from "./PopPanel";
|
||
|
|
export { ComponentEditorPanel } from "./ComponentEditorPanel";
|
||
|
|
export { ComponentEditorPanelV4 } from "./ComponentEditorPanelV4";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Renderers 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/renderers/PopLayoutRenderer.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v3 레이아웃 CSS Grid 렌더러 |
|
||
|
|
| 입력 | PopLayoutDataV3, modeKey |
|
||
|
|
|
||
|
|
**내보내기**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export function PopLayoutRenderer({ ... }) { ... }
|
||
|
|
export function hasBaseLayout(layout: PopLayoutDataV3): boolean { ... }
|
||
|
|
export function getEffectiveModeLayout(layout: PopLayoutDataV3, modeKey: PopLayoutModeKey) { ... }
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/renderers/PopFlexRenderer.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | v4 레이아웃 Flexbox 렌더러 |
|
||
|
|
| 라인 수 | 498줄 |
|
||
|
|
| 입력 | PopLayoutDataV4, viewportWidth |
|
||
|
|
|
||
|
|
**핵심 Props**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface PopFlexRendererProps {
|
||
|
|
layout: PopLayoutDataV4;
|
||
|
|
viewportWidth: number;
|
||
|
|
isDesignMode?: boolean;
|
||
|
|
selectedComponentId?: string | null;
|
||
|
|
onComponentClick?: (componentId: string) => void;
|
||
|
|
onContainerClick?: (containerId: string) => void;
|
||
|
|
onBackgroundClick?: () => void;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**내부 컴포넌트**:
|
||
|
|
|
||
|
|
| 컴포넌트 | 역할 |
|
||
|
|
|----------|------|
|
||
|
|
| `ContainerRenderer` | 컨테이너 재귀 렌더링 |
|
||
|
|
| `ComponentRendererV4` | v4 컴포넌트 렌더링 |
|
||
|
|
|
||
|
|
**핵심 함수**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 반응형 규칙 적용
|
||
|
|
function applyResponsiveRules(container: PopContainerV4, viewportWidth: number): PopContainerV4
|
||
|
|
|
||
|
|
// 크기 제약 → CSS 스타일
|
||
|
|
function calculateSizeStyle(size: PopSizeConstraintV4, settings: PopGlobalSettingsV4): React.CSSProperties
|
||
|
|
|
||
|
|
// 정렬 값 변환
|
||
|
|
function mapAlignment(value: string): React.CSSProperties["alignItems"]
|
||
|
|
function mapJustify(value: string): React.CSSProperties["justifyContent"]
|
||
|
|
|
||
|
|
// 컴포넌트 내용 렌더링
|
||
|
|
function renderComponentContent(component: PopComponentDefinitionV4, ...): React.ReactNode
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/renderers/ComponentRenderer.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 개별 컴포넌트 렌더러 (디자인 모드용) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/renderers/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export { PopLayoutRenderer, hasBaseLayout, getEffectiveModeLayout } from "./PopLayoutRenderer";
|
||
|
|
export { ComponentRenderer } from "./ComponentRenderer";
|
||
|
|
export { PopFlexRenderer } from "./PopFlexRenderer";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Types 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/types/pop-layout.ts`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 레이아웃 전체 타입 시스템 |
|
||
|
|
| 라인 수 | 1442줄 |
|
||
|
|
|
||
|
|
**주요 타입** (v4):
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// v4 레이아웃
|
||
|
|
interface PopLayoutDataV4 {
|
||
|
|
version: "pop-4.0";
|
||
|
|
root: PopContainerV4;
|
||
|
|
components: Record<string, PopComponentDefinitionV4>;
|
||
|
|
dataFlow: PopDataFlow;
|
||
|
|
settings: PopGlobalSettingsV4;
|
||
|
|
metadata?: PopLayoutMetadata;
|
||
|
|
}
|
||
|
|
|
||
|
|
// v4 컨테이너
|
||
|
|
interface PopContainerV4 {
|
||
|
|
id: string;
|
||
|
|
type: "stack";
|
||
|
|
direction: "horizontal" | "vertical";
|
||
|
|
wrap: boolean;
|
||
|
|
gap: number;
|
||
|
|
alignItems: "start" | "center" | "end" | "stretch";
|
||
|
|
justifyContent: "start" | "center" | "end" | "space-between";
|
||
|
|
padding?: number;
|
||
|
|
responsive?: PopResponsiveRuleV4[];
|
||
|
|
children: (string | PopContainerV4)[];
|
||
|
|
}
|
||
|
|
|
||
|
|
// v4 크기 제약
|
||
|
|
interface PopSizeConstraintV4 {
|
||
|
|
width: "fixed" | "fill" | "hug";
|
||
|
|
height: "fixed" | "fill" | "hug";
|
||
|
|
fixedWidth?: number;
|
||
|
|
fixedHeight?: number;
|
||
|
|
minWidth?: number;
|
||
|
|
maxWidth?: number;
|
||
|
|
minHeight?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
// v4 반응형 규칙
|
||
|
|
interface PopResponsiveRuleV4 {
|
||
|
|
breakpoint: number;
|
||
|
|
direction?: "horizontal" | "vertical";
|
||
|
|
gap?: number;
|
||
|
|
hidden?: boolean;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**주요 타입** (v3):
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// v3 레이아웃
|
||
|
|
interface PopLayoutDataV3 {
|
||
|
|
version: "pop-3.0";
|
||
|
|
layouts: {
|
||
|
|
tablet_landscape: PopModeLayoutV3;
|
||
|
|
tablet_portrait: PopModeLayoutV3;
|
||
|
|
mobile_landscape: PopModeLayoutV3;
|
||
|
|
mobile_portrait: PopModeLayoutV3;
|
||
|
|
};
|
||
|
|
components: Record<string, PopComponentDefinition>;
|
||
|
|
dataFlow: PopDataFlow;
|
||
|
|
settings: PopGlobalSettings;
|
||
|
|
metadata?: PopLayoutMetadata;
|
||
|
|
}
|
||
|
|
|
||
|
|
// v3 모드별 레이아웃
|
||
|
|
interface PopModeLayoutV3 {
|
||
|
|
componentPositions: Record<string, GridPosition>;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 그리드 위치
|
||
|
|
interface GridPosition {
|
||
|
|
col: number;
|
||
|
|
row: number;
|
||
|
|
colSpan: number;
|
||
|
|
rowSpan: number;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**주요 함수**:
|
||
|
|
|
||
|
|
| 함수 | 역할 |
|
||
|
|
|------|------|
|
||
|
|
| `createEmptyPopLayoutV4()` | 빈 v4 레이아웃 생성 |
|
||
|
|
| `createEmptyPopLayoutV3()` | 빈 v3 레이아웃 생성 |
|
||
|
|
| `addComponentToV4Layout()` | v4에 컴포넌트 추가 |
|
||
|
|
| `removeComponentFromV4Layout()` | v4에서 컴포넌트 삭제 |
|
||
|
|
| `updateComponentInV4Layout()` | v4 컴포넌트 수정 |
|
||
|
|
| `updateContainerV4()` | v4 컨테이너 수정 |
|
||
|
|
| `findContainerV4()` | v4 컨테이너 찾기 |
|
||
|
|
| `addComponentToV3Layout()` | v3에 컴포넌트 추가 |
|
||
|
|
| `removeComponentFromV3Layout()` | v3에서 컴포넌트 삭제 |
|
||
|
|
| `updateComponentPositionInModeV3()` | v3 특정 모드 위치 수정 |
|
||
|
|
| `isV4Layout()` | v4 타입 가드 |
|
||
|
|
| `isV3Layout()` | v3 타입 가드 |
|
||
|
|
| `ensureV3Layout()` | v1/v2/v3 → v3 변환 |
|
||
|
|
| `migrateV2ToV3()` | v2 → v3 마이그레이션 |
|
||
|
|
| `migrateV1ToV3()` | v1 → v3 마이그레이션 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/designer/types/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export * from "./pop-layout";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Management 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/management/PopCategoryTree.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 화면 카테고리 트리 |
|
||
|
|
| 기능 | 그룹 추가/수정/삭제, 화면 목록 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/management/PopScreenSettingModal.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 화면 설정 모달 |
|
||
|
|
| 기능 | 화면명, 설명, 그룹 설정 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/management/PopScreenPreview.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 화면 미리보기 |
|
||
|
|
| 기능 | 썸네일, 기본 정보 표시 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/management/PopScreenFlowView.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 화면 간 플로우 시각화 |
|
||
|
|
| 기능 | 화면 연결 관계 표시 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/management/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export { PopCategoryTree } from "./PopCategoryTree";
|
||
|
|
export { PopScreenSettingModal } from "./PopScreenSettingModal";
|
||
|
|
export { PopScreenPreview } from "./PopScreenPreview";
|
||
|
|
export { PopScreenFlowView } from "./PopScreenFlowView";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. Dashboard 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/PopDashboard.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 대시보드 메인 |
|
||
|
|
| 구성 | 헤더, KPI, 메뉴그리드, 공지, 푸터 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/DashboardHeader.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 상단 헤더 |
|
||
|
|
| 표시 | 로고, 시간, 사용자 정보 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/DashboardFooter.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 하단 푸터 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/MenuGrid.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 메뉴 그리드 |
|
||
|
|
| 스타일 | 앱 아이콘 형태 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/KpiBar.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | KPI 요약 바 |
|
||
|
|
| 표시 | 핵심 지표 수치 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/NoticeBanner.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 공지 배너 |
|
||
|
|
| 스타일 | 슬라이드 배너 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/NoticeList.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 공지 목록 |
|
||
|
|
| 스타일 | 리스트 형태 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/ActivityList.tsx`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | 최근 활동 목록 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export { PopDashboard } from "./PopDashboard";
|
||
|
|
export { DashboardHeader } from "./DashboardHeader";
|
||
|
|
export { DashboardFooter } from "./DashboardFooter";
|
||
|
|
export { MenuGrid } from "./MenuGrid";
|
||
|
|
export { KpiBar } from "./KpiBar";
|
||
|
|
export { NoticeBanner } from "./NoticeBanner";
|
||
|
|
export { NoticeList } from "./NoticeList";
|
||
|
|
export { ActivityList } from "./ActivityList";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/types.ts`
|
||
|
|
|
||
|
|
대시보드 관련 타입 정의
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/data.ts`
|
||
|
|
|
||
|
|
대시보드 샘플/목업 데이터
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/dashboard/dashboard.css`
|
||
|
|
|
||
|
|
대시보드 전용 스타일
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Library 파일
|
||
|
|
|
||
|
|
### `frontend/lib/api/popScreenGroup.ts`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 화면 그룹 API 클라이언트 |
|
||
|
|
| 라인 수 | 183줄 |
|
||
|
|
|
||
|
|
**타입**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface PopScreenGroup extends ScreenGroup {
|
||
|
|
children?: PopScreenGroup[];
|
||
|
|
}
|
||
|
|
|
||
|
|
interface CreatePopScreenGroupRequest {
|
||
|
|
group_name: string;
|
||
|
|
group_code: string;
|
||
|
|
description?: string;
|
||
|
|
icon?: string;
|
||
|
|
display_order?: number;
|
||
|
|
parent_group_id?: number | null;
|
||
|
|
target_company_code?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface UpdatePopScreenGroupRequest {
|
||
|
|
group_name?: string;
|
||
|
|
description?: string;
|
||
|
|
icon?: string;
|
||
|
|
display_order?: number;
|
||
|
|
is_active?: boolean;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**API 함수**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
async function getPopScreenGroups(searchTerm?: string): Promise<PopScreenGroup[]>
|
||
|
|
async function createPopScreenGroup(data: CreatePopScreenGroupRequest): Promise<...>
|
||
|
|
async function updatePopScreenGroup(id: number, data: UpdatePopScreenGroupRequest): Promise<...>
|
||
|
|
async function deletePopScreenGroup(id: number): Promise<...>
|
||
|
|
async function ensurePopRootGroup(): Promise<...>
|
||
|
|
```
|
||
|
|
|
||
|
|
**유틸리티**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
function buildPopGroupTree(groups: PopScreenGroup[]): PopScreenGroup[]
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/lib/registry/PopComponentRegistry.ts`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 컴포넌트 중앙 레지스트리 |
|
||
|
|
| 라인 수 | 268줄 |
|
||
|
|
|
||
|
|
**타입**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface PopComponentDefinition {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
description: string;
|
||
|
|
category: PopComponentCategory;
|
||
|
|
icon?: string;
|
||
|
|
component: React.ComponentType<any>;
|
||
|
|
configPanel?: React.ComponentType<any>;
|
||
|
|
defaultProps?: Record<string, any>;
|
||
|
|
touchOptimized?: boolean;
|
||
|
|
minTouchArea?: number;
|
||
|
|
supportedDevices?: ("mobile" | "tablet")[];
|
||
|
|
createdAt?: Date;
|
||
|
|
updatedAt?: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
type PopComponentCategory =
|
||
|
|
| "display"
|
||
|
|
| "input"
|
||
|
|
| "action"
|
||
|
|
| "layout"
|
||
|
|
| "feedback";
|
||
|
|
```
|
||
|
|
|
||
|
|
**메서드**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
class PopComponentRegistry {
|
||
|
|
static registerComponent(definition: PopComponentDefinition): void
|
||
|
|
static unregisterComponent(id: string): void
|
||
|
|
static getComponent(id: string): PopComponentDefinition | undefined
|
||
|
|
static getComponentByUrl(url: string): PopComponentDefinition | undefined
|
||
|
|
static getAllComponents(): PopComponentDefinition[]
|
||
|
|
static getComponentsByCategory(category: PopComponentCategory): PopComponentDefinition[]
|
||
|
|
static getComponentsByDevice(device: "mobile" | "tablet"): PopComponentDefinition[]
|
||
|
|
static searchComponents(query: string): PopComponentDefinition[]
|
||
|
|
static getComponentCount(): number
|
||
|
|
static getStatsByCategory(): Record<PopComponentCategory, number>
|
||
|
|
static addEventListener(callback: (event: PopComponentRegistryEvent) => void): void
|
||
|
|
static removeEventListener(callback: (event: PopComponentRegistryEvent) => void): void
|
||
|
|
static clear(): void
|
||
|
|
static hasComponent(id: string): boolean
|
||
|
|
static debug(): void
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/lib/schemas/popComponentConfig.ts`
|
||
|
|
|
||
|
|
| 항목 | 내용 |
|
||
|
|
|------|------|
|
||
|
|
| 역할 | POP 컴포넌트 설정 스키마 |
|
||
|
|
| 라인 수 | 232줄 |
|
||
|
|
| 검증 | Zod 기반 |
|
||
|
|
|
||
|
|
**기본값**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const popCardListDefaults = { ... }
|
||
|
|
const popTouchButtonDefaults = { ... }
|
||
|
|
const popScannerInputDefaults = { ... }
|
||
|
|
const popStatusBadgeDefaults = { ... }
|
||
|
|
```
|
||
|
|
|
||
|
|
**스키마**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const popCardListOverridesSchema = z.object({ ... })
|
||
|
|
const popTouchButtonOverridesSchema = z.object({ ... })
|
||
|
|
const popScannerInputOverridesSchema = z.object({ ... })
|
||
|
|
const popStatusBadgeOverridesSchema = z.object({ ... })
|
||
|
|
```
|
||
|
|
|
||
|
|
**유틸리티**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
function getPopComponentUrl(componentType: string): string
|
||
|
|
function getPopComponentDefaults(componentType: string): Record<string, any>
|
||
|
|
function getPopDefaultsByUrl(componentUrl: string): Record<string, any>
|
||
|
|
function parsePopOverridesByUrl(componentUrl: string, overrides: Record<string, any>): Record<string, any>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. 루트 컴포넌트 파일
|
||
|
|
|
||
|
|
### `frontend/components/pop/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
export * from "./designer";
|
||
|
|
export * from "./management";
|
||
|
|
export * from "./dashboard";
|
||
|
|
// 개별 컴포넌트 export
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/types.ts`
|
||
|
|
|
||
|
|
POP 공통 타입 정의
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/data.ts`
|
||
|
|
|
||
|
|
POP 샘플/목업 데이터
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### `frontend/components/pop/styles.css`
|
||
|
|
|
||
|
|
POP 전역 스타일
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 기타 루트 레벨 컴포넌트
|
||
|
|
|
||
|
|
| 파일 | 역할 |
|
||
|
|
|------|------|
|
||
|
|
| `PopApp.tsx` | POP 앱 셸 |
|
||
|
|
| `PopHeader.tsx` | 공통 헤더 |
|
||
|
|
| `PopBottomNav.tsx` | 하단 네비게이션 |
|
||
|
|
| `PopStatusTabs.tsx` | 상태 탭 |
|
||
|
|
| `PopWorkCard.tsx` | 작업 카드 |
|
||
|
|
| `PopProductionPanel.tsx` | 생산 패널 |
|
||
|
|
| `PopSettingsModal.tsx` | 설정 모달 |
|
||
|
|
| `PopAcceptModal.tsx` | 수락 모달 |
|
||
|
|
| `PopProcessModal.tsx` | 프로세스 모달 |
|
||
|
|
| `PopEquipmentModal.tsx` | 설비 모달 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 파일 수 통계
|
||
|
|
|
||
|
|
| 폴더 | 파일 수 | 설명 |
|
||
|
|
|------|---------|------|
|
||
|
|
| `app/(pop)` | 6 | App Router 페이지 |
|
||
|
|
| `components/pop/designer` | 12 | 디자이너 모듈 |
|
||
|
|
| `components/pop/management` | 5 | 관리 모듈 |
|
||
|
|
| `components/pop/dashboard` | 12 | 대시보드 모듈 |
|
||
|
|
| `components/pop` (루트) | 15 | 루트 컴포넌트 |
|
||
|
|
| `lib` | 3 | 라이브러리 |
|
||
|
|
| **총계** | **53** | |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
*이 문서는 POP 화면 시스템의 파일 목록을 관리하기 위한 참조용으로 작성되었습니다.*
|