Design System v2 (OKLCH 3계층 토큰)
SPEC #006 §2-3 · SPEC #012 정합. linkmusic-frontend-space/packages/ui/.
Overview
디자인 시스템 v2 — handoff 20-design-system-proposal.md v0.1 채택. OKLCH 색공간 + Toss-restraint (절제된
표현). 공통 토큰은 surface 3종이 공유, 밀도 / 스케일은 surface 별 독립.
3 계층 토큰
Layer 1 — Primitive (raw palette · 변경 거의 없음)
↓
Layer 2 — Semantic (light · dark 2 mapping)
↓
Layer 3 — Surface-specific (밀도 · 스케일 · 모션)
↓
base.css (Tailwind v4 reset + tokens 활용)Layer 1 — Primitive (tokens.css)
OKLCH ramp:
--n-0…--n-12— near-pure gray neutral (0=darkest, 12=lightest)--brand-1…--brand-5— Pulse Violet (primary =--brand-3)--energy-1…--energy-3— Signal Lime (예약 ramp — v2 미매핑)--mag-1·--mag-2— Magenta (예약 — 앨범 아트만)--success-1/2·--warn-1/2·--danger-1/2·--info-1/2— semantic hues--imp-alert·--imp-alert-fg— 임퍼소네이션 빨간 배너 전용 토큰
Layer 2 — Semantic (semantic.css)
:root (light) + [data-theme="dark"] 2매핑:
--bg— 페이지 배경--surface— 카드 · 모달 등 layered surface--fg— text default--fg-muted·--fg-soft--primary·--primary-fg--ring— focus ring--border·--border-strong--now-playing— 송출 중 표시 전용 색--imp-alert— 임퍼소네이션 배너 색
Layer 3 — Surface scale
surface 3종이 같은 Layer 1·2 위에 자기 밀도를 얹는다:
| 토큰 | Surface 10 (admin) | Surface 11 (본사 모드) | Surface 12 (점장 모드) |
|---|---|---|---|
--font-base | 14px (compact) | 15px (medium) | 17px (large) |
--density | compact | medium | comfortable |
--radius | 0.375rem | 0.5rem | 0.625rem |
--tap-min | 32px | 40px | 48px |
--motion | 120ms subtle | 180ms reassuring | 200ms decisive |
packages/ui/src/styles/surface-admin.css — Surface 10 layer.
Surface 11·12 는 후속 SPEC.
Tailwind v4 통합
apps/admin/src/app/globals.css 의 cascade:
@import url("https://cdn.jsdelivr.net/.../pretendardvariable.css"); /* 폰트 최상단 */
@import "tailwindcss"; /* v4 reset + utilities */
@import "@linkmusic/ui/styles/all.css"; /* Layer 1→2→3→base */@linkmusic/ui/styles/all.css:
@import "./tokens.css"; /* Layer 1 */
@import "./semantic.css"; /* Layer 2 */
@import "./surface-admin.css"; /* Layer 3 — surface 별 다른 파일 */
@import "./base.css"; /* element defaults */ThemeProvider
packages/ui/src/lib/theme-provider.tsx:
<html data-theme="light|dark">토글- 사용자 선택 → cookie
lm_theme저장 (non-HttpOnly · SSR 사용) - 초기값 SSR:
await readThemeFromCookie()→ layout 의<html data-theme="">미리 박힘 → 깜빡임 X
apps/admin/src/lib/theme-cookie.ts:
export const readThemeFromCookie = async (): Promise<Theme> => {
const c = (await cookies()).get("lm_theme")?.value;
if (c === "light" || c === "dark") return c;
return "system"; // OS prefers-color-scheme 기본
};Secure cookie 정책 — lm_theme 는 non-HttpOnly. Secure 는 location.protocol === "https:" 일 때만
([[feedback-4]]).
컴포넌트 (@linkmusic/ui)
packages/ui/src/components/ (flat — atoms/·shells/ 하위 디렉토리 없음). export 단일 소스는
packages/ui/src/index.ts:
| 컴포넌트 | 용도 |
|---|---|
Button | primary · secondary · ghost · danger (CVA variants) |
Banner | 정보 · 경고 · 위험 · 성공. 임퍼소네이션 배너 별도 (--imp-alert) |
StatusPill | enum status 시각 (ACTIVE · SUSPENDED · …) |
OrgAvatar | 본사/매장 헤더 아바타 (initial-based fallback) |
Card | 카드 컨테이너 (Card·CardHeader·CardTitle·CardContent) |
Dialog | Radix Dialog wrapper — 개별 export (DialogContent 등, namespace 없음) |
DropdownMenu | Radix DropdownMenu wrapper |
Tabs / Tab | 필터 button group (role="group" + aria-pressed, Radix 미사용) |
Toast | Radix Toast wrapper (ToastProvider·ToastViewport 등) |
Switch | on/off 토글 |
Field | label + input + error 묶음 |
Input / Label | 폼 primitive |
FormSection | 폼 영역 grouping + title · description |
AuthShell | 로그인 / 비밀번호 변경 등 인증 화면 셸 |
AuthCard | 인증 폼 카드 |
운영사 백오피스 셸 (
OpsShell) 은@linkmusic/ui에 단일 컴포넌트로 없다.apps/admin의(protected)/layout.tsx가Topbar+Sidebar를 조합한다. 마찬가지로OpsStepper·PageHeader도@linkmusic/ui가 아니라apps/admin/src/components/shell/소속이다 (등록 화면 stepper · 페이지 헤더). 자세한 구조는 Shells 참고.
Constraints
- handoff 에 없는 시각 결정 금지 (
[[memory: feedback_design_only_from_handoff]]). 새 컴포넌트 / 화면이 필요하면 사용자가 claude design 에 받아온 시안을 입력으로. - Tailwind v4 의
@import "tailwindcss"는 base.css 위에. - font @import 는 apps globals.css 최상단 (
@import룰이 다른 rule 보다 앞서야 함).
Decisions
- OKLCH 채택 — perceptual lightness (RGB 대비 brightness 일관)
- Toss-restraint — 강조색 (lime · magenta) 은 송출 / now-playing 같은 의미 있는 자리만
- shadcn/ui 미사용 — handoff 토큰을 직접 코드화 (custom)
- Storybook 후속 — atoms 가 안정되면 도입
Roadmap
- Surface 11·12 layer 추가 (
surface-store-hq.css·surface-store.css) - Storybook (
packages/ui시각 카탈로그) - Tokens documentation site (이 docs 의
/features/design-system/tokens)
Toast·DropdownMenu는 이미@linkmusic/ui에 존재하고 admin 에서 사용 중이다 (roadmap 항목 아님).
References
- SPEC #006 §2-3 (v1 토큰)
- SPEC #012 (v2 — Toss-restraint 재정의)
- handoff
20-design-system-proposal.mdv0.1 linkmusic-frontend-space/packages/ui/src/styles/linkmusic-frontend-space/packages/ui/src/components/