feat(V2-1a): Monorepo 구조 전환 — apps/desktop으로 V1 이동
- npm workspaces 루트 (apps/*, packages/*) 세팅 - V1 전체를 apps/desktop/으로 git mv (src, resources, tests, sidecar, scripts, electron.vite.config.ts, electron-builder.yml, vitest.config.ts, tsconfig.node.json, tsconfig.web.json) - apps/desktop/package.json 신규 (name=@d3ro/desktop) - productName: 'd3ro-voice' 명시 — app.getName()을 고정하여 userData 경로 %APPDATA%\d3ro-voice\ 그대로 유지 (기존 DB/설정 연속성 보장) - 루트 package.json을 workspace 루트로 재구성, 공통 devDep만 유지 (typescript, eslint, prettier) - turbo.json, tsconfig.base.json 추가 (Turborepo 자체 설치는 별도 sub-phase) - memory/project_status.md 생성 (규칙 13) 검증: - npm run typecheck 통과 - npm run build 통과 (electron-vite main+preload+renderer) - npm run dev 실제 실행 → DB/핫키/Ollama 자동 실행 모두 정상
This commit is contained in:
parent
3a160b9032
commit
45a580878a
178 changed files with 214 additions and 0 deletions
163
apps/desktop/src/renderer/components/OllamaGuideModal.tsx
Normal file
163
apps/desktop/src/renderer/components/OllamaGuideModal.tsx
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// src/renderer/components/OllamaGuideModal.tsx
|
||||
// Ollama 설치/설정 안내 모달
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Divider,
|
||||
IconButton,
|
||||
} from '@mui/material'
|
||||
import CloseIcon from '@mui/icons-material/Close'
|
||||
import OpenInNewIcon from '@mui/icons-material/OpenInNew'
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy'
|
||||
import { d3roPalette, d3roFontMono, d3roShadow } from '../theme'
|
||||
import { Led } from './ds'
|
||||
import { useI18n } from '../i18n'
|
||||
|
||||
interface OllamaGuideModalProps {
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function CodeBlock({ children }: { children: string }): React.ReactElement {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
bgcolor: d3roPalette.bg.inset,
|
||||
borderRadius: '8px',
|
||||
p: 1.5,
|
||||
fontFamily: d3roFontMono,
|
||||
fontSize: '12px',
|
||||
color: d3roPalette.accent.amber,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
boxShadow: d3roShadow.inset,
|
||||
}}
|
||||
>
|
||||
<span>{children}</span>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => navigator.clipboard.writeText(children)}
|
||||
sx={{ color: d3roPalette.text.inactive, '&:hover': { color: d3roPalette.accent.amber } }}
|
||||
>
|
||||
<ContentCopyIcon sx={{ fontSize: 14 }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export function OllamaGuideModal({ open, onClose }: OllamaGuideModalProps): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
||||
const handleOpenLink = (url: string) => {
|
||||
window.electronAPI.system.openExternal({ url })
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
sx: {
|
||||
bgcolor: d3roPalette.bg.chassis,
|
||||
backgroundImage: 'none',
|
||||
border: `1px solid ${d3roPalette.border.subtle}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
fontFamily: d3roFontMono,
|
||||
fontWeight: 700,
|
||||
fontSize: '14px',
|
||||
letterSpacing: '1px',
|
||||
color: d3roPalette.accent.amber,
|
||||
py: 1.5,
|
||||
}}
|
||||
>
|
||||
{t('ollama.title')}
|
||||
<IconButton onClick={onClose} size="small" sx={{ color: d3roPalette.text.inactive }}>
|
||||
<CloseIcon sx={{ fontSize: 18 }} />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<Divider sx={{ borderColor: d3roPalette.border.subtle }} />
|
||||
<DialogContent sx={{ bgcolor: d3roPalette.bg.app }}>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, py: 1 }}>
|
||||
{/* Step 1 */}
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
|
||||
<Led color="amber" size={8} />
|
||||
<Typography sx={{ fontFamily: d3roFontMono, fontSize: '12px', fontWeight: 700 }}>
|
||||
{t('ollama.step1.title')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" sx={{ color: d3roPalette.text.secondary, mb: 1.5 }}>
|
||||
{t('ollama.step1.desc')}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
endIcon={<OpenInNewIcon sx={{ fontSize: 14 }} />}
|
||||
onClick={() => handleOpenLink('https://ollama.com/download')}
|
||||
sx={{ fontFamily: d3roFontMono, fontSize: '11px' }}
|
||||
>
|
||||
ollama.com/download
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ borderColor: d3roPalette.border.subtle }} />
|
||||
|
||||
{/* Step 2 */}
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
|
||||
<Led color="amber" size={8} />
|
||||
<Typography sx={{ fontFamily: d3roFontMono, fontSize: '12px', fontWeight: 700 }}>
|
||||
{t('ollama.step2.title')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" sx={{ color: d3roPalette.text.secondary, mb: 1.5 }}>
|
||||
{t('ollama.step2.desc')}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<CodeBlock>ollama pull qwen3:4b</CodeBlock>
|
||||
<Typography variant="caption" sx={{ color: d3roPalette.text.inactive }}>
|
||||
{t('ollama.step2.alt')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ borderColor: d3roPalette.border.subtle }} />
|
||||
|
||||
{/* Step 3 */}
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
|
||||
<Led color="green" size={8} />
|
||||
<Typography sx={{ fontFamily: d3roFontMono, fontSize: '12px', fontWeight: 700 }}>
|
||||
{t('ollama.step3.title')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" sx={{ color: d3roPalette.text.secondary }}>
|
||||
{t('ollama.step3.desc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ px: 3, pb: 2, bgcolor: d3roPalette.bg.app }}>
|
||||
<Button onClick={onClose} variant="contained">
|
||||
{t('common.confirm')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue