2026-02-04 14:14:48 +09:00
|
|
|
# POP v4 통합 설계 모드 스펙
|
|
|
|
|
|
|
|
|
|
**작성일: 2026-02-04**
|
2026-02-04 14:19:12 +09:00
|
|
|
**상태: Phase 1.6 완료 (비율 스케일링 시스템)**
|
2026-02-04 14:14:48 +09:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 개요
|
|
|
|
|
|
|
|
|
|
v3/v4 탭을 제거하고, **v4 자동 모드를 기본**으로 하되 **모드별 오버라이드** 기능을 지원하는 통합 설계 방식.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 핵심 개념
|
|
|
|
|
|
|
|
|
|
### 기존 방식 (v3)
|
|
|
|
|
```
|
|
|
|
|
4개 모드 각각 설계 필요
|
|
|
|
|
태블릿 가로: 버튼 → col 1, row 1
|
|
|
|
|
태블릿 세로: 버튼 → col 1, row 5 (따로 설정)
|
|
|
|
|
모바일 가로: 버튼 → col 1, row 1 (따로 설정)
|
|
|
|
|
모바일 세로: 버튼 → col 1, row 10 (따로 설정)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 새로운 방식 (v4 통합)
|
|
|
|
|
```
|
|
|
|
|
기본: 태블릿 가로에서 규칙 설정
|
|
|
|
|
버튼 → width: fill, height: 48px
|
|
|
|
|
|
|
|
|
|
결과: 모든 모드에 자동 적용
|
|
|
|
|
태블릿 가로: 버튼 너비 1024px, 높이 48px
|
|
|
|
|
태블릿 세로: 버튼 너비 768px, 높이 48px
|
|
|
|
|
모바일 가로: 버튼 너비 667px, 높이 48px
|
|
|
|
|
모바일 세로: 버튼 너비 375px, 높이 48px
|
|
|
|
|
|
|
|
|
|
예외: 특정 모드에서 편집하면 오버라이드
|
|
|
|
|
모바일 세로: 버튼 높이 36px (수동 설정)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 현재 UI (Phase 1.5 완료)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
|
|
|
│ ← 목록 화면명 *변경됨 [↶][↷] 자동 레이아웃 (v4) [저장] │
|
|
|
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
|
|
|
│ 편집 중: v4 (자동 반응형) │
|
|
|
|
|
│ 규칙 기반 레이아웃 │
|
|
|
|
|
├────────────┬────────────────────────────────────┬───────────────┤
|
|
|
|
|
│ 컴포넌트 │ 미리보기: [모바일↕][모바일↔] │ 속성 │
|
|
|
|
|
│ │ [태블릿↕][태블릿↔(기본)] │ │
|
|
|
|
|
│ 필드 │ 너비: [====●====] 1024 x 768 │ │
|
|
|
|
|
│ 버튼 │ │ │
|
|
|
|
|
│ 리스트 │ ┌──────────────────────────────┐ │ │
|
|
|
|
|
│ 인디케이터 │ │ [필드1] [필드2] [필드3] │ │ │
|
|
|
|
|
│ 스캐너 │ │ [필드4] [Spacer] [버튼] │ │ │
|
|
|
|
|
│ 숫자패드 │ │ │ │ │
|
|
|
|
|
│ 스페이서 │ │ (가로 배치 + 자동 줄바꿈) │ │ │
|
|
|
|
|
│ │ │ (스크롤 가능) │ │ │
|
|
|
|
|
│ │ └──────────────────────────────┘ │ │
|
|
|
|
|
│ │ 태블릿 가로 (1024x768) │ │
|
|
|
|
|
└────────────┴────────────────────────────────────┴───────────────┘
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 레이아웃 방식 (업계 표준)
|
|
|
|
|
|
|
|
|
|
| 서비스 | 방식 |
|
|
|
|
|
|--------|------|
|
|
|
|
|
| Figma | Auto Layout (Flexbox) |
|
|
|
|
|
| Webflow | Flexbox + CSS Grid |
|
|
|
|
|
| FlutterFlow | Row/Column/Stack |
|
|
|
|
|
| Adalo 2.0 | Flexbox + Constraints |
|
|
|
|
|
| **POP v4** | **Flexbox (horizontal + wrap)** |
|
|
|
|
|
|
|
|
|
|
### Spacer 컴포넌트 사용법
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
[버튼A] [Spacer(fill)] [버튼B] → 버튼B가 오른쪽 끝으로
|
|
|
|
|
[Spacer] [컴포넌트] [Spacer] → 컴포넌트가 가운데로
|
|
|
|
|
[Spacer(fill)] [컴포넌트] → 컴포넌트가 오른쪽으로
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 프리셋 버튼 (4개 모드)
|
|
|
|
|
|
|
|
|
|
| 버튼 | 해상도 | 설명 |
|
|
|
|
|
|------|--------|------|
|
|
|
|
|
| 모바일↕ | 375 x 667 | 모바일 세로 |
|
|
|
|
|
| 모바일↔ | 667 x 375 | 모바일 가로 |
|
|
|
|
|
| 태블릿↕ | 768 x 1024 | 태블릿 세로 |
|
|
|
|
|
| 태블릿↔* | 1024 x 768 | 태블릿 가로 (기본) |
|
|
|
|
|
|
|
|
|
|
### 레이아웃 판별 로직
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// 새 화면 또는 빈 레이아웃 → v4로 시작
|
|
|
|
|
const hasValidLayout = loadedLayout && loadedLayout.version;
|
|
|
|
|
const hasComponents = loadedLayout?.components &&
|
|
|
|
|
Object.keys(loadedLayout.components).length > 0;
|
|
|
|
|
|
|
|
|
|
if (hasValidLayout && hasComponents) {
|
|
|
|
|
// v4면 v4, 그 외 v3로 변환
|
|
|
|
|
} else {
|
|
|
|
|
// v4로 새로 시작
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 오버라이드 동작 (Phase 2 예정)
|
|
|
|
|
|
|
|
|
|
### 자동 감지 방식
|
|
|
|
|
1. 사용자가 **태블릿 가로(기본)**에서 편집 → 기본 규칙 저장
|
|
|
|
|
2. 사용자가 **다른 모드**에서 편집 → 해당 모드 오버라이드 자동 저장
|
|
|
|
|
3. 편집 안 한 모드 → 기본 규칙에서 자동 계산
|
|
|
|
|
|
|
|
|
|
### 편집 상태 표시
|
|
|
|
|
|
|
|
|
|
| 상태 | 버튼 색상 | 설명 |
|
|
|
|
|
|------|----------|------|
|
|
|
|
|
| 기본 (태블릿 가로) | 강조 + "(기본)" | 항상 표시 |
|
|
|
|
|
| 자동 | 기본 색상 | 편집 안 함 |
|
|
|
|
|
| 편집됨 | 강조 색상 | 오버라이드 있음 |
|
|
|
|
|
|
|
|
|
|
### 되돌리기
|
|
|
|
|
- 편집된 모드에만 "자동으로 되돌리기" 버튼 활성화
|
|
|
|
|
- 클릭 시 오버라이드 삭제 → 기본 규칙 복원
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 데이터 구조
|
|
|
|
|
|
|
|
|
|
### PopLayoutDataV4 (Phase 2에서 수정 예정)
|
|
|
|
|
```typescript
|
|
|
|
|
interface PopLayoutDataV4 {
|
|
|
|
|
version: "pop-4.0";
|
|
|
|
|
root: PopContainerV4;
|
|
|
|
|
components: Record<string, PopComponentDefinitionV4>;
|
|
|
|
|
dataFlow: PopDataFlow;
|
|
|
|
|
settings: PopGlobalSettingsV4;
|
|
|
|
|
|
|
|
|
|
// 모드별 오버라이드 (Phase 2에서 추가)
|
|
|
|
|
overrides?: {
|
|
|
|
|
mobile_portrait?: ModeOverride;
|
|
|
|
|
mobile_landscape?: ModeOverride;
|
|
|
|
|
tablet_portrait?: ModeOverride;
|
|
|
|
|
// tablet_landscape는 기본이므로 오버라이드 없음
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface ModeOverride {
|
|
|
|
|
components?: Record<string, Partial<PopComponentDefinitionV4>>;
|
|
|
|
|
containers?: Record<string, Partial<PopContainerV4>>;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### PopComponentDefinitionV4 (Phase 3에서 수정 예정)
|
|
|
|
|
```typescript
|
|
|
|
|
interface PopComponentDefinitionV4 {
|
|
|
|
|
type: PopComponentType;
|
|
|
|
|
label?: string;
|
|
|
|
|
size: PopSizeConstraintV4;
|
|
|
|
|
alignSelf?: "start" | "center" | "end" | "stretch";
|
|
|
|
|
|
|
|
|
|
// 모드별 표시 설정 (Phase 3에서 추가)
|
|
|
|
|
visibility?: {
|
|
|
|
|
mobile_portrait?: boolean; // 기본 true
|
|
|
|
|
mobile_landscape?: boolean; // 기본 true
|
|
|
|
|
tablet_portrait?: boolean; // 기본 true
|
|
|
|
|
tablet_landscape?: boolean; // 기본 true
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 컴포넌트 표시/숨김 (Phase 3 예정)
|
|
|
|
|
|
|
|
|
|
### 업계 표준 (Webflow, Figma)
|
|
|
|
|
- 삭제가 아닌 **숨김** 처리
|
|
|
|
|
- 특정 모드에서만 `display: none`
|
|
|
|
|
- 언제든 다시 표시 가능
|
|
|
|
|
|
|
|
|
|
### UI (속성 패널)
|
|
|
|
|
```
|
|
|
|
|
┌─────────────────────────┐
|
|
|
|
|
│ 버튼 │
|
|
|
|
|
├─────────────────────────┤
|
|
|
|
|
│ 표시 설정 │
|
|
|
|
|
│ [x] 모바일 세로 │
|
|
|
|
|
│ [x] 모바일 가로 │
|
|
|
|
|
│ [x] 태블릿 세로 │
|
|
|
|
|
│ [x] 태블릿 가로 │
|
|
|
|
|
│ │
|
|
|
|
|
│ (체크 해제 = 숨김) │
|
|
|
|
|
└─────────────────────────┘
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 구현 상태
|
|
|
|
|
|
|
|
|
|
### Phase 1: 기본 구조 (완료)
|
|
|
|
|
- [x] v3/v4 탭 제거 (자동 판별)
|
|
|
|
|
- [x] 새 화면 → v4로 시작
|
|
|
|
|
- [x] 기존 v3 화면 → v3로 로드 (하위 호환)
|
|
|
|
|
- [x] 4개 프리셋 버튼 (모바일↕, 모바일↔, 태블릿↕, 태블릿↔)
|
|
|
|
|
- [x] 기본 프리셋 표시 (태블릿 가로 + "(기본)")
|
|
|
|
|
- [x] 슬라이더 유지 (320~1200px, 비율 유지)
|
|
|
|
|
- [x] ComponentPaletteV4 생성
|
|
|
|
|
|
|
|
|
|
### Phase 1.5: Flexbox 가로 배치 (완료)
|
|
|
|
|
- [x] Undo/Redo (Ctrl+Z / Ctrl+Shift+Z, 데스크탑 모드와 동일 방식)
|
|
|
|
|
- [x] 드래그 리사이즈 핸들
|
|
|
|
|
- [x] Flexbox 가로 배치 (`direction: horizontal`, `wrap: true`)
|
|
|
|
|
- [x] 컴포넌트 타입별 기본 크기 설정
|
|
|
|
|
- [x] Spacer 컴포넌트 (`pop-spacer`)
|
|
|
|
|
- [x] 컴포넌트 순서 변경 (드래그 앤 드롭)
|
|
|
|
|
- [x] 디바이스 스크린 무한 스크롤
|
|
|
|
|
|
2026-02-04 14:19:12 +09:00
|
|
|
### Phase 1.6: 비율 스케일링 시스템 (완료)
|
|
|
|
|
- [x] 기준 너비 1024px (10인치 태블릿 가로)
|
|
|
|
|
- [x] 최대 너비 1366px (12인치 태블릿)
|
|
|
|
|
- [x] 뷰포트 감지 및 resize 이벤트 리스너
|
|
|
|
|
- [x] 컴포넌트 크기 스케일 적용 (fixedWidth/Height)
|
|
|
|
|
- [x] 컨테이너 스케일 적용 (gap, padding)
|
|
|
|
|
- [x] 디자인 모드 분리 (scale=1)
|
|
|
|
|
- [x] DndProvider 에러 수정
|
|
|
|
|
|
2026-02-04 14:14:48 +09:00
|
|
|
### Phase 2: 오버라이드 기능 (다음)
|
|
|
|
|
- [ ] ModeOverride 데이터 구조 추가
|
|
|
|
|
- [ ] 편집 감지 → 자동 오버라이드 저장
|
|
|
|
|
- [ ] 편집 상태 표시 (버튼 색상)
|
|
|
|
|
- [ ] "자동으로 되돌리기" 버튼
|
|
|
|
|
|
|
|
|
|
### Phase 3: 컴포넌트 표시/숨김
|
|
|
|
|
- [ ] visibility 속성 추가
|
|
|
|
|
- [ ] 속성 패널 체크박스 UI
|
|
|
|
|
- [ ] 렌더러에서 visibility 처리
|
|
|
|
|
|
|
|
|
|
### Phase 4: 순서 오버라이드
|
|
|
|
|
- [ ] 모드별 children 순서 오버라이드
|
|
|
|
|
- [ ] 드래그로 순서 변경 UI
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 관련 파일
|
|
|
|
|
|
|
|
|
|
| 파일 | 역할 | 상태 |
|
|
|
|
|
|------|------|------|
|
|
|
|
|
| `PopDesigner.tsx` | v3/v4 통합 디자이너 | 완료 |
|
|
|
|
|
| `PopCanvasV4.tsx` | v4 캔버스 (4개 프리셋 + 슬라이더) | 완료 |
|
2026-02-04 14:19:32 +09:00
|
|
|
| `PopFlexRenderer.tsx` | v4 Flexbox 렌더러 + 비율 스케일링 | 완료 |
|
2026-02-04 14:14:48 +09:00
|
|
|
| `ComponentPaletteV4.tsx` | v4 컴포넌트 팔레트 | 완료 |
|
|
|
|
|
| `ComponentEditorPanelV4.tsx` | v4 속성 편집 패널 | 완료 |
|
|
|
|
|
| `pop-layout.ts` | v3/v4 타입 정의 | 완료, Phase 2-3에서 수정 예정 |
|
2026-02-04 14:19:32 +09:00
|
|
|
| `page.tsx` (뷰어) | v4 뷰어 + viewportWidth 감지 | 완료 |
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 비율 스케일링 시스템
|
|
|
|
|
|
|
|
|
|
### 업계 표준
|
|
|
|
|
Rockwell Automation HMI의 "Scale with Fixed Aspect Ratio" 방식 적용
|
|
|
|
|
|
|
|
|
|
### 원리
|
|
|
|
|
10인치(1024px) 기준으로 디자인 → 8~12인치에서 배치 유지, 크기만 비례 조정
|
|
|
|
|
|
|
|
|
|
### 계산
|
|
|
|
|
```
|
|
|
|
|
scale = viewportWidth / 1024
|
|
|
|
|
scaledWidth = originalWidth * scale
|
|
|
|
|
scaledHeight = originalHeight * scale
|
|
|
|
|
scaledGap = originalGap * scale
|
|
|
|
|
scaledPadding = originalPadding * scale
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 화면별 결과
|
|
|
|
|
|
|
|
|
|
| 화면 | scale | 200px 컴포넌트 | 8px gap |
|
|
|
|
|
|------|-------|----------------|---------|
|
|
|
|
|
| 8인치 (800px) | 0.78 | 156px | 6px |
|
|
|
|
|
| 10인치 (1024px) | 1.00 | 200px | 8px |
|
|
|
|
|
| 12인치 (1366px) | 1.33 | 266px | 11px |
|
|
|
|
|
| 14인치+ | 1.33 (max) | 266px + 여백 | 11px |
|
|
|
|
|
|
|
|
|
|
### 적용 위치
|
|
|
|
|
|
|
|
|
|
| 파일 | 함수/변수 | 역할 |
|
|
|
|
|
|------|----------|------|
|
|
|
|
|
| `PopFlexRenderer.tsx` | `BASE_VIEWPORT_WIDTH` | 기준 너비 상수 (1024) |
|
|
|
|
|
| `PopFlexRenderer.tsx` | `calculateSizeStyle(size, settings, scale)` | 크기 스케일 적용 |
|
|
|
|
|
| `PopFlexRenderer.tsx` | `ContainerRenderer.containerStyle` | gap, padding 스케일 적용 |
|
|
|
|
|
| `page.tsx` | `viewportWidth` state | 뷰포트 너비 감지 |
|
|
|
|
|
| `page.tsx` | `Math.min(window.innerWidth, 1366)` | 최대 너비 제한 |
|
2026-02-04 14:14:48 +09:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
*이 문서는 v4 통합 설계 모드의 스펙을 정의합니다.*
|
|
|
|
|
*최종 업데이트: 2026-02-04*
|