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:
yunchan8804 2026-04-08 14:04:41 +09:00
parent 3a160b9032
commit 45a580878a
178 changed files with 214 additions and 0 deletions

View file

@ -0,0 +1,78 @@
// src/renderer/components/ProBadge.tsx
// Feature gate badge: renders children normally if unlocked,
// shows lock overlay with PRO badge if locked.
import { Box, Typography } from '@mui/material'
import LockIcon from '@mui/icons-material/Lock'
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '../theme'
import { useProFeature } from '../hooks/useProFeature'
import { useI18n } from '../i18n'
import type { Feature } from '@shared/types'
interface ProBadgeProps {
feature: Feature
children: React.ReactNode
}
export function ProBadge({ feature, children }: ProBadgeProps): React.ReactElement {
const { t } = useI18n()
const { unlocked, loading, showUpgrade } = useProFeature(feature)
// While loading or if unlocked, render children normally
if (loading || unlocked) {
return <>{children}</>
}
return (
<Box sx={{ position: 'relative' }}>
{/* Children rendered with reduced opacity */}
<Box sx={{ opacity: 0.35, pointerEvents: 'none', filter: 'grayscale(0.6)' }}>
{children}
</Box>
{/* Lock overlay */}
<Box
onClick={showUpgrade}
sx={{
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
borderRadius: d3roRadius.inner,
transition: 'background-color 0.15s ease',
'&:hover': {
bgcolor: d3roPalette.accent.amberDim,
},
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
px: 1.5,
py: 0.5,
borderRadius: d3roRadius.small,
bgcolor: d3roPalette.bg.elevated,
border: `1px solid ${d3roPalette.border.default}`,
}}
>
<LockIcon sx={{ fontSize: 14, color: d3roPalette.accent.amber }} />
<Typography
sx={{
fontFamily: d3roFontMono,
fontSize: d3roTypo.small.size,
fontWeight: d3roTypo.small.weight,
letterSpacing: d3roTypo.small.spacing,
color: d3roPalette.accent.amber,
}}
>
{t('license.pro.required')}
</Typography>
</Box>
</Box>
</Box>
)
}