Phase 1+2 구현: Electron 뼈대 + STT/핫키/오케스트레이터
Phase 1: - 프로젝트 초기화 (TypeScript strict, electron-vite, ESLint, Prettier) - shared 타입 (ipc-channels 113채널, types, errors, constants) - 메인 프로세스 뼈대 (bootstrap, lifecycle, 단일 인스턴스) - LoggerService, ConfigService (electron-store ESM dynamic import) - React 19 + MUI 7 Dashboard, 시스템 트레이 Phase 2: - AudioCaptureService (node-record-lpcm16, PCM16 16kHz mono) - HotkeyService (uiohook-napi, 더블프레스, holdMode/toggleMode) - LocalSTTService (faster-whisper Python sidecar, 이중 조건 플러시) - VoiceModeService 오케스트레이터 (이중 상태머신, Action Queue) - Python sidecar (FastAPI: health/load/transcribe/shutdown) - IPC 핸들러 (voice, stt, hotkey) + Preload API 확장
This commit is contained in:
parent
e24bb8378c
commit
1d152d01a1
46 changed files with 10828 additions and 4 deletions
110
src/renderer/components/AppLayout.tsx
Normal file
110
src/renderer/components/AppLayout.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// src/renderer/components/AppLayout.tsx
|
||||
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Drawer,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Divider,
|
||||
Typography,
|
||||
Chip
|
||||
} from '@mui/material'
|
||||
import DashboardIcon from '@mui/icons-material/Dashboard'
|
||||
import HistoryIcon from '@mui/icons-material/History'
|
||||
import MenuBookIcon from '@mui/icons-material/MenuBook'
|
||||
import SettingsIcon from '@mui/icons-material/Settings'
|
||||
import { DashboardPage } from '../pages/DashboardPage'
|
||||
|
||||
type Route = 'dashboard' | 'history' | 'dictionary'
|
||||
|
||||
const DRAWER_WIDTH = 240
|
||||
|
||||
const NAV_ITEMS: Array<{ route: Route; label: string; icon: React.ReactElement }> = [
|
||||
{ route: 'dashboard', label: 'Dashboard', icon: <DashboardIcon /> },
|
||||
{ route: 'history', label: 'History', icon: <HistoryIcon /> },
|
||||
{ route: 'dictionary', label: 'Dictionary', icon: <MenuBookIcon /> }
|
||||
]
|
||||
|
||||
export function AppLayout(): React.ReactElement {
|
||||
const [currentRoute, setCurrentRoute] = useState<Route>('dashboard')
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', height: '100vh' }}>
|
||||
{/* Sidebar Drawer */}
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
width: DRAWER_WIDTH,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: DRAWER_WIDTH,
|
||||
boxSizing: 'border-box'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Header */}
|
||||
<Box sx={{ p: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<Typography variant="h6" noWrap sx={{ fontWeight: 700 }}>
|
||||
D3RO Voice
|
||||
</Typography>
|
||||
<Chip label="v1.0" size="small" variant="outlined" />
|
||||
</Box>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Navigation */}
|
||||
<List sx={{ flex: 1, pt: 1 }}>
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<ListItemButton
|
||||
key={item.route}
|
||||
selected={currentRoute === item.route}
|
||||
onClick={() => setCurrentRoute(item.route)}
|
||||
sx={{ my: 0.5 }}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 40 }}>{item.icon}</ListItemIcon>
|
||||
<ListItemText primary={item.label} />
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Bottom */}
|
||||
<List>
|
||||
<ListItemButton sx={{ my: 0.5 }}>
|
||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
||||
<SettingsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Settings" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Drawer>
|
||||
|
||||
{/* Content Area */}
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
p: 3,
|
||||
overflow: 'auto',
|
||||
bgcolor: 'background.default'
|
||||
}}
|
||||
>
|
||||
{currentRoute === 'dashboard' && <DashboardPage />}
|
||||
{currentRoute === 'history' && (
|
||||
<Typography variant="h5" color="text.secondary">
|
||||
History (Phase 5)
|
||||
</Typography>
|
||||
)}
|
||||
{currentRoute === 'dictionary' && (
|
||||
<Typography variant="h5" color="text.secondary">
|
||||
Dictionary (Phase 5)
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue