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:
Yun Chan 2026-04-05 09:54:55 +09:00
parent f41fc277e3
commit 28371a9d1a
19 changed files with 1879 additions and 403 deletions

View file

@ -7,10 +7,10 @@ import SearchIcon from '@mui/icons-material/Search'
import DeleteIcon from '@mui/icons-material/Delete'
import ContentCopyIcon from '@mui/icons-material/ContentCopy'
import { MetalCard, PhosphorText, Led } from '../components/ds'
import { d3roPalette, d3roFontMono } from '../theme'
import type { HistoryEntry, HistoryPage as HistoryPageData } from '@shared/types'
const PAGE_SIZE = 20
const MONO = 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace'
function formatDate(ts: number): string {
return new Date(ts).toLocaleString('ko-KR', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })
@ -40,7 +40,7 @@ export function HistoryPage(): React.ReactElement {
return (
<Box sx={{ maxWidth: 900, mx: 'auto', p: 4 }}>
<PhosphorText variant="label" sx={{ mb: 2, display: 'block', color: '#77797c' }}>
<PhosphorText variant="label" sx={{ mb: 2, display: 'block', color: d3roPalette.text.inactive }}>
TRANSCRIPTION LOG {data?.total ?? 0} ENTRIES
</PhosphorText>
@ -51,11 +51,11 @@ export function HistoryPage(): React.ReactElement {
fullWidth
sx={{
mb: 3,
'& .MuiInputBase-input': { fontFamily: MONO, fontSize: '12px', letterSpacing: '0.5px' },
'& .MuiInputBase-input': { fontFamily: d3roFontMono, fontSize: '12px', letterSpacing: '0.5px' },
}}
slotProps={{
input: {
startAdornment: <InputAdornment position="start"><SearchIcon sx={{ color: '#77797c', fontSize: 18 }} /></InputAdornment>,
startAdornment: <InputAdornment position="start"><SearchIcon sx={{ color: d3roPalette.text.inactive, fontSize: 18 }} /></InputAdornment>,
},
}}
/>
@ -76,13 +76,13 @@ export function HistoryPage(): React.ReactElement {
<Led color={entry.status === 'completed' ? 'green' : 'red'} size={6} />
<Box sx={{ flex: 1, minWidth: 0 }}>
<Box sx={{
fontSize: '13px', color: '#fff', lineHeight: 1.5,
fontSize: '13px', color: d3roPalette.text.primary, lineHeight: 1.5,
overflow: 'hidden', textOverflow: 'ellipsis',
display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
}}>
{entry.polishedText || entry.originalText}
</Box>
<Box sx={{ display: 'flex', gap: 2, mt: 1, fontFamily: MONO, fontSize: '10px', color: '#5c2615', letterSpacing: '0.5px' }}>
<Box sx={{ display: 'flex', gap: 2, mt: 1, fontFamily: d3roFontMono, fontSize: '10px', color: d3roPalette.text.dimLabel, letterSpacing: '0.5px' }}>
<span>{formatDate(entry.createdAt)}</span>
<span>{formatDuration(entry.duration)}</span>
{entry.detectedLanguage && <span>{entry.detectedLanguage.toUpperCase()}</span>}
@ -91,11 +91,11 @@ export function HistoryPage(): React.ReactElement {
</Box>
<Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>
<IconButton size="small" onClick={() => navigator.clipboard.writeText(entry.polishedText || entry.originalText)}
sx={{ color: '#77797c', '&:hover': { color: '#f25b29' } }}>
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}>
<ContentCopyIcon sx={{ fontSize: 16 }} />
</IconButton>
<IconButton size="small" onClick={() => { window.electronAPI.history.delete({ id: entry.id }); loadData() }}
sx={{ color: '#77797c', '&:hover': { color: '#ef4444' } }}>
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.tag.red } }}>
<DeleteIcon sx={{ fontSize: 16 }} />
</IconButton>
</Box>