FeaturesDesign System 컴포넌트Tokens (OKLCH 3계층)

Tokens — OKLCH 3계층

SPEC #006 · #012 · architecture/design-system 정합. 토큰 본체는 packages/ui/src/styles/.

Overview

OKLCH 색공간 + 3 계층 cascade. apps/admin/src/app/globals.css 에서 import.

Cascade

/* apps/admin/src/app/globals.css */
@import url("https://cdn.jsdelivr.net/.../pretendardvariable.css");  /* font 최상단 */
@import "tailwindcss";
@import "@linkmusic/ui/styles/all.css";  /* Layer 1→2→3→base */

@linkmusic/ui/styles/all.css:

@import "./tokens.css";          /* Layer 1: primitive */
@import "./semantic.css";        /* Layer 2: semantic light/dark */
@import "./surface-admin.css";   /* Layer 3: Surface 10 scale */
@import "./base.css";            /* element defaults using tokens */

Layer 1 — Primitive (tokens.css)

ramp의미
--n-0--n-12near-pure gray neutral (0=darkest, 12=lightest)
--brand-1--brand-5Pulse Violet (primary = --brand-3)
--energy-1--energy-3Signal Lime (예약 ramp — v2 에서 시맨틱 미매핑)
--mag-1 · --mag-2Magenta (예약 — 앨범 아트만)
--success-1 · --success-2semantic success
--warn-1 · --warn-2semantic warning
--danger-1 · --danger-2semantic danger
--info-1 · --info-2semantic info
--imp-alert · --imp-alert-fg임퍼소네이션 빨간 배너 전용 토큰 (스케일 아님)

OKLCH 표현 — perceptual lightness 일관:

--brand-3: oklch(0.58 0.22 295); /* ★ primary */

Layer 2 — Semantic (semantic.css)

:root(light) + [data-theme="dark"] 2 mapping (system 은 dark 와 동일 값을 prefers-color-scheme 으로):

토큰lightdark
--bg--n-10--n-0
--surface--n-12--n-1
--surface-2--n-9--n-2
--surface-3--n-8--n-3
--fg--n-1--n-9
--fg-muted--n-5--n-6
--fg-soft--n-4--n-5
--border--n-8--n-3
--border-strong--n-7--n-4
--primary--brand-3--brand-3
--primary-strong--brand-2--brand-2
--primary-fg--n-12oklch(0.99 0 0)
--ring--brand-3--brand-4
--success--success-1--success-2
--warn--warn-1--warn-2
--danger--danger-1--danger-2
--info--info-1--info-2
--now-playing--brand-3--brand-4

--imp-alert 는 light/dark 무관 단일 primitive 토큰 — semantic 매핑 없이 임퍼소네이션 배너가 직접 참조.

Layer 3 — Surface scale (surface-admin.css)

Surface 10 = compact density:

:root {
  --font-base: 14px;
  --density: compact;
  --radius: 0.375rem;
  --tap-min: 32px;
  --motion: 120ms;
}

Surface 11·12 layer 는 후속 SPEC (각자 surface-store-hq.css · surface-store.css).

ThemeProvider

// packages/ui/src/lib/theme-provider.tsx
'use client';
export const ThemeProvider = ({ initialTheme, children }) => {
  const [theme, setTheme] = useState(initialTheme);
  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
  }, [theme]);
  // setTheme 호출 시 쿠키 기록 (Max-Age = 1년):
  //   const maxAge = 60 * 60 * 24 * 365;
  //   const secure = location.protocol === "https:" ? "; Secure" : "";
  //   document.cookie = `lm_theme=${theme}; Path=/; Max-Age=${maxAge}; SameSite=Lax${secure}`;
  // ...
};

SSR — apps/admin/src/lib/theme-cookie.tsreadThemeFromCookie()<html data-theme> 미리 박음 → hydration 깜빡임 X.

Constraints

  • @import url(...font) 는 apps globals.css 최상단 — CSS @import 룰 순서 ([[feedback-9]]).
  • Tailwind v4 @import "tailwindcss" 다음에 ui all.css — base layer 충돌 방지.
  • Layer 1 변경 거의 없음 — palette 자체. semantic mapping 만 자유 조정.
  • --imp-alert 토큰은 정의만, 실 사용은 임퍼소네이션 배너 한정.

Roadmap

  • Surface 11·12 layer
  • color-mix() 폴리필 검토 (구 브라우저 — v1 Chrome/Edge 최신만 지원이라 불필요)
  • 토큰 시각 카탈로그 (Storybook)

References

  • SPEC #006 §2-3 · SPEC #012
  • handoff 20-design-system-proposal.md v0.1
  • linkmusic-frontend-space/packages/ui/src/styles/