Phase 10~11 전체 구현: 킬러 피처 5종 + 수익화 시스템

Phase 10 킬러 피처:
- MemoService: 태그 CRUD + 마크다운 내보내기 (memo_tags DB)
- VoiceCommandService: 키워드→명령어 매칭, 프리셋 4종
- ScreenContextService: PowerShell 활성 윈도우 + Ctrl+C 선택 텍스트
- ChainService: LLM 명령어 순차 실행 파이프라인
- CaptionService: 6초 청크 연속 전사 + 시스템 오디오 루프백

VoiceModeService 파이프라인 통합:
- 녹음 시작 → 컨텍스트 캡처 → STT → 키워드 매칭 → LLM(체인/컨텍스트 주입) → 삽입

시스템 오디오 캡처:
- setDisplayMediaRequestHandler + audio: 'loopback' (IPC 브릿지)
- electron-audio-loopback 패키지 contextIsolation 호환 불가 → 직접 구현

Phase 11 수익화:
- LicenseService: Free/Pro/Pro+ 3티어, LemonSqueezy API
- Feature Gate: requireFeature/checkFeature/consumeFeature
- 일일 쿼터: Free dictation 20/일, LLM 10/일 (SQLite daily_usage)
- LicenseModal, ProBadge, UpgradePromptModal UI

디자인 보강:
- d3roTypo(13종), d3roShadow(10종), d3roRadius(7종) 토큰 시스템
- ScreenPanel, ButtonGroup DS 컴포넌트 신규
- PhosphorText 4→13종 변형, MetalDial conic-gradient 광택
- 공유 컴포넌트: EmptyStateCard, SearchInput, PageHeader, HistoryEntryCard

기타:
- 자막 핫키 SSOT 전체 연동 (Config→Hotkey→VoiceMode→Caption→Settings)
- StatusBar 자막 LED + 효과음, 자막 로딩 UI
- LLM 상태 이벤트 전파 수정 (폴링 제거 → onStatusChanged)
- 커맨드 팝업 "선택 해제" 항목 추가
This commit is contained in:
Yun Chan 2026-04-05 21:36:09 +09:00
parent 36d77ca224
commit a31f96bbb8
97 changed files with 11853 additions and 1143 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>
)
}