Phase 9 완료: 전체 남은 기능 구현
1. RecordingTip: thinking 상태 전환 시 opacity 보장 2. 히스토리 오디오 경로: WAV 파일 경로를 DB에 기록 3. 마이크 테스트 UI: Settings Audio 탭에 TEST 버튼 + 레벨 바 4. 온보딩 플로우: 첫 실행 시 3단계 안내 (환영→마이크→핫키→완료) 5. MetalDial 컴포넌트: 동심원 그루브, 회전 포인터, LED 인디케이터
This commit is contained in:
parent
d7074e359d
commit
c338a19c90
7 changed files with 431 additions and 4 deletions
119
src/renderer/components/ds/MetalDial.tsx
Normal file
119
src/renderer/components/ds/MetalDial.tsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// src/renderer/components/ds/MetalDial.tsx
|
||||
// 시안 A: 메탈 다이얼 — 정밀기기 회전 노브, 동심원 그루브, LED 인디케이터
|
||||
|
||||
import { Box, Typography } from '@mui/material'
|
||||
import { d3roPalette, d3roFontMono } from '../../theme'
|
||||
|
||||
interface MetalDialProps {
|
||||
/** 0.0 ~ 1.0 값 (다이얼 위치) */
|
||||
value?: number
|
||||
/** 라벨 텍스트 */
|
||||
label?: string
|
||||
/** 크기 (px) */
|
||||
size?: number
|
||||
/** LED 인디케이터 색상 */
|
||||
ledColor?: string
|
||||
}
|
||||
|
||||
export function MetalDial({
|
||||
value = 0,
|
||||
label,
|
||||
size = 120,
|
||||
ledColor = d3roPalette.accent.amber,
|
||||
}: MetalDialProps): React.ReactElement {
|
||||
const rotation = value * 270 - 135 // -135° ~ +135° 범위
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
|
||||
{/* 다이얼 외곽 */}
|
||||
<Box
|
||||
sx={{
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: '50%',
|
||||
bgcolor: d3roPalette.bg.chassis,
|
||||
boxShadow: `
|
||||
0 4px 12px rgba(0,0,0,0.5),
|
||||
inset 0 2px 4px rgba(255,255,255,0.08),
|
||||
inset 0 -2px 4px rgba(0,0,0,0.3)
|
||||
`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
{/* 동심원 그루브 (CSS로 시뮬레이션) */}
|
||||
<Box
|
||||
sx={{
|
||||
width: size - 16,
|
||||
height: size - 16,
|
||||
borderRadius: '50%',
|
||||
background: `
|
||||
repeating-radial-gradient(
|
||||
circle at center,
|
||||
${d3roPalette.bg.chassis} 0px,
|
||||
${d3roPalette.bg.card} 1px,
|
||||
${d3roPalette.bg.chassis} 2px
|
||||
)
|
||||
`,
|
||||
boxShadow: `
|
||||
inset 0 1px 3px rgba(0,0,0,0.6),
|
||||
0 1px 1px rgba(255,255,255,0.05)
|
||||
`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transform: `rotate(${rotation}deg)`,
|
||||
transition: 'transform 0.2s ease-out',
|
||||
}}
|
||||
>
|
||||
{/* 포인터 인디케이터 */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 8,
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: '50%',
|
||||
bgcolor: ledColor,
|
||||
boxShadow: `0 0 6px ${ledColor}`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* LED 인디케이터 (우측 상단) */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 4,
|
||||
right: size * 0.25,
|
||||
width: 5,
|
||||
height: 5,
|
||||
borderRadius: '50%',
|
||||
bgcolor: ledColor,
|
||||
boxShadow: `0 0 4px ${ledColor}`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* 라벨 */}
|
||||
{label && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontFamily: d3roFontMono,
|
||||
fontSize: '9px',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '1.5px',
|
||||
color: d3roPalette.text.inactive,
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -7,3 +7,4 @@ export { Led } from './Led'
|
|||
export { PhysicalButton } from './PhysicalButton'
|
||||
export { MetalCard } from './MetalCard'
|
||||
export { PhosphorText } from './PhosphorText'
|
||||
export { MetalDial } from './MetalDial'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue