240 lines
7.6 KiB
Markdown
240 lines
7.6 KiB
Markdown
# 2026-02-06 작업 기록
|
|
|
|
## 요약
|
|
v5.1 자동 줄바꿈 + 검토 필요 시스템 완성, 브레이크포인트 재설계, 세로 자동 확장 구현
|
|
|
|
---
|
|
|
|
## 완료
|
|
|
|
### 브레이크포인트 재설계
|
|
- [x] GRID_BREAKPOINTS 값 수정 (기기 기반)
|
|
- [x] detectGridMode() 조건 수정
|
|
- [x] useDeviceOrientation.ts TABLET_MIN 768로 변경
|
|
- [x] 뷰어에서 detectGridMode() 사용하여 일관성 확보
|
|
|
|
### 세로 자동 확장
|
|
- [x] VIEWPORT_PRESETS에서 height 속성 제거
|
|
- [x] dynamicCanvasHeight useMemo 추가
|
|
- [x] MIN_CANVAS_HEIGHT, CANVAS_EXTRA_ROWS 상수 추가
|
|
- [x] gridLabels 동적 계산 (행 수 자동 조정)
|
|
- [x] gridCells 동적 계산 (PopRenderer)
|
|
- [x] 뷰어 프리뷰 모드 스크롤 지원
|
|
|
|
### 자동 줄바꿈 시스템 (v5.1)
|
|
- [x] convertAndResolvePositions() 자동 줄바꿈 로직
|
|
- [x] 원본 col 보존 로직
|
|
- [x] 초과 컴포넌트 맨 아래 배치
|
|
- [x] colSpan 자동 축소
|
|
|
|
### 검토 필요 시스템
|
|
- [x] needsReview() 함수 추가
|
|
- [x] OutOfBoundsPanel → ReviewPanel 변경
|
|
- [x] 파란색 테마 (안내 느낌)
|
|
- [x] 클릭 시 컴포넌트 선택
|
|
|
|
### 버그 수정
|
|
- [x] hiddenComponentIds 중복 정의 에러 수정
|
|
- [x] useDrop 의존성 배열 수정
|
|
- [x] 검토 필요 패널 모드별 표시 불일치 수정
|
|
|
|
### 그리드 셀 크기 강제 고정 (v5.2.1)
|
|
- [x] gridAutoRows → gridTemplateRows 변경 (행 높이 강제 고정)
|
|
- [x] dynamicRowCount를 gridStyle과 gridCells에서 공유
|
|
- [x] 컴포넌트 overflow: visible → overflow: hidden 변경
|
|
- [x] PopRenderer dynamicRowCount에서 숨김 컴포넌트 제외
|
|
- [x] PopCanvas와 PopRenderer의 여유행 기준 통일 (+3)
|
|
- [x] 디버깅용 console.log 2개 삭제
|
|
- [x] 뷰어 page.tsx viewportWidth 선언 순서 수정
|
|
|
|
---
|
|
|
|
## 브레이크포인트 변경 상세
|
|
|
|
### 변경 전 → 변경 후
|
|
|
|
| 모드 | 변경 전 | 변경 후 | 근거 |
|
|
|------|--------|--------|------|
|
|
| mobile_portrait | ~599px | ~479px | 스마트폰 세로 최대 440px |
|
|
| mobile_landscape | 600~839px | 480~767px | 767px까지 스마트폰 |
|
|
| tablet_portrait | 840~1023px | 768~1023px | iPad Mini 768px 포함 |
|
|
| tablet_landscape | 1024px+ | 동일 | 변경 없음 |
|
|
|
|
### 연구 결과 (기기별 CSS 뷰포트)
|
|
|
|
| 기기 | CSS 뷰포트 너비 |
|
|
|------|----------------|
|
|
| iPhone SE | 375px |
|
|
| iPhone 16 Pro | 402px |
|
|
| Galaxy S25 Ultra | 440px |
|
|
| iPad Mini 7 | 768px |
|
|
| iPad Pro 11 | 834px (세로), 1194px (가로) |
|
|
| iPad Pro 13 | 1024px (세로), 1366px (가로) |
|
|
|
|
---
|
|
|
|
## 세로 자동 확장 상세
|
|
|
|
### 핵심 상수
|
|
|
|
```typescript
|
|
const MIN_CANVAS_HEIGHT = 600; // 최소 캔버스 높이 (px)
|
|
const CANVAS_EXTRA_ROWS = 3; // 항상 유지되는 여유 행 수
|
|
```
|
|
|
|
### 동적 높이 계산 로직
|
|
|
|
```typescript
|
|
const dynamicCanvasHeight = useMemo(() => {
|
|
const visibleComps = Object.values(layout.components)
|
|
.filter(comp => !hiddenComponentIds.includes(comp.id));
|
|
|
|
if (visibleComps.length === 0) return MIN_CANVAS_HEIGHT;
|
|
|
|
const maxRowEnd = visibleComps.reduce((max, comp) => {
|
|
const pos = getEffectivePosition(comp);
|
|
return Math.max(max, pos.row + pos.rowSpan);
|
|
}, 1);
|
|
|
|
const totalRows = maxRowEnd + CANVAS_EXTRA_ROWS;
|
|
const height = totalRows * (rowHeight + gap) + padding * 2;
|
|
|
|
return Math.max(MIN_CANVAS_HEIGHT, height);
|
|
}, [dependencies]);
|
|
```
|
|
|
|
### 영향받는 영역
|
|
|
|
| 영역 | 변경 |
|
|
|------|------|
|
|
| 캔버스 컨테이너 | minHeight: dynamicCanvasHeight |
|
|
| 디바이스 스크린 | minHeight: dynamicCanvasHeight |
|
|
| 행 라벨 | 동적 행 수 계산 |
|
|
| 격자 셀 | 동적 행 수 계산 |
|
|
|
|
---
|
|
|
|
## 자동 줄바꿈 로직 상세
|
|
|
|
### 처리 단계
|
|
|
|
```
|
|
1. 비율 변환 + 원본 col 보존
|
|
converted = map(comp => ({
|
|
position: convertPositionToMode(comp.position),
|
|
originalCol: comp.position.col, // 원본 보존
|
|
}))
|
|
|
|
2. 정상 vs 초과 분리
|
|
normalComponents = filter(originalCol <= targetColumns)
|
|
overflowComponents = filter(originalCol > targetColumns)
|
|
|
|
3. 초과 컴포넌트 맨 아래 배치
|
|
maxRow = normalComponents의 최대 (row + rowSpan - 1)
|
|
overflowComponents → col=1, row=maxRow+1
|
|
|
|
4. colSpan 자동 축소
|
|
if (colSpan > targetColumns) colSpan = targetColumns
|
|
|
|
5. 겹침 해결
|
|
resolveOverlaps([...normalComponents, ...wrappedComponents])
|
|
```
|
|
|
|
---
|
|
|
|
## 대화 핵심
|
|
|
|
### 반응형 불일치 문제
|
|
|
|
**사용자 리포트**:
|
|
> "아이폰 SE, iPad Pro 프리셋은 잘 되는데,
|
|
> 브라우저 수동 리사이즈 시 6칸 모드가 적용 안 되는 것 같아"
|
|
|
|
**원인 분석**:
|
|
- useResponsiveMode: width/height 비율로 landscape/portrait 판정
|
|
- GRID_BREAKPOINTS: 순수 너비 기반
|
|
- 768~839px 구간에서 불일치 발생
|
|
|
|
**해결**:
|
|
- 뷰어에서 detectGridMode(viewportWidth) 사용
|
|
- 프리뷰 모드만 useResponsiveModeWithOverride 유지
|
|
|
|
### 세로 무한 스크롤 결정
|
|
|
|
**사용자 질문**:
|
|
> "우리 화면 모드는 너비만 신경쓰면 되잖아?
|
|
> 세로는 무한 스크롤이 가능해야 하겠네?"
|
|
|
|
**확인 사항**:
|
|
1. 너비만 신경쓰면 됨 ✅
|
|
2. 캔버스 세로 무한 스크롤 필요 ✅
|
|
3. 뷰어에서 터치 스크롤 지원 ✅
|
|
|
|
**구현 방식 선택**:
|
|
- 수동 행 추가 방식 vs **자동 확장 방식 (채택)**
|
|
- 이유: 여유 공간 3행 자동 유지, 사용자 부담 최소화
|
|
|
|
---
|
|
|
|
## 빌드 결과
|
|
|
|
```
|
|
exit_code: 0
|
|
주요 변경 파일: 6개
|
|
```
|
|
|
|
---
|
|
|
|
## 관련 링크
|
|
|
|
- ADR: [decisions/005-breakpoint-redesign.md](../decisions/005-breakpoint-redesign.md)
|
|
- ADR: [decisions/006-auto-wrap-review-system.md](../decisions/006-auto-wrap-review-system.md)
|
|
- 이전 세션: [sessions/2026-02-05.md](./2026-02-05.md)
|
|
|
|
---
|
|
|
|
## 이번 작업에서 배운 것
|
|
|
|
### 새로 알게 된 기술 개념
|
|
|
|
- **gridAutoRows vs gridTemplateRows**: `gridAutoRows`는 행의 *최소* 높이만 보장하고 콘텐츠에 따라 늘어날 수 있음. `gridTemplateRows`는 행 높이를 *강제 고정*함. 가이드 셀과 컴포넌트가 같은 Grid 컨테이너에 있을 때, 컴포넌트 콘텐츠가 행 높이를 밀어내면 인접한 빈 가이드 셀 크기도 함께 변해 시각적 불일치가 발생함.
|
|
|
|
### 발생했던 에러와 원인 패턴
|
|
|
|
| 에러 | 원인 패턴 |
|
|
|------|-----------|
|
|
| 그리드 셀 크기 불균일 | 같은 CSS Grid에서 gridAutoRows(최소값)를 사용하면 콘텐츠가 행 높이를 변형시킴 |
|
|
| Canvas vs Renderer 행 수 불일치 | 같은 데이터(행 수)를 두 곳에서 계산하면서 필터 조건(숨김 제외)이 달랐음 |
|
|
| 디버깅 console.log 잔존 | 기능 완료 후 정리 단계를 생략함 |
|
|
| viewportWidth 참조 순서 | 변수 사용 코드가 선언 코드보다 위에 위치 (JS 호이스팅으로 동작은 하지만 가독성 저하) |
|
|
|
|
### 다음에 비슷한 작업할 때 주의할 점
|
|
|
|
1. **CSS Grid에서 "고정 크기" 셀이 필요하면 `gridTemplateRows`를 사용**하고, `gridAutoRows`는 동적 추가행 대비용으로만 유지
|
|
2. **같은 데이터를 여러 곳에서 계산할 때, 필터 조건이 동일한지 반드시 비교** (숨김 제외 등)
|
|
3. **기능 완료 후 `console.log`를 Grep으로 검색하여 디버깅 로그 정리**
|
|
4. **변수 선언 순서는 의존 관계 순서와 일치**시켜야 가독성과 유지보수성 확보
|
|
|
|
---
|
|
|
|
## 중단점
|
|
|
|
> **다음 작업**: Phase 4 실제 컴포넌트 구현
|
|
> - pop-label, pop-button 등 실제 렌더링 구현
|
|
> - 데이터 바인딩 연결
|
|
> - STATUS.md의 "다음 작업" 섹션 참조
|
|
|
|
---
|
|
|
|
## 다음 작업자 참고
|
|
|
|
1. **테스트 필요**
|
|
- 아이폰 SE 실기기 테스트
|
|
- iPad Mini 세로 모드 확인
|
|
- 브라우저 리사이즈로 모드 전환 확인
|
|
|
|
2. **향후 작업**
|
|
- Phase 4: 실제 컴포넌트 구현 (pop-label, pop-button 등)
|
|
- 데이터 바인딩 연결
|
|
- 워크플로우 연동
|