# [체크리스트] 버튼 아이콘화 - 화면 디자이너 버튼 표시 모드 확장

> 관련 문서: [계획서](./BIC[계획]-버튼-아이콘화.md) | [맥락노트](./BIC[맥락]-버튼-아이콘화.md)

---

## 공정 상태

- 전체 진행률: **100%** (전 단계 구현 및 검증 완료)
- 현재 단계: 완료

---

## 구현 체크리스트

### 1단계: 아이콘 매핑 파일 생성

- [x] `frontend/lib/button-icon-map.tsx` 생성
- [x] 버튼 액션별 추천 아이콘 매핑 (`actionIconMap`) 정의 (14개 액션 x 6개 아이콘)
- [x] 아이콘 크기 비율 매핑 (`iconSizePresets`) 정의 (작게/보통/크게/매우 크게, 버튼 높이 대비 %) + `getIconSizeStyle()` 유틸
- [x] lucide 아이콘 동적 렌더링 포함 `getButtonDisplayContent()` 구현
- [x] SVG 아이콘 렌더링 (DOMPurify 정화 via `isomorphic-dompurify`)
- [x] 아이콘 이름 → 컴포넌트 매핑 객체 (`iconMap`) + `addToIconMap()` 동적 추가
- [x] deprecated 액션용 안내 문구 상수 (`NO_ICON_MESSAGE`) 정의
- [x] `isomorphic-dompurify` 기존 설치 확인 (추가 설치 불필요)
- [x] `ButtonIconRenderer` 공용 컴포넌트 추가 (모든 렌더러에서 재사용)
- [x] `getDefaultIconForAction()` 디폴트 아이콘 유틸 함수 추가 (액션별 첫 번째 추천 / 범용 폴백)
- [x] `FALLBACK_ICON_NAME` 상수 + `SquareMousePointer` import/매핑 추가

### 2단계: ButtonConfigPanel 수정

- [x] 표시 모드 버튼 그룹 UI 추가 (텍스트 / 아이콘 / 아이콘+텍스트)
- [x] `displayMode` 상태 관리 및 `onUpdateProperty` 연동
- [x] 아이콘 모드 선택 시 조건부 UI 분기 (텍스트 입력 숨김 → 아이콘 선택 표시)
- [x] 아이콘+텍스트 모드 선택 시 아이콘 선택 + 텍스트 입력 **동시** 표시
- [x] 버튼 액션별 추천 아이콘 그리드 렌더링 (4열 그리드)
- [x] 선택된 아이콘 하이라이트 (`ring-2 ring-primary/30 border-primary`)
- [x] 아이콘 크기 비율 프리셋 버튼 그룹 (작게/보통/크게/매우 크게, 한글 라벨)
- [x] px 직접 입력 필드 제거 (비율 프리셋만 제공)
- [x] `icon.name`, `icon.size` 를 `onUpdateProperty`로 저장
- [x] 아이콘 색상 컬러 피커 구현 (`ColorPickerWithTransparent` 재사용)
- [x] "텍스트 색상과 동일" 초기화 버튼 구현
- [x] 텍스트 위치 4방향 설정 추가 (`iconTextPosition`, 왼쪽/오른쪽/위쪽/아래쪽)
- [x] 아이콘-텍스트 간격 설정 추가 (`iconGap`, 슬라이더 + 직접 입력, 아이콘+텍스트 모드 전용)
- [x] 아이콘 모드 레이아웃 안내 문구 표시 (Info 아이콘 + bg-blue-50 박스)
- [x] 액션 변경 시 선택 아이콘 자동 초기화 로직 (추천 목록에 없으면 해제)
- [x] deprecated 액션에서 안내 문구 + 커스텀 아이콘 추가 버튼 표시
- [x] 아이콘/아이콘+텍스트 모드 전환 시 아이콘 미선택이면 디폴트 아이콘 자동 부여
- [x] 커스텀 아이콘 삭제 시 디폴트 아이콘으로 자동 복귀 (텍스트 모드 전환 방지)

### 3단계: 커스텀 아이콘 추가/삭제 (lucide 검색)

- [x] "lucide 검색" 버튼 UI
- [x] lucide 아이콘 검색 팝오버 (Popover + Command + CommandInput)
- [x] `import { icons } from "lucide-react"` 기반 전체 아이콘 검색/필터링
- [x] 선택 시 `componentConfig.customIcons` 배열 추가 + `addToIconMap` 동적 등록
- [x] lucide 커스텀 아이콘 그리드 렌더링 (추천 아이콘 아래, 구분선 포함)
- [x] lucide 커스텀 아이콘 X 버튼으로 개별 삭제

### 3-1단계: 커스텀 아이콘 추가/삭제 (SVG 붙여넣기)

- [x] "SVG 붙여넣기" 버튼 UI (Popover)
- [x] SVG 입력 textarea + DOMPurify 실시간 미리보기
- [x] SVG 유효성 검사 (`<svg` 태그 포함 여부)
- [x] 아이콘 이름 입력 필드 (관리자가 구분용 이름 지정)
- [x] DOMPurify로 SVG 정화(sanitize) 후 저장
- [x] `componentConfig.customSvgIcons` 배열에 `{ name, svg }` 추가
- [x] SVG 커스텀 아이콘 그리드 렌더링 (lucide 커스텀 아이콘과 함께 표시)
- [x] SVG 커스텀 아이콘 X 버튼으로 개별 삭제
- [x] 커스텀 아이콘(lucide + SVG 모두)이 모든 버튼 액션에서 공통 노출

### 4단계: 버튼 렌더링 수정 (뷰어/위젯)

- [x] `InteractiveScreenViewerDynamic.tsx` - `ButtonIconRenderer` 적용
- [x] `InteractiveScreenViewer.tsx` - `ButtonIconRenderer` 적용
- [x] `ButtonWidget.tsx` - `ButtonIconRenderer` 적용 (디자인/실행 모드 모두)
- [x] `OptimizedButtonComponent.tsx` - `ButtonIconRenderer` 적용 (실행 중 "처리 중..." 유지)
- [x] `ButtonPrimaryComponent.tsx` - `ButtonIconRenderer` 적용 (v2-button-primary 캔버스 렌더링)
- [x] lucide 아이콘 렌더링 (`icon.type === "lucide"`, `getLucideIcon` 조회)
- [x] SVG 아이콘 렌더링 (`icon.type === "svg"`, DOMPurify 정화 후 innerHTML)
- [x] 아이콘+텍스트 모드: `inline-flex items-center` + 동적 `gap` (iconGap px)
- [x] `icon.color` 설정 시 아이콘만 별도 색상 적용 (inline style)
- [x] `icon.color` 미설정 시 textColor 상속 (currentColor 기본)
- [x] 아이콘 크기 비율 프리셋 `getIconSizeStyle()` 처리 (버튼 높이 대비 %)
- [x] 텍스트 위치 4방향 렌더링 (`flexDirection` + 요소 순서 조합)

### 4-2단계: 버튼 테두리 이중 적용 수정

- [x] `RealtimePreviewDynamic.tsx` — position wrapper에서 버튼 컴포넌트 border strip 추가
- [x] `ButtonPrimaryComponent.tsx` — 외부 wrapper에서 border 속성 destructure 제거
- [x] `ButtonPrimaryComponent.tsx` — `border: "none"` shorthand 제거, 개별 longhand 속성으로 변경
- [x] `isButtonComponent` 조건에 `"v2-button-primary"` 추가

### 4-1단계: 키보드 단축키 충돌 수정

- [x] `ScreenDesigner.tsx` 글로벌 keydown 핸들러에 입력 필드 감지 가드 추가
- [x] `browserShortcuts` 배열에서 `Ctrl+V` 제거
- [x] 입력 필드(input/textarea/select/contentEditable) 포커스 시 Ctrl+A/C/V/Z 기본 동작 허용
- [x] SVG 붙여넣기 textarea에 `onPaste`/`onKeyDown` stopPropagation 핸들러 추가

### 5단계: 검증

- [x] 텍스트 모드: 기존 동작 변화 없음 확인 (하위 호환성)
- [x] `displayMode` 없는 기존 버튼: 텍스트 모드로 정상 동작
- [x] 아이콘 모드 선택 → 추천 아이콘 6개 그리드 표시
- [x] 아이콘 선택 → 캔버스(오른쪽 프리뷰) 및 실제 화면에서 아이콘 렌더링 확인
- [x] 아이콘 크기 비율 프리셋 변경 → 버튼 높이 대비 비율 반영 확인
- [x] 텍스트 위치 4방향(왼/오른/위/아래) 변경 → 레이아웃 방향 반영 확인
- [x] 버튼 테두리 설정 → 내부 버튼에만 적용, 외부 wrapper에 이중 적용 없음 확인
- [x] 버튼 액션 변경 → 추천 아이콘 목록 갱신 확인
- [x] lucide 커스텀 아이콘 추가 → 모든 액션에서 노출 확인
- [x] SVG 커스텀 아이콘 붙여넣기 → 미리보기 → 추가 → 모든 액션에서 노출 확인
- [x] SVG에 악성 코드 삽입 시도 → DOMPurify 정화 후 안전 렌더링 확인
- [x] 커스텀 아이콘 삭제 → 목록에서 제거 확인
- [x] deprecated 액션에서 안내 문구 + 커스텀 아이콘 추가 가능 확인
- [x] 아이콘+텍스트 모드: 아이콘 + 텍스트 나란히 렌더링 확인
- [x] 아이콘+텍스트 간격 조절: 슬라이더/직접 입력으로 간격 변경 → 실시간 반영 확인
- [x] 아이콘 색상 미설정 → textColor와 동일한 색상 확인
- [x] 아이콘 색상 설정 → 아이콘만 해당 색상, 텍스트는 textColor 유지 확인
- [x] 외부 SVG (고유 색상) → icon.color 설정해도 SVG 원본 색상 유지 확인
- [x] "텍스트 색상과 동일" 버튼 → icon.color 해제되고 textColor 상속 복원 확인
- [x] 레이아웃 안내 문구: 아이콘 모드에서만 표시, 다른 모드에서 숨김 확인
- [x] 입력 필드에서 Ctrl+A/C/V/Z 단축키 정상 동작 확인
- [x] 아이콘 모드 전환 시 디폴트 아이콘 자동 선택 → 캔버스에 즉시 반영 확인
- [x] 커스텀 아이콘 삭제 시 디폴트 아이콘으로 복귀 → 아이콘 모드 유지 확인
- [x] deprecated 액션에서 디폴트 폴백 아이콘(SquareMousePointer) 표시 확인

### 6단계: 동적 아이콘 로딩 (뷰어 렌더링 누락 수정)

- [x] `button-icon-map.tsx`에 `icons as allLucideIcons` import 추가
- [x] `getLucideIcon()` — `iconMap` miss 시 `allLucideIcons` fallback 조회 + 캐싱
- [x] `allLucideIcons`를 `button-icon-map.tsx`에서 re-export (import 중앙화)
- [x] `ButtonConfigPanel.tsx` — `lucide-react` 직접 import 제거, `button-icon-map`에서 import로 통합
- [x] 화면 관리에서 선택한 커스텀 lucide 아이콘이 실제 화면(뷰어)에서도 렌더링됨 확인

### 7단계: 정리

- [x] TypeScript 컴파일 에러 없음 확인
- [x] 불필요한 import 없음 확인
- [x] 문서 3개 최신화 (동적 로딩 반영)
- [x] 이 체크리스트 완료 표시 업데이트

### 8단계: 커스텀 아이콘 전역 관리 (미구현)

- [ ] `custom_icon_registry` 테이블 마이그레이션 SQL 작성 및 실행 (개발섭 + 본섭)
- [ ] 백엔드 API 구현 (GET/POST/DELETE `/api/custom-icons`)
- [ ] 프론트엔드 API 클라이언트 함수 추가 (`lib/api/`)
- [ ] `ButtonConfigPanel` — 커스텀 아이콘 조회/추가/삭제를 전역 API로 변경
- [ ] 기존 `componentConfig.customIcons` 하위 호환 병합 처리
- [ ] 검증: 화면 A에서 추가한 커스텀 아이콘이 화면 B에서도 보이는지 확인

---

## 변경 이력

| 날짜 | 내용 |
|------|------|
| 2026-03-04 | 계획서, 맥락노트, 체크리스트 작성 완료 |
| 2026-03-04 | 외부 SVG 붙여넣기 기능 추가 (3개 문서 모두 반영) |
| 2026-03-04 | 아이콘+텍스트 모드, 레이아웃 안내 추가 |
| 2026-03-04 | 설정 패널 내 미리보기 제거 (오른쪽 캔버스 프리뷰로 대체) |
| 2026-03-04 | 아이콘 색상 설정 추가 (icon.color, 기본값 textColor 상속) |
| 2026-03-04 | 3개 문서 교차 검토 — 개요 누락 보완, 시각 예시 문구 통일, 렌더 함수 px 대응, 용어 명확화 |
| 2026-03-04 | 구현 완료 — 1~4단계 코드 작성, 6단계 린트/타입 검증 통과 |
| 2026-03-04 | 아이콘-텍스트 간격 설정 추가 (iconGap, 슬라이더+직접 입력) |
| 2026-03-04 | noIconAction에서 커스텀 아이콘 추가 허용 + 안내 문구 변경 |
| 2026-03-04 | ScreenDesigner 키보드 단축키 수정 — 입력 필드에서 텍스트 편집 단축키 허용 |
| 2026-03-04 | SVG 붙여넣기 textarea에 onPaste/onKeyDown 핸들러 추가 |
| 2026-03-04 | SVG 커스텀 아이콘 이름 중복 방지 (자동 넘버링) |
| 2026-03-04 | 디폴트 아이콘 자동 부여 — 모드 전환 시 자동 선택, 커스텀 삭제 시 디폴트 복귀 |
| 2026-03-04 | `getDefaultIconForAction()` 유틸 + `SquareMousePointer` 폴백 아이콘 추가 |
| 2026-03-04 | 3개 문서 변경사항 동기화 및 코드 정리 |
| 2026-03-04 | 아이콘 크기: 절대 px → 버튼 높이 대비 비율(%) 4단계 프리셋으로 변경, px 직접 입력 제거 |
| 2026-03-04 | 텍스트 위치 4방향 설정 추가 (왼쪽/오른쪽/위쪽/아래쪽) |
| 2026-03-04 | 버튼 테두리 이중 적용 수정 — position wrapper에서 border strip, border shorthand 제거 |
| 2026-03-04 | 프리셋 라벨 한글화 (작게/보통/크게/매우 크게), 라벨 "아이콘 크기 비율"로 변경 |
| 2026-03-13 | 동적 아이콘 로딩 — `getLucideIcon()` fallback으로 `allLucideIcons` 조회+캐싱, import 중앙화 |
| 2026-03-13 | 문서 3개 최신화 (계획서 설계 원칙, 맥락노트 결정사항 #18, 체크리스트 6-7단계) |
| 2026-03-13 | 커스텀 아이콘 전역 관리 계획 추가 (8단계, 미구현) — DB 테이블 + API + 프론트 변경 예정 |
