Phase 8: SSOT 리팩토링 + HotkeyRecordModal + Dashboard 재작성
- d3roPalette 11개 토큰 추가 (sidebar, chassis, inactive 등) - DS 컴포넌트 6개 + 페이지 5개 매직넘버 → 팔레트 참조 (0개 잔여) - HotkeyRecordModal 신규: 커스텀 핫키 녹화 모달 - SettingsModal 재작성: 음성 모드 3개(받아쓰기/Agent/원터치) + 핫키 변경 - DashboardPage 재작성: Hero + 통계 4카드 + CRT 서비스 상태 + 히스토리 날짜 그룹핑 - recording-tip 색상 수정: #1F5DF2(파란) → #f25b29(앰버) - 설계 문서: phase-8.md, speakly-settings-ui.md
This commit is contained in:
parent
f41fc277e3
commit
28371a9d1a
19 changed files with 1879 additions and 403 deletions
213
docs/phases/phase-8.md
Normal file
213
docs/phases/phase-8.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# Phase 8: 핵심 기능 보강 + UI 디자인 근본 재설계
|
||||
|
||||
## 목표
|
||||
1. **핫키 변경 UI 구현** (HotkeyRecordModal) — 앱 테스트를 위한 차단 해제
|
||||
2. **Settings에 음성 모드 토글 3개 추가** (받아쓰기/Agent/원터치)
|
||||
3. **d3roPalette SSOT 확장 및 매직넘버 ~40곳 제거**
|
||||
4. **DashboardPage 기능 중심 재작성** (통계+히스토리+상태)
|
||||
5. **HistoryPage 날짜 그룹핑**
|
||||
6. **recording-tip 색상 버그 수정** (파란색 `#1F5DF2` → 앰버 `#f25b29`)
|
||||
|
||||
## 전제 조건
|
||||
Phase 7.5 완료 (SoundEffect, AutoLaunch, HotkeyService, VoiceModeService 모두 동작)
|
||||
|
||||
---
|
||||
|
||||
## 태스크
|
||||
|
||||
### 8.1 HotkeyRecordModal 구현
|
||||
- **파일**: `src/renderer/components/HotkeyRecordModal.tsx`
|
||||
- Speakly HotkeyRecordModal 패턴 차용:
|
||||
1. Modal 열림 → `document.addEventListener('keydown')` 리스너 등록
|
||||
2. 키 조합 감지 → `HotkeyBinding` 형태로 Chip/태그 표시
|
||||
3. 유효성 검증: 시스템 예약키 블랙리스트 (Ctrl+C, Ctrl+V, Alt+F4, Ctrl+Alt+Del 등)
|
||||
4. 중복 핫키 충돌 감지 → 경고 메시지 표시
|
||||
5. "저장" 클릭 → IPC `hotkey:setDictationShortcut` / `hotkey:setHandsFreeShortcut` 호출
|
||||
6. "취소" 또는 ESC → 모달 닫기, 변경 없음
|
||||
- 키 표시: platform-specific 라벨 (`Ctrl` → Windows, 키코드 → 표시 문자열 매핑)
|
||||
- HotkeyBinding 구조:
|
||||
```typescript
|
||||
interface HotkeyBinding {
|
||||
keyCode: number;
|
||||
ctrl: boolean;
|
||||
alt: boolean;
|
||||
shift: boolean;
|
||||
meta: boolean;
|
||||
displayLabel: string; // 예: "Right Alt", "Ctrl+Shift+F5"
|
||||
}
|
||||
```
|
||||
- **IPC 채널**: 기존 `hotkey:setDictationShortcut`, `hotkey:setHandsFreeShortcut`, `hotkey:setCommandShortcut` 활용
|
||||
- **시스템 예약키 블랙리스트** (`src/shared/constants.ts`에 추가):
|
||||
```typescript
|
||||
export const RESERVED_HOTKEYS: Set<string> = new Set([
|
||||
'Ctrl+C', 'Ctrl+V', 'Ctrl+X', 'Ctrl+Z', 'Ctrl+A', 'Ctrl+S',
|
||||
'Alt+F4', 'Alt+Tab', 'Ctrl+Alt+Delete', 'Win+L', 'Win+D',
|
||||
'Ctrl+Shift+Escape', 'PrintScreen',
|
||||
]);
|
||||
```
|
||||
|
||||
### 8.2 Settings 핫키 섹션 UI
|
||||
- **파일**: `src/renderer/components/SettingsModal.tsx`
|
||||
- General 탭에 "Shortcuts" 섹션 추가 (기존 토글 설정 아래):
|
||||
- 받아쓰기(Dictation) 핫키: 현재 바인딩 표시 + "변경" 버튼 → HotkeyRecordModal 열기
|
||||
- 핸즈프리(Hands-free) 핫키: 동일 패턴
|
||||
- Agent Mode 핫키: 더블프레스 기반이므로 "받아쓰기 키 2회 누름" 안내 텍스트만 표시
|
||||
- 각 핫키 옆에 현재 바인딩을 `Chip` 컴포넌트로 표시 (예: `Right Alt`)
|
||||
- 핫키 변경 성공 시 → `Chip` 갱신 + 토스트 알림
|
||||
- IPC 호출: `hotkey:getDictationShortcut`, `hotkey:getHandsFreeShortcut`로 초기값 로드
|
||||
|
||||
### 8.3 음성 모드 토글 3개 (Settings 연동)
|
||||
- **파일**: `src/renderer/components/SettingsModal.tsx` (General 탭)
|
||||
- Speakly Settings의 음성 모드 섹션 패턴:
|
||||
- **Dictation Mode**: `Switch` 토글 (기본 ON) + 핫키 Chip + "Hold-to-talk" 설명
|
||||
- **Agent Mode**: `Switch` 토글 (기본 OFF) + "Dictation 키 더블프레스" 설명
|
||||
- Dictation이 OFF이면 Agent도 비활성 (의존 관계 표시)
|
||||
- **Hands-free (One-touch)**: `Switch` 토글 (기본 OFF) + 핫키 Chip + "Toggle on/off" 설명
|
||||
- **IPC / ConfigService 연동**:
|
||||
- `config:set({ key: 'dictationEnabled', value: boolean })`
|
||||
- `config:set({ key: 'agentModeEnabled', value: boolean })`
|
||||
- `config:set({ key: 'handsFreeEnabled', value: boolean })`
|
||||
- AppConfig에 3개 필드 추가 (`src/shared/types.ts`)
|
||||
- **HotkeyService 연동**: 모드가 비활성이면 해당 핫키 이벤트 무시
|
||||
|
||||
### 8.4 d3roPalette SSOT 확장
|
||||
- **파일**: `src/renderer/theme.ts`
|
||||
- 현재 `d3roPalette`에 누락된 시맨틱 토큰 추가:
|
||||
```typescript
|
||||
export const d3roPalette = {
|
||||
// ...기존 유지...
|
||||
interactive: {
|
||||
/** 비활성 아이콘/라벨 (현재 '#77797c' 매직넘버로 사용 중) */
|
||||
muted: '#77797c',
|
||||
/** 호버 시 앰버로 전환할 때 사용 */
|
||||
hoverAccent: '#f25b29',
|
||||
/** 호버 시 위험 색상 */
|
||||
hoverDanger: '#ef4444',
|
||||
},
|
||||
metadata: {
|
||||
/** 보조 정보 텍스트 (현재 '#5c2615' 매직넘버) */
|
||||
dim: '#5c2615',
|
||||
},
|
||||
sidebar: {
|
||||
bg: '#1e1f21',
|
||||
activeBtn: '#242528',
|
||||
activeBtnPressed: '#1a1a1c',
|
||||
},
|
||||
shadow: {
|
||||
/** 물리 버튼 돌출 */
|
||||
buttonRaised: '0 2px 4px rgba(0,0,0,0.3), inset 0 1px 1px rgba(255,255,255,0.06)',
|
||||
/** 물리 버튼 눌림 */
|
||||
buttonPressed: 'inset 0 2px 4px rgba(0,0,0,0.6)',
|
||||
/** 인셋 패널 */
|
||||
inset: 'inset 0 2px 6px rgba(0,0,0,0.6), 0 1px 1px rgba(255,255,255,0.05)',
|
||||
},
|
||||
} as const;
|
||||
```
|
||||
- 목표: 모든 컴포넌트에서 `'#77797c'`, `'#5c2615'`, `'#1e1f21'`, `'#242528'` 등 매직넘버를 `d3roPalette.*` 참조로 교체
|
||||
|
||||
### 8.5 매직넘버 ~40곳 제거
|
||||
- **대상 파일** (grep 결과 기준):
|
||||
- `src/renderer/components/AppLayout.tsx` (~15곳)
|
||||
- `src/renderer/pages/HistoryPage.tsx` (~6곳)
|
||||
- `src/renderer/pages/DictionaryPage.tsx` (~5곳)
|
||||
- `src/renderer/pages/CommandsPage.tsx` (~5곳)
|
||||
- `src/renderer/components/StatusBar.tsx` (~5곳)
|
||||
- `src/renderer/components/ds/PhysicalButton.tsx` (~5곳)
|
||||
- `src/renderer/components/ds/MetalCard.tsx` (~4곳)
|
||||
- `src/renderer/components/ds/CrtDisplay.tsx` (~5곳)
|
||||
- `src/renderer/components/ds/Led.tsx` (~4곳)
|
||||
- **규칙**: `theme.ts`에서 `d3roPalette` / `d3roFontMono` export한 값만 사용
|
||||
- **예외**: DS 컴포넌트 내부의 WebGL 셰이더 uniform 값은 매직넘버 허용 (JS→GLSL 변환 복잡)
|
||||
- **검증**: `grep -rn '#[0-9a-fA-F]{6}' src/renderer/ --include='*.tsx'` 결과에서 `theme.ts` 외 0건
|
||||
|
||||
### 8.6 DashboardPage 기능 중심 재작성
|
||||
- **파일**: `src/renderer/pages/DashboardPage.tsx`
|
||||
- 현재 CRT+LED 인스트루먼트 패널 → **기능 중심 레이아웃**으로 교체:
|
||||
1. **상단: 통계 카드 4개** (MetalCard 사용)
|
||||
- 총 세션 수 / 오늘 세션 수 / 총 녹음 시간 / 연속 사용 일수
|
||||
- PhosphorText로 값 표시, 각 카드에 Led 인디케이터
|
||||
2. **중단: 최근 히스토리** (5~10건)
|
||||
- 날짜 그룹핑 (오늘/어제/이번 주)
|
||||
- 원본 텍스트 + 모드 Chip + 녹음 시간
|
||||
- 클릭 시 히스토리 상세 or 복사
|
||||
3. **하단: 시스템 상태 패널**
|
||||
- Ollama 연결 상태 (Led green/red)
|
||||
- STT 엔진 상태 (모델명 + ready/loading)
|
||||
- 현재 핫키 바인딩 표시
|
||||
- **IPC 호출**: `stats:getSummary`, `history:getAll({ page: 0, pageSize: 10 })`, `llm:getStatus`, `stt:getStatus`
|
||||
- CRT 디스플레이는 제거하지 않고 **축소하여 시스템 상태 영역에 배치** (옵션)
|
||||
|
||||
### 8.7 HistoryPage 날짜 그룹핑
|
||||
- **파일**: `src/renderer/pages/HistoryPage.tsx`
|
||||
- 히스토리 목록을 날짜별 섹션으로 그룹핑:
|
||||
- "오늘" / "어제" / "이번 주" / "이번 달" / "YYYY년 M월"
|
||||
- 각 섹션 헤더: PhosphorText variant="label" + 항목 수
|
||||
- 그룹핑 유틸 함수:
|
||||
```typescript
|
||||
function groupByDate(entries: HistoryEntry[]): Map<string, HistoryEntry[]> {
|
||||
// createdAt 기준으로 그룹핑
|
||||
// 오늘/어제/이번주/이번달/그외 구분
|
||||
}
|
||||
```
|
||||
- 날짜 섹션 사이 시각적 구분선 (Divider + 앰버 강조)
|
||||
- 스크롤 시 현재 날짜 섹션 sticky header (옵션)
|
||||
|
||||
### 8.8 recording-tip 색상 버그 수정
|
||||
- **파일**: `src/renderer/popups/recording-tip/style.css`
|
||||
- **문제**: 웨이브 바와 프로그레스 바 색상이 Speakly 기본값 `#1F5DF2` (파란색)으로 하드코딩됨
|
||||
- **수정**: D3RO 앰버 악센트 `#f25b29`로 변경
|
||||
```css
|
||||
.wave-bar {
|
||||
background: #f25b29; /* was: #1F5DF2 */
|
||||
}
|
||||
.progress-bar {
|
||||
background: #f25b29; /* was: #1F5DF2 */
|
||||
}
|
||||
```
|
||||
- **에러 아이콘**: 기존 `#D32F2F` → `#ef4444` (d3roPalette.tag.red)로 통일
|
||||
|
||||
### 8.9 AppConfig 타입 확장
|
||||
- **파일**: `src/shared/types.ts`
|
||||
- 음성 모드 토글 3개 필드 추가:
|
||||
```typescript
|
||||
export interface AppConfig {
|
||||
// ...기존 필드 유지...
|
||||
/** 받아쓰기 모드 활성화 (hold-to-talk) */
|
||||
dictationEnabled: boolean;
|
||||
/** Agent 모드 활성화 (더블프레스, dictation 의존) */
|
||||
agentModeEnabled: boolean;
|
||||
/** 핸즈프리 모드 활성화 (토글) */
|
||||
handsFreeEnabled: boolean;
|
||||
}
|
||||
```
|
||||
- ConfigService 기본값 설정: `dictationEnabled: true`, `agentModeEnabled: false`, `handsFreeEnabled: false`
|
||||
|
||||
### 8.10 DS 컴포넌트 d3roPalette 참조 전환
|
||||
- **대상 파일**:
|
||||
- `src/renderer/components/ds/Led.tsx`: 색상 맵을 `d3roPalette.accent.*`, `d3roPalette.tag.*`에서 가져오기
|
||||
- `src/renderer/components/ds/PhysicalButton.tsx`: `#242528`, `#1a1a1c`, `#f25b29`, `#77797c` → 팔레트 참조
|
||||
- `src/renderer/components/ds/MetalCard.tsx`: `#1b1c1e`, `#242427`, `#2a2a2d` → 팔레트 참조
|
||||
- `src/renderer/components/ds/CrtDisplay.tsx`: `#1a1a1c`, `#050605`, `#f25b29` → 팔레트 참조 (셰이더 uniform 제외)
|
||||
- DS 컴포넌트가 직접 hex 리터럴을 갖지 않고, 반드시 `d3roPalette` 또는 `theme.palette`에서 읽도록 변경
|
||||
- `import { d3roPalette } from '../../theme'` 패턴 통일
|
||||
|
||||
---
|
||||
|
||||
## Speakly RE 참조
|
||||
- **Settings.js**: General 탭에 음성 모드 토글 3개 (Dictation/Agent/Hands-free), 각 모드별 핫키 Chip, 마이크 테스트
|
||||
- **HotkeyRecordModal.js**: keydown 리스너 → 조합키 Chip 표시, 시스템 예약키 블랙리스트, platform-specific 키 라벨
|
||||
- **CustomInstructionPage.js**: 커스텀 명령어별 핫키 바인딩 UI (재활용 패턴)
|
||||
- **Dashboard.js**: 통계 카드 4개, 최근 히스토리 날짜 그룹핑 (오늘/어제/이전)
|
||||
- **HotkeyConfig.js**: VK 코드 → 표시 문자열 매핑 테이블, 시스템 예약키 감지
|
||||
|
||||
## 완료 조건
|
||||
- [ ] Settings에서 핫키 변경 가능 (HotkeyRecordModal 작동)
|
||||
- [ ] 변경된 핫키로 녹음 → 전사 → 삽입 사이클 테스트 가능
|
||||
- [ ] Settings에 음성 모드 토글 3개 표시 + 설정 저장/로드
|
||||
- [ ] Dictation OFF → Agent 자동 비활성 연동 작동
|
||||
- [ ] DashboardPage에 통계 + 최근 히스토리 + 시스템 상태 표시
|
||||
- [ ] HistoryPage 날짜 그룹핑 (오늘/어제/이번 주 등)
|
||||
- [ ] recording-tip 웨이브 바/프로그레스 바 색상이 앰버(`#f25b29`)
|
||||
- [ ] `grep '#[0-9a-fA-F]{6}' src/renderer/**/*.tsx` 결과에서 `theme.ts` 외 매직넘버 0건
|
||||
- [ ] `npm run typecheck` 통과
|
||||
- [ ] 모든 DS 컴포넌트가 `d3roPalette` 참조 (hex 리터럴 직접 사용 없음)
|
||||
Loading…
Add table
Add a link
Reference in a new issue