프로젝트 · 2026
useTaehwan()/ui
읽고 있는 이 문서, 그 문서가 만든 화면
- TypeScript
- Tailwind v4
- React
개요
디자인 시스템을 처음부터 별도 패키지로 만들면, 무엇이 필요한지 모르는 상태에서 API를 고정하게 되어 거의 항상 틀립니다. 그래서 이 사이트의 v1을 '첫 소비처'로 두고 실사용으로 API를 검증한 뒤 추출하는 전략을 택했습니다. 검증이 끝난 뒤 사이트는 v2에서 자체 도면 테마로 독립했고, 시스템은 Orbit·각(Gak)이 씁니다.
작업 사례
사례 1
추출 순서 — 소비처에서 먼저 검증하고 패키지로 뺀다
- 문제
- 디자인 시스템을 처음부터 별도 패키지로 만들면, 무엇이 필요한지 모르는 상태에서 컴포넌트 API를 고정하게 됩니다. 회사에서 사내 UI킷을 제작·소비 양쪽에서 담당하며 이런 API가 소비처에서 어떻게 깨지는지를 먼저 봤습니다.
- 파악
- API가 틀리는 지점은 설계 단계가 아니라 실제 화면에 붙이는 순간에 드러납니다. 소비처가 없는 컴포넌트는 검증할 방법이 없었습니다.
- 해결
- 이 사이트의 v1을 첫 소비처로 두고 6개 프리미티브로 시작해 실사용으로 API를 검증한 뒤 별도 저장소로 추출, npm 0.1.0(2026.07.18) → 0.2.0(07.26)으로 배포했습니다. 이후 Orbit·각(Gak)이 같은 패키지를 설치해 쓰면서 컴포넌트가 10개로 늘었습니다.
사례 2
테마가 그림자를 따라오지 않는다
- 문제
- 토큰만 덮어써서 다크모드·프로젝트별 테마를 만드는 구조인데, 색·라운드는 따라오는데 그림자만 테마를 무시했습니다.
- 파악
- 빌드 산출물을 열어보니 Tailwind v4가 shadow-sm 유틸리티에 그림자 값을 빌드타임에 인라인해 두고 있었습니다(--tw-shadow: 0 1px 2px … #33302a0d). 런타임에 --shadow-* 토큰을 덮어도 유틸리티가 그 변수를 참조하지 않으니 반영될 수가 없었습니다. 영향 범위는 shadow-sm을 쓰는 Card와 shadow-lg를 쓰는 Modal 둘.
- 해결
- 프레임워크 한계로 판단해 우회하지 않고 시안-구현 간극 문서(token-mapping.md)에 기록했습니다. 대신 테마 오버라이드 범위를 색 13개·radius 4개로 명시하고, Modal이 body 포털이라 data-theme을 html에 걸어야 한다는 함정도 함께 문서화했습니다.
사례 3
데모가 뜬다 = 패키지가 정상이다, 를 진짜로 만들기
- 문제
- 데모 사이트가 소스(src)를 직접 import하면, 빌드 산출물(dist)이나 exports 설정이 깨져도 데모는 멀쩡히 뜹니다. 데모가 패키지 정상성을 증명하지 못했습니다.
- 파악
- 실제 소비자가 겪는 경로는 npm install → package.json exports → dist입니다. 데모가 그 경로를 타지 않으면 검증하는 대상이 다른 것입니다.
- 해결
- 데모를 npm workspace(file:..)로 묶어 exports가 가리키는 dist를 소비자와 같은 방식으로 import하게 하고, demo:build가 라이브러리 빌드를 선행하도록 강제했습니다. 이제 ui.usetaehwan.page가 뜨는 것 자체가 배포 산출물의 정상성 증명입니다.
핵심 기능
토큰 단일 소스(SSOT)
컬러·타이포·스페이싱·라운드·섀도우를 Tailwind v4 @theme 토큰으로 정의. 컴포넌트는 var(--color-*)만 참조하므로 토큰 하나를 바꾸면 화면 전체가 따라 바뀝니다.
프로젝트별 테마
컴포넌트가 토큰만 참조하므로, 소비 프로젝트에서 토큰을 덮어쓰는 것만으로 전혀 다른 무드의 테마가 됩니다. 이 사이트 v1(웜 뉴트럴)·Orbit(우주)·각(볼트 그린)이 같은 패키지로 세 가지 무드를 냈습니다. 다크모드도 같은 원리 — .dark에서 토큰 값만 덮고, on-brand 글자색은 배경 밝기로 자동 계산해 WCAG 대비를 유지합니다.
10개 컴포넌트
Button · Input · Card · Badge · Typography · Container · Modal · ProgressBar · OrbitLoader · EmptyState. native 속성 상속 + cn(clsx+tailwind-merge)으로 외부 className 병합, focus-visible·aria-invalid 접근성 대응.
인터랙티브 토큰 데모
방문자가 브랜드 색·라운드 토큰을 조작하면 컴포넌트가 그 자리에서 실시간으로 반응. '토큰 기반으로 동작한다'를 직접 체험시키는 것이 목적입니다.
스택
- TypeScript
- Tailwind v4
- React 19
- Next.js 16
- Framer Motion