WIP: 인스트루먼트 UI 시도 (DS 컴포넌트 + CRT 셰이더)

- DS 컴포넌트: CrtDisplay, InstrumentPanel, Led, PhysicalButton, MetalCard, PhosphorText
- Dashboard: CRT WebGL 셰이더 + 물리 버튼 + LED 클러스터
- 사이드바: 72px 미니 네비게이션
- 문제: SSOT 위반(매직넘버 41곳), 시안 A 정체성 부족, 모달/팝업 방치
- 다음: 디자인 근본 재설계 필요
This commit is contained in:
Yun Chan 2026-04-05 09:20:40 +09:00
parent 3f4d0c5828
commit 85d626b922
13 changed files with 930 additions and 746 deletions

View file

@ -0,0 +1,77 @@
// src/renderer/components/ds/InstrumentPanel.tsx
// 시안 A: 메탈 섀시 컨테이너 — 노이즈 텍스처, 각인 텍스트, 물리적 존재감
import { Box, Typography } from '@mui/material'
interface InstrumentPanelProps {
children: React.ReactNode
/** 상단 좌측 각인 */
engravingLeft?: string
/** 상단 우측 각인 */
engravingRight?: string
/** 하단 중앙 각인 */
engravingBottom?: string
}
export function InstrumentPanel({
children,
engravingLeft = 'D3RO-VOICE SYS.',
engravingRight = 'MOD-01 / TERMINAL',
engravingBottom = 'LOCAL AI VOICE ASSISTANT',
}: InstrumentPanelProps): React.ReactElement {
return (
<Box
sx={{
position: 'relative',
bgcolor: '#242528',
borderRadius: '24px',
p: 3,
boxShadow:
'0 60px 100px -20px rgba(0,0,0,0.8), 0 12px 0 #111112, 0 13px 4px rgba(0,0,0,0.5), inset 0 1px 1px rgba(255,255,255,0.15), inset 0 -1px 2px rgba(0,0,0,0.4)',
// 메탈 노이즈는 CSS로 시뮬레이션
'&::before': {
content: '""',
position: 'absolute',
inset: 0,
borderRadius: '24px',
backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")`,
opacity: 0.04,
mixBlendMode: 'overlay',
pointerEvents: 'none',
zIndex: 1,
},
}}
>
{/* 각인 텍스트 */}
<Engraving sx={{ top: 12, left: 24 }}>{engravingLeft}</Engraving>
<Engraving sx={{ top: 12, right: 24 }}>{engravingRight}</Engraving>
<Engraving sx={{ bottom: 12, left: '50%', transform: 'translateX(-50%)' }}>{engravingBottom}</Engraving>
{/* 콘텐츠 (z-index 5로 노이즈 위) */}
<Box sx={{ position: 'relative', zIndex: 5 }}>
{children}
</Box>
</Box>
)
}
function Engraving({ children, sx }: { children: string; sx: Record<string, unknown> }): React.ReactElement {
return (
<Typography
sx={{
position: 'absolute',
fontSize: '9px',
letterSpacing: '1.5px',
color: '#1a1a1c',
textShadow: '0 1px 0 rgba(255,255,255,0.08)',
fontWeight: 700,
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
zIndex: 2,
userSelect: 'none',
...sx,
}}
>
{children}
</Typography>
)
}