16 KiB
[계획서] 버튼 아이콘화 - 화면 디자이너 버튼 표시 모드 확장
개요
화면 디자이너에서 버튼을 텍스트 모드(현행), 아이콘 모드, 아이콘+텍스트 모드 중 선택할 수 있도록 확장한다. 아이콘 모드 선택 시 버튼 액션에 맞는 아이콘 후보군이 제시되고, 관리자가 원하는 아이콘을 선택한다. 아이콘 크기 비율(버튼 높이 대비 4단계 프리셋), 아이콘 색상, 텍스트 위치(4방향), 아이콘-텍스트 간격 설정을 제공한다. 관리자가 lucide 검색 또는 외부 SVG 붙여넣기로 커스텀 아이콘을 추가/삭제할 수 있다.
현재 동작
- 버튼은 항상 텍스트 모드로만 표시됨
ButtonConfigPanel.tsx에서 "버튼 텍스트" 입력 → 실제 화면에서 해당 텍스트가 버튼에 표시- 아이콘 표시 기능 없음
현재 코드 위치
| 구분 | 파일 | 설명 |
|---|---|---|
| 설정 패널 | frontend/components/screen/config-panels/ButtonConfigPanel.tsx |
버튼 텍스트, 액션 설정 (784~854행) |
| 뷰어 렌더링 | frontend/components/screen/InteractiveScreenViewerDynamic.tsx |
실제 버튼 렌더링 (961~983행) |
| 뷰어 렌더링 | frontend/components/screen/InteractiveScreenViewer.tsx |
실제 버튼 렌더링 (2041~2059행) |
| 위젯 렌더링 | frontend/components/screen/widgets/types/ButtonWidget.tsx |
위젯 기반 버튼 렌더링 (67~86행) |
| 최적화 컴포넌트 | frontend/components/screen/OptimizedButtonComponent.tsx |
최적화된 버튼 컴포넌트 (643~674행) |
변경 후 동작
1. 표시 모드 선택 (라디오 그룹)
ButtonConfigPanel에 "버튼 텍스트" 입력 위에 표시 모드 선택 UI 추가:
- 텍스트 모드 (기본값, 현행 유지): 버튼에 텍스트만 표시
- 아이콘 모드: 버튼에 아이콘만 표시
- 아이콘+텍스트 모드: 버튼에 아이콘과 텍스트를 함께 표시
[ 텍스트 | 아이콘 | 아이콘+텍스트 ] ← 라디오 그룹 (토글 형태)
2. 텍스트 모드 선택 시
- 현재와 동일하게 "버튼 텍스트" 입력 필드 표시
- 변경 사항 없음
2-1. 아이콘+텍스트 모드 선택 시
- 아이콘 선택 UI (3장과 동일) + 버튼 텍스트 입력 필드 둘 다 표시
- 렌더링: 텍스트 위치에 따라 아이콘과 텍스트 배치 방향이 달라짐
- 텍스트 위치 4방향: 오른쪽(기본), 왼쪽, 위쪽, 아래쪽
- 예시:
[ ✓ 저장 ](오른쪽),[ 저장 ✓ ](왼쪽), 세로 배치 (위쪽/아래쪽) - 아이콘과 텍스트 사이 간격: 기본 6px, 관리자가 0~무제한 조절 가능 (슬라이더 0~32px + 직접 입력)
3. 아이콘 모드 선택 시
3-1. 버튼 액션별 추천 아이콘 목록
버튼 액션(action.type)에 따라 해당 액션에 어울리는 아이콘 후보군을 그리드로 표시:
| 버튼 액션 | 값 | 추천 아이콘 (lucide-react) |
|---|---|---|
| 저장 | save |
Check, Save, CheckCircle, CircleCheck, FileCheck, ShieldCheck |
| 삭제 | delete |
Trash2, Trash, XCircle, X, Eraser, CircleX |
| 편집 | edit |
Pencil, PenLine, Edit, SquarePen, FilePen, PenTool |
| 페이지 이동 | navigate |
ArrowRight, ExternalLink, MoveRight, Navigation, CornerUpRight, Link |
| 모달 열기 | modal |
Maximize2, PanelTop, AppWindow, LayoutGrid, Layers, FolderOpen |
| 데이터 전달 | transferData |
SendHorizontal, ArrowRightLeft, Repeat, PackageCheck, Upload, Share2 |
| 엑셀 다운로드 | excel_download |
Download, FileDown, FileSpreadsheet, Sheet, Table, FileOutput |
| 엑셀 업로드 | excel_upload |
Upload, FileUp, FileSpreadsheet, Sheet, ImportIcon, FileInput |
| 즉시 저장 | quickInsert |
Zap, Plus, PlusCircle, SquarePlus, FilePlus, BadgePlus |
| 제어 흐름 | control |
Settings, SlidersHorizontal, ToggleLeft, Workflow, GitBranch, Cog |
| 바코드 스캔 | barcode_scan |
ScanLine, QrCode, Camera, Scan, ScanBarcode, Focus |
| 운행알림 및 종료 | operation_control |
Truck, Car, MapPin, Navigation2, Route, Bell |
| 이벤트 발송 | event |
Send, Bell, Radio, Megaphone, Podcast, BellRing |
| 복사 | copy |
Copy, ClipboardCopy, Files, CopyPlus, Duplicate, ClipboardList |
적절한 아이콘이 없는 액션 (숨김 처리된 deprecated 액션들):
| 버튼 액션 | 값 | 안내 문구 |
|---|---|---|
| 연관 데이터 버튼 모달 열기 | openRelatedModal |
안내 문구 표시 + 커스텀 아이콘 추가 가능 |
| (deprecated) 데이터 전달 + 모달 | openModalWithData |
안내 문구 표시 + 커스텀 아이콘 추가 가능 |
| 테이블 이력 보기 | view_table_history |
안내 문구 표시 + 커스텀 아이콘 추가 가능 |
| 코드 병합 | code_merge |
안내 문구 표시 + 커스텀 아이콘 추가 가능 |
| 공차등록 | empty_vehicle |
안내 문구 표시 + 커스텀 아이콘 추가 가능 |
안내 문구: "적절한 추천 아이콘이 없습니다. 텍스트 모드를 사용하거나 아래에서 아이콘을 직접 추가하세요." 안내 문구 아래에 커스텀 아이콘 목록 + lucide 검색/SVG 붙여넣기 버튼이 표시됨
3-2. 아이콘 선택 UI
- 액션별 추천 아이콘을 4~6열 그리드로 표시
- 각 아이콘은 32x32 크기, 호버 시 하이라이트, 선택 시 ring 표시
- 아이콘 아래에 이름 표시 (
text-[10px]) - 관리자가 추가한 커스텀 아이콘이 있으면 "커스텀 아이콘" 구분선 아래 함께 표시
3-3. 아이콘 크기 비율 설정
버튼 높이 대비 비율로 아이콘 크기를 설정 (정사각형 유지):
프리셋 (ToggleGroup, 4단계):
| 이름 | 버튼 높이 대비 | 설명 |
|---|---|---|
| 작게 | 40% | 컴팩트한 아이콘 |
| 보통 | 55% | 기본값, 대부분의 버튼에 적합 |
| 크게 | 70% | 존재감 있는 크기 |
| 매우 크게 | 85% | 아이콘 강조, 버튼에 꽉 차는 느낌 |
- px 직접 입력은 제거 (비율 기반이므로 버튼 크기 변경 시 아이콘도 자동 비례)
- 저장:
icon.size에 프리셋 문자열("보통") 저장 - 렌더링:
height: N%+aspect-ratio: 1/1로 정사각형 유지
3-4. 아이콘 색상 설정
아이콘 크기 아래에 아이콘 전용 색상 설정:
- 컬러 피커: 기존 버튼 색상 설정과 동일한 UI 사용
- 기본값: 미설정 (=
textColor상속, 기존 동작과 동일) - 설정 시: lucide 아이콘은 지정한 색상으로 덮어쓰기
- 외부 SVG: 고유 색상이 하드코딩된 SVG는 이 설정의 영향을 받지 않음 (원본 유지)
- 초기화 버튼: "텍스트 색상과 동일" 버튼으로 별도 색상 해제 가능
| 상황 | iconColor 설정 | 결과 |
|---|---|---|
| lucide 아이콘, iconColor 미설정 | 없음 | textColor 상속 (기존 동작) |
| lucide 아이콘, iconColor 설정 | #22c55e |
초록색 아이콘 |
| 외부 SVG (고유 색상), iconColor 설정 | #22c55e |
SVG 원본 색상 유지 (무시) |
| 외부 SVG (currentColor), iconColor 설정 | #22c55e |
초록색 아이콘 |
3-5. 텍스트 위치 설정 (아이콘+텍스트 모드 전용)
아이콘 대비 텍스트의 배치 방향을 4방향으로 설정:
| 위치 | 값 | 레이아웃 | 설명 |
|---|---|---|---|
| 왼쪽 | left |
텍스트 ← 아이콘 |
텍스트가 아이콘 왼쪽 (가로) |
| 오른쪽 | right |
아이콘 → 텍스트 |
기본값, 아이콘 뒤에 텍스트 (가로) |
| 위쪽 | top |
텍스트 위, 아이콘 아래 | 세로 배치 |
| 아래쪽 | bottom |
아이콘 위, 텍스트 아래 | 세로 배치 |
- 기본값:
"right"(아이콘 오른쪽에 텍스트) - 저장:
componentConfig.iconTextPosition - 아이콘 모드에서는 이 옵션이 숨겨짐 (텍스트가 없으므로 불필요)
3-6. 아이콘-텍스트 간격 설정 (아이콘+텍스트 모드 전용)
아이콘+텍스트 모드에서 아이콘과 텍스트 사이 간격을 조절:
- 슬라이더: 0~32px 범위 시각적 조절
- 직접 입력: px 수치 직접 입력 (최솟값 0, 최댓값 제한 없음)
- 기본값: 6px
- 아이콘 모드에서는 이 옵션이 숨겨짐 (텍스트가 없으므로 불필요)
3-7. 아이콘 모드 레이아웃 안내
아이콘만 표시하면 텍스트보다 좁은 공간으로 충분하므로 안내 문구 표시:
ℹ 아이콘만 표시할 때는 버튼 영역의 가로 폭을 줄여 정사각형에 가깝게 만들면 더 깔끔합니다.
bg-blue-50 dark:bg-blue-950/20배경의 안내 박스- 아이콘 모드(
"icon")에서만 표시, 아이콘+텍스트 모드에서는 숨김
3-8. 디폴트 아이콘 자동 부여
아이콘/아이콘+텍스트 모드 전환 시 아이콘이 미선택 상태이면 디폴트 아이콘을 자동으로 부여한다.
| 상황 | 디폴트 아이콘 |
|---|---|
| 추천 아이콘이 있는 액션 (save, delete 등) | 해당 액션의 첫 번째 추천 아이콘 (예: save → Check) |
| 추천 아이콘이 없는 액션 (deprecated 등) | 범용 폴백 아이콘: SquareMousePointer |
커스텀 아이콘 삭제 시:
- 현재 선택된 커스텀 아이콘을 삭제하면 디폴트 아이콘으로 자동 복귀 (텍스트 모드로 빠지지 않음)
- 아이콘 모드를 유지한 채 디폴트 아이콘이 캔버스에 즉시 반영됨
3-9. 커스텀 아이콘 추가/삭제
방법 1: lucide 아이콘 검색으로 추가
- "아이콘 추가" 버튼 클릭 시 lucide 아이콘 전체 검색 가능한 모달/팝오버 표시
- 검색 입력 → 아이콘 이름으로 필터링 → 선택하면 커스텀 목록에 추가
방법 2: 외부 SVG 붙여넣기로 추가
- "SVG 붙여넣기" 버튼 클릭 시 텍스트 입력 영역(textarea) 표시
- 외부에서 복사한 SVG 코드를 붙여넣기 → 미리보기로 확인 → "추가" 버튼으로 등록
- SVG 유효성 검사:
<svg태그가 포함된 올바른 SVG인지 확인, 아니면 에러 메시지 - 추가 시 관리자가 아이콘 이름을 직접 입력 (목록에서 구분용)
- 저장 형태: SVG 문자열을
customSvgIcons배열에{ name, svg }객체로 저장
공통 규칙:
- 추가된 커스텀 아이콘(lucide/SVG 모두)은 모든 버튼 액션의 아이콘 후보에 공통으로 노출
- 커스텀 아이콘에 X 버튼으로 삭제 가능
데이터 구조
componentConfig 확장
interface ButtonComponentConfig {
text: string; // 기존: 버튼 텍스트
displayMode: "text" | "icon" | "icon-text"; // 신규: 표시 모드 (기본값: "text")
icon?: {
name: string; // lucide 아이콘 이름 또는 커스텀 SVG 아이콘 이름
type: "lucide" | "svg"; // 아이콘 출처 구분 (기본값: "lucide")
size: "작게" | "보통" | "크게" | "매우 크게"; // 버튼 높이 대비 비율 프리셋 (기본값: "보통")
color?: string; // 아이콘 색상 (미설정 시 textColor 상속)
};
iconGap?: number; // 아이콘-텍스트 간격 px (기본값: 6, 아이콘+텍스트 모드 전용)
iconTextPosition?: "right" | "left" | "top" | "bottom"; // 텍스트 위치 (기본값: "right", 아이콘+텍스트 모드 전용)
customIcons?: string[]; // 관리자가 추가한 lucide 커스텀 아이콘 이름 목록
customSvgIcons?: Array<{ // 관리자가 붙여넣기한 외부 SVG 아이콘 목록
name: string; // 관리자가 지정한 아이콘 이름
svg: string; // SVG 문자열 원본
}>;
action: {
type: string; // 기존: 버튼 액션 타입
// ...기존 action 속성들 유지
};
}
저장 예시
{
"text": "저장",
"displayMode": "icon",
"icon": {
"name": "Check",
"type": "lucide",
"size": "보통",
"color": "#22c55e"
},
"customIcons": ["Rocket", "Star"],
"customSvgIcons": [
{
"name": "회사로고",
"svg": "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'>...</svg>"
}
],
"action": {
"type": "save"
}
}
시각적 동작 예시
ButtonConfigPanel (디자이너 편집 모드)
표시 모드: [ 텍스트 | (아이콘) | 아이콘+텍스트 ] ← 아이콘 선택됨
아이콘 선택:
┌──────────────────────────────────┐
│ 추천 아이콘 (저장) │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ ✓ │ │ 💾 │ │ ✓○ │ │ ○✓ │ │
│ │Check│ │Save│ │Chk○│ │○Chk│ │
│ └────┘ └────┘ └────┘ └────┘ │
│ ┌────┐ ┌────┐ │
│ │📄✓│ │🛡✓│ │
│ │FChk│ │ShCk│ │
│ └────┘ └────┘ │
│ │
│ ── 커스텀 아이콘 ── │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │ 🚀 │ │ ⭐ │ │[로고]│ │
│ │Rckt │ │Star│ │회사 │ │
│ │ ✕ │ │ ✕│ │ ✕ │ │
│ └────┘ └────┘ └────┘ │
│ [+ lucide 검색] [+ SVG 붙여넣기]│
└──────────────────────────────────┘
아이콘 크기 비율: [ 작게 | (보통) | 크게 | 매우 크게 ]
텍스트 위치: [ 왼쪽 | (오른쪽) | 위쪽 | 아래쪽 ] ← 아이콘+텍스트 모드에서만 표시
아이콘-텍스트 간격: [━━━━━○━━] [6] px ← 아이콘+텍스트 모드에서만 표시
아이콘 색상: [■ #22c55e] [텍스트 색상과 동일]
ℹ 아이콘만 표시할 때는 버튼 영역의 가로 폭을 줄여 정사각형에 가깝게 만들면 더 깔끔합니다.
실제 화면 렌더링
| 모드 | 표시 |
|---|---|
| 텍스트 모드 | [ 저장 ] |
| 아이콘 모드 (보통, 55%) | [ ✓ ] |
| 아이콘 모드 (매우 크게, 85%) | [ ✓ ] |
| 아이콘+텍스트 (텍스트 오른쪽) | [ ✓ 저장 ] (간격 6px) |
| 아이콘+텍스트 (텍스트 왼쪽) | [ 저장 ✓ ] |
| 아이콘+텍스트 (텍스트 아래쪽) | 아이콘 위, 텍스트 아래 (세로) |
| 아이콘+텍스트 (색상 분리) | [ 초록✓ 검정저장 ] |
변경 대상
수정 파일
| 파일 | 변경 내용 |
|---|---|
ButtonConfigPanel.tsx |
표시 모드 3종 라디오, 아이콘 그리드, 크기, 색상, 간격 설정, 레이아웃 안내, 커스텀 아이콘 UI |
InteractiveScreenViewerDynamic.tsx |
displayMode 3종 분기 → 아이콘/아이콘+텍스트/텍스트 렌더링 |
InteractiveScreenViewer.tsx |
동일 분기 추가 |
ButtonWidget.tsx |
동일 분기 추가 |
OptimizedButtonComponent.tsx |
동일 분기 추가 |
ScreenDesigner.tsx |
입력 필드 포커스 시 키보드 단축키 기본 동작 허용 (Ctrl+A/C/V/Z) |
RealtimePreviewDynamic.tsx |
버튼 컴포넌트 position wrapper에서 border 속성 분리 (이중 테두리 방지) |
신규 파일
| 파일 | 내용 |
|---|---|
frontend/lib/button-icon-map.ts |
버튼 액션별 추천 아이콘 매핑 + 아이콘 동적 렌더링 유틸 |
설계 원칙
- 기본값은
"text"모드 → 기존 모든 버튼은 변경 없이 동작 displayMode가 없거나"text"이면 현행 텍스트 렌더링 유지- 아이콘/아이콘+텍스트 모드 전환 시 아이콘 미선택이면 디폴트 아이콘 자동 부여 (빈 상태 방지)
- 커스텀 아이콘 삭제 시 텍스트 모드로 빠지지 않고 디폴트 아이콘으로 자동 복귀
- 아이콘 모드에서도
text값은 유지 (접근성 aria-label로 활용) - 기본 아이콘은 lucide-react 사용 (프로젝트 일관성)
- 외부 SVG 붙여넣기도 지원 → 관리자가 회사 로고 등 자체 아이콘을 등록 가능
- lucide 커스텀 아이콘은
componentConfig.customIcons에, SVG 아이콘은componentConfig.customSvgIcons에 저장 - lucide 아이콘 렌더링: 아이콘 이름 → 컴포넌트 매핑, SVG 아이콘 렌더링:
dangerouslySetInnerHTML+ DOMPurify 정화