Phase 7~8 구현: 테스트 + 빌드 + CI/CD + SoundEffect + AutoLaunch + UI 리디자인
- vitest 41개 단위 테스트 (HistoryService, DictionaryService, CustomInstructionService, VoiceModeService, D3ROError) - electron-builder.yml (NSIS, asarUnpack, extraResources) - .gitlab-ci.yml (lint, typecheck, test, build, release) - SoundEffectService: WAV 프리로드 + PowerShell 재생 + VoiceMode 연동 - AutoLaunchService: app.setLoginItemSettings + ConfigService 동기화 - TextInsertService: 간이 삽입 검증 (EditMonitor 경량) - 번들링 인프라: SoX 다운로드 스크립트, PyInstaller 빌드, 경로 해상도 유틸 - AudioCaptureService/LocalSTTService: 번들 경로 자동 감지 - 08-design-system.md 기반 MUI 테마 (다크+라이트+auto 테마 시스템) - 전체 UI 컴포넌트 리디자인: AppLayout, Dashboard, StatusBar, History, Dictionary, Commands, Settings - 효과음 WAV 생성: recording-start, recording-stop, error - EPIPE 에러 핸들링 추가
This commit is contained in:
parent
ed5541f769
commit
3f4d0c5828
40 changed files with 6034 additions and 580 deletions
|
|
@ -1,26 +1,40 @@
|
|||
// src/renderer/components/StatusBar.tsx
|
||||
// 하단 상태 표시: Ollama 연결 상태
|
||||
// 하단 상태 표시: LED 인디케이터 + 태그 시스템. 08-design-system.md SSOT.
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Box, Chip } from '@mui/material'
|
||||
import CircleIcon from '@mui/icons-material/Circle'
|
||||
import { Box, Typography, Chip } from '@mui/material'
|
||||
import { d3roPalette, d3roFontMono } from '../theme'
|
||||
import type { LLMStatus } from '@shared/types'
|
||||
|
||||
function Led({ active, color }: { active: boolean; color?: string }): React.ReactElement {
|
||||
const c = color ?? d3roPalette.tag.green
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: '50%',
|
||||
bgcolor: active ? c : d3roPalette.text.disabled,
|
||||
boxShadow: active ? `0 0 4px ${c}, 0 0 8px ${c}40` : 'none',
|
||||
flexShrink: 0,
|
||||
transition: 'background 0.3s ease, box-shadow 0.3s ease',
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function StatusBar(): React.ReactElement {
|
||||
const [llmStatus, setLlmStatus] = useState<LLMStatus | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// 초기 상태 조회
|
||||
window.electronAPI.llm.getStatus().then((result) => {
|
||||
if (result.success) setLlmStatus(result.data)
|
||||
})
|
||||
|
||||
// 상태 변경 구독
|
||||
const unsub = window.electronAPI.llm.onStatusChanged((event) => {
|
||||
setLlmStatus(event.status)
|
||||
})
|
||||
|
||||
// 5초마다 폴링 (main에서 이벤트를 보내지 않을 수 있으므로)
|
||||
const interval = setInterval(() => {
|
||||
window.electronAPI.llm.getStatus().then((result) => {
|
||||
if (result.success) setLlmStatus(result.data)
|
||||
|
|
@ -40,30 +54,53 @@ export function StatusBar(): React.ReactElement {
|
|||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
gap: 2,
|
||||
px: 2,
|
||||
py: 0.5,
|
||||
borderTop: 1,
|
||||
borderColor: 'divider',
|
||||
bgcolor: 'background.paper'
|
||||
py: 0.75,
|
||||
borderTop: `1px solid ${d3roPalette.border.subtle}`,
|
||||
bgcolor: 'background.paper',
|
||||
minHeight: 32,
|
||||
}}
|
||||
>
|
||||
<Chip
|
||||
icon={<CircleIcon sx={{ fontSize: 8 }} />}
|
||||
label={connected ? 'Ollama Connected' : 'Ollama Offline'}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color={connected ? 'success' : 'default'}
|
||||
sx={{ height: 22, '& .MuiChip-label': { fontSize: 11 } }}
|
||||
/>
|
||||
{/* Ollama 상태 */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
|
||||
<Led active={connected} color={connected ? d3roPalette.tag.green : d3roPalette.tag.red} />
|
||||
<Typography
|
||||
sx={{
|
||||
fontFamily: d3roFontMono,
|
||||
fontSize: '11px',
|
||||
color: d3roPalette.text.secondary,
|
||||
letterSpacing: '0.02em',
|
||||
}}
|
||||
>
|
||||
{connected ? 'OLLAMA' : 'OFFLINE'}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* 활성 모델 태그 */}
|
||||
{llmStatus?.activeModel && (
|
||||
<Chip
|
||||
label={llmStatus.activeModel}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ height: 22, '& .MuiChip-label': { fontSize: 11 } }}
|
||||
color="primary"
|
||||
sx={{ height: 20, '& .MuiChip-label': { px: 1, fontSize: '10px' } }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 스페이서 */}
|
||||
<Box sx={{ flex: 1 }} />
|
||||
|
||||
{/* 핫키 힌트 */}
|
||||
<Typography
|
||||
sx={{
|
||||
fontFamily: d3roFontMono,
|
||||
fontSize: '10px',
|
||||
color: d3roPalette.text.label,
|
||||
letterSpacing: '0.05em',
|
||||
}}
|
||||
>
|
||||
RIGHT ALT — DICTATE
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue