시작하기
시작하기
센트럴바이 디자인 시스템의 약속, 원칙, 쓰는 법(가져오기·토큰·테마·언어)과 출시용·라이브러리 구분을 한 페이지에.
계약
디자인 시스템은 제품이 아니라 계약이다. 문서·코드·디자인은 한 원천에서 나온다.
센트럴바이는 흩어진 업무 기록에서 내가 해온 일을 찾아, 근거와 함께 기억하고 필요할 때 설명할 수 있게 돕는 개인 업무 기억 서비스다. 약속은 “You work. centralby remembers.” 이 시스템의 모든 규칙은 이 약속을 화면에서 지키기 위해 있다.
- 컴포넌트의 문서는 meta 파일 하나다. 문서화하지 않은 prop은 tsc가 실패시킨다.
- 색·크기·시간 값은 토큰에만 있다. 리터럴은 design:lint가 막는다.
- 이 가이드의 값과 숫자는 실행 중인 CSS와 registry에서 읽는다. 문서가 코드보다 앞서거나 뒤처질 수 없다.
지금의 규모
- 컴포넌트
- 142
- 출시 화면에서 사용
- 71
- 라이브러리 전용
- 71
- 만들지 않는 이유 페이지
- 6
- 위젯
- 61 · 출시 12종
- 가이드 페이지
- 21
숫자는 이 페이지가 열릴 때 registry.ts·rulePages·오너 선택 위젯 목록(picks.ts)에서 직접 센다. 문서에 적은 숫자가 아니다.
원칙
제품 철학은 화면에서 쓰는 방식에 적용한다. 라이브러리에 차트가 있어도 생산성 점수에 쓰지 않는다는 식이다(DIRECTION §4).
- 기록과 근거를 먼저 보존한다. 추천·발견·보고서·경력 문장은 쌓인 기록을 활용하는 기능이다. 화려한 대시보드로 기록의 부족을 가리지 않는다.
- 사실과 해석을 구분한다. 원문에서 확인한 것, 시스템의 추정, 사용자의 진술을 나눈다. 메일 수신은 기여가 아니고 일정 초대는 참석이 아니다. 자료 수를 생산성 점수로 바꾸지 않는다.
- 자동화가 새 업무를 만들지 않는다. 결과는 들어오는 대로 보여주고, 검토는 기여 귀속·사실 충돌·외부에 쓸 문장처럼 중요한 지점에만 모은다.
- 사용자의 수정과 선택을 존중한다. 직접 쓴 설명은 자동 정리 때문에 사라지지 않는다. 합치기·나누기·연결 해제·되돌리기가 가능하다.
- 수집한 범위만 설명한다. 아직 읽지 않음, 읽었지만 결과 없음, 일부 실패를 구분한다. 접근할 수 없는 과거 자료를 복원한다고 약속하지 않는다.
- 필요한 순간의 효용으로 평가한다. 방문 횟수를 늘리려고 불필요한 확인이나 반복 행동을 만들지 않는다.
쓰는 법
가져오기
화면은 @/design 하나에서만 가져온다. meta·registry·catalog·*.preview.tsx는 공개 API가 아니다. 기존(legacy) 화면은 @/design을 가져올 수 없고, v4 코드는 @/ui를 가져올 수 없다(lint R6·R7).
import { Button, StateView, TrustLabel } from '@/design';
<StateView state="partial" surface="list">
{rows}
</StateView>컴포넌트는 className·style을 받지 않는다. 배치는 부모가, 모양은 토큰이 정한다. 나머지 네이티브 속성은 그대로 전달된다.
토큰
세 층이다: primitive(--p-*, 원시값, tokens 폴더 안에서만) → semantic(--cb-*, 역할 이름) → 컴포넌트 로컬 변수. 컴포넌트와 화면은 --cb-*만 쓴다.
.row {
padding: var(--cb-space-3) var(--cb-space-4);
border-bottom: var(--cb-border-width) solid var(--cb-line);
color: var(--cb-ink);
transition: background-color var(--cb-dur-fast) var(--cb-ease);
}테마
라이트가 기본이고 다크를 함께 설계했다. <html data-theme="light|dark">가 있으면 그것을, 없으면 prefers-color-scheme을 따른다. themeScript가 첫 페인트 전에 적용해 깜빡임이 없다. 미리보기 프레임은 data-theme을 따로 줄 수 있다. 제품에는 테마 선택기가 없다(DIRECTION 1.6) — 선택기는 카탈로그 전용이다.
// (v4)/layout.tsx
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
// a frame that is always dark
<div data-theme="dark">…</div>언어
UI는 한국어·영어·중국어(간체)·스페인어 4개 언어다. <html lang>은 서버가 centralby_locale 쿠키로 정한다. 컴포넌트 안의 문구는 DesignLocaleProvider로 받는다. 사용자가 쓴 기록·작업 제목은 번역하지 않고, 언어를 모르면 dir="auto"만 붙인다.
<DesignLocaleProvider locale={locale}>
<AppShell />
</DesignLocaleProvider>스페인어가 가장 길다. 라벨은 한국어 대비 +35%를 수용해야 하고, 카탈로그의 “가장 긴 언어(es)” 토글로 확인한다.
출시용과 라이브러리
오너는 “하나의 방대한 디자인 시스템을 먼저 만들고, 앱 개발 때 필요한 것을 꺼내 쓴다”로 정했다. 그래서 모든 컴포넌트 meta에 launch가 있다. launch: true는 출시 화면(랜딩·/signup·/start·오늘·기록·나)이 실제로 쓰는 것이다. launch: false는 라이브러리에만 있고, 첫 소비자가 생길 때 true로 바꾼다.
- 이렇게출시 화면은 launch: true 컴포넌트로 조립한다. 라이브러리 컴포넌트가 필요하면 먼저 meta를 true로 바꾸고 검토를 받는다.
- 이렇게 하지 않기launch: false라고 품질 기준이 낮지 않다. 접근성·4개 언어·토큰 규칙은 같다.
| 분류 | 전체 | 출시 | 라이브러리 | 출시용 예 |
|---|---|---|---|---|
| 글자 | 10 | 7 | 3 | |
| 레이아웃 | 7 | 6 | 1 | |
| 버튼과 동작 | 4 | 2 | 2 | |
| 입력 | 13 | 6 | 7 | |
| 탐색 | 11 | 6 | 5 | |
| 목록과 표시 | 15 | 6 | 9 | |
| 상태와 알림 | 16 | 12 | 4 | |
| 미디어와 구매 | 5 | 0 | 5 | |
| 차트 | 9 | 0 | 9 | |
| 날짜와 시간 | 12 | 2 | 10 | |
| 편집 도구 | 7 | 0 | 7 | |
| 근거와 신뢰 | 20 | 19 | 1 | |
| 기록과 경험 | 9 | 2 | 7 | |
| 위젯 | 4 | 3 | 1 |
만들지 않는 것
라이브러리 범위에서는 v3-jh 목록을 모두 갖추지만, 제품 화면에서는 다음을 쓰지 않는다.
- 테마 선택기, 외관 농도 조절, 폰트 선택기
- 스프링 물리, 스크러빙, 시간축 스크러버
- 활동 히트맵, streak, 생산성 수치, 점수, 순위
- 10–11px 글자(최소 13px)
컴포넌트가 없는 대신 “만들지 않는 이유” 페이지를 둔 경우도 있다(예: RadarChart, ComboChart). 사이드바에서 해당 분류 끝에 있다.
다음에 볼 곳
컴포넌트 목록은 사이드바의 “모든 컴포넌트”, 원시값과 의미 토큰 전체는 “디자인 토큰”, 위젯은 “위젯”에 있다.
@/design · src/design/tokens/*.css · src/design/registry.ts