@bnvsrnd/brand-assets
v1.4.0
Published
BNV Solutions design tokens & components
Maintainers
Readme
brand-assets
비앤브이솔루션(BNV Solutions) 공식 디자인 시스템 단일 진본. Figma에서 디자인하고, 코드에서 바로 쓸 수 있도록 토큰화해서 자동 빌드합니다.
운영 브랜치는
main. Tokens Studio가tokens.json을 push하면 GitHub Actions가 자동으로 CSS/TS를 빌드해서 다시 commit합니다.
현재 상태
✅ Foundation Tokens 완성
| 카테고리 | 내용 |
|---|---|
| Color (Primitive) | Brand 10단계 + Gray, Success, Warning, Danger, Info(Sky) (각 10단계) + White/Black |
| Color (Semantic) | Background, Text, Border, Action, Status (Success/Warning/Danger/Info/Neutral) — Light/Dark 자동 매핑 |
| Typography | 15개 Text Styles (Display, Heading 1-4, Body, Label + Default/Small Semibold, Caption, Overline) |
| Spacing | 14단계 (space-0 0px ~ space-13 96px), 4px 베이스 |
| Radius | 7단계 (radius-none ~ radius-full) |
| Elevation | 4단계 shadow (Sm/Md/Lg/Xl) |
| Icon Size | 5단계 (Xs 12 / Sm 16 / Md 20 / Lg 24 / Xl 32) |
🎉 코어 컴포넌트 20/20 완성 (Figma + React + Demo)
| 그룹 | 컴포넌트 | |---|---| | Form (7) | Button · Input · Checkbox · Radio · Toggle · Textarea · Select | | Display (5) | Badge · Avatar · Card · Search · Divider | | Overlay (4) | Modal · Drawer · Toast · Tooltip | | Navigation (2) | Tabs · Menu | | Feedback (2) | Spinner · Alert |
🔧 접근성
- Portal (Modal · Drawer · ToastContainer · Tooltip) — 부모 transform/overflow 영향 없음
- Focus Trap + Body Scroll Lock (Modal · Drawer)
- Keyboard Navigation (Tabs ←→, Menu ↓↑, Select)
- Animation API (Modal · Drawer · Toast) —
animationprop + CSS 변수 + Exit animation prefers-reduced-motion대응- ARIA roles:
dialog,tab,tabpanel,menu,menuitem,listbox,option,switch,alert,tooltip,status,separator
🧪 Unit Tests
- Vitest + Testing Library
- 68 tests across 20 components
npm test/npm run test:watch/npm run test:coverage
사용 방법
1단계: 설치
npm install @bnvsrnd/brand-assetspeer dependency: React 18+ (React 19 권장). 이 단계는 파일을
node_modules/에 다운로드만 합니다. 아직 화면엔 적용되지 않음.
2단계: 글로벌 CSS에 한 번만 import
프로젝트의 글로벌 CSS 파일 한 곳 또는 entry 파일에서:
// app/layout.tsx (Next.js) 또는 main.tsx (Vite)
import '@bnvsrnd/brand-assets/tokens/light.css';
import '@bnvsrnd/brand-assets/tokens/dark.css';
import '@bnvsrnd/brand-assets/styles.css'; // 컴포넌트도 쓸 경우또는 CSS 파일에서:
/* src/styles/globals.css */
@import '@bnvsrnd/brand-assets/tokens/light.css';
@import '@bnvsrnd/brand-assets/tokens/dark.css';
@import '@bnvsrnd/brand-assets/styles.css';⭐ 한 번만 import하면 프로젝트 전체에서 토큰 + 모든 컴포넌트 사용 가능. 페이지/컴포넌트마다 따로 import 불필요.
3단계: 컴포넌트에서 토큰 사용
.button {
background: var(--action-primary-default);
color: var(--action-primary-text);
padding: var(--space-3) var(--space-5);
border-radius: var(--radius-md);
font: var(--label-default);
}
.button:hover {
background: var(--action-primary-hover);
}다크 모드 토글
<html data-theme="dark">→ 모든 semantic 토큰이 자동으로 dark 매핑으로 전환됩니다.
토큰 둘러보기
전체 토큰 시각화: demo/index.html 브라우저로 열기 (Dark 토글 포함).
Per-product Brand 색 override (필수 인지)
BNV는 여러 제품을 운영하고 각 제품의 brand 색이 다릅니다 (코딩 플랫폼=퍼플, 수학 플랫폼=민트, BNV 메인=블루 …). 이 패키지의 --brand-* 토큰은 BNV 기본값이며, 각 제품은 brand 10단계만 override해서 자신의 색을 입힙니다.
의도된 토큰 분류
| 분류 | 토큰 | Override 가능? |
|---|---|---|
| 구조 (모든 제품 공통) | --gray-*, --space-*, --radius-*, --elevation-*, typography | ❌ 절대 금지 |
| Brand (제품별) | --brand-50 ~ --brand-900 | ✅ 권장 |
| Semantic | --action-primary-*, --status-*, --text-*, --background-* | ❌ brand-*만 바꾸면 자동 따라옴 |
Override 방법
// entry 파일
import '@bnvsrnd/brand-assets/tokens/light.css';
import '@bnvsrnd/brand-assets/tokens/dark.css';
import '@bnvsrnd/brand-assets/styles.css';
import './brand-override.css'; // ← 가장 마지막!/* coding-platform/src/brand-override.css — Purple 예시 */
:root {
--brand-50: #faf5ff;
--brand-100: #f3e8ff;
--brand-200: #e9d5ff;
--brand-300: #d8b4fe;
--brand-400: #c084fc;
--brand-500: #a855f7;
--brand-600: #9333ea;
--brand-700: #7e22ce;
--brand-800: #6b21a8;
--brand-900: #581c87;
}
[data-theme='dark'] {
--brand-50: #581c87;
--brand-100: #6b21a8;
--brand-200: #7e22ce;
--brand-300: #9333ea;
--brand-400: #a855f7;
--brand-500: #c084fc;
--brand-600: #d8b4fe;
--brand-700: #e9d5ff;
--brand-800: #f3e8ff;
--brand-900: #faf5ff;
}→ 모든 컴포넌트(Button, Badge, Progress, Modal focus ring 등)가 자동으로 그 제품의 brand 색을 따라옵니다. 컴포넌트 코드 변경 0줄.
10단계 색 생성 도구
hex 하나만 정하면 자동 생성:
- uicolors.app — hex → 10단계 + CSS export
- tailwindcss.com/docs/colors — purple/emerald/teal 등 검증된 팔레트 그대로 복사
- radix-ui.com/colors/custom — 더 정교한 생성
Tailwind 프로젝트와 통합
Tailwind config가 CSS 변수를 참조하도록 설정하면 bg-brand-600 같은 유틸리티도 자동으로 그 제품의 brand 색을 따라옵니다:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: 'var(--brand-50)',
100: 'var(--brand-100)',
200: 'var(--brand-200)',
300: 'var(--brand-300)',
400: 'var(--brand-400)',
500: 'var(--brand-500)',
600: 'var(--brand-600)',
700: 'var(--brand-700)',
800: 'var(--brand-800)',
900: 'var(--brand-900)',
DEFAULT: 'var(--brand-500)',
},
// Semantic도 동일 패턴으로 매핑하면 다크 모드 자동 대응
surface: 'var(--background-surface)',
ink: 'var(--text-primary)',
line: 'var(--border-default)',
},
borderRadius: {
sm: 'var(--radius-sm)',
md: 'var(--radius-md)',
lg: 'var(--radius-lg)',
full: 'var(--radius-full)',
},
},
},
};이제 className="bg-brand-600 rounded-lg"가 그 제품의 brand 색 + 우리 시스템 토큰 값으로 렌더됩니다.
React 컴포넌트 사용
위 2단계의 글로벌 import만 돼있으면, 어디서든 컴포넌트 import만으로 동작.
컴포넌트 카탈로그
import {
// Form (7)
Button, Input, Checkbox, Radio, Toggle, Textarea, Select,
// Display (5)
Badge, Avatar, Card, Search, Divider,
// Overlay (4)
Modal, Drawer, Toast, ToastContainer, Tooltip,
// Navigation (2)
Tabs, Menu,
// Feedback (2)
Spinner, Alert,
} from '@bnvsrnd/brand-assets';빠른 예시
Button
<Button variant="primary" size="md">저장</Button>
<Button variant="secondary" disabled>취소</Button>Input / Textarea
<Input label="이메일" helperText="[email protected]" />
<Textarea label="메모" maxLength={500} />Checkbox / Radio / Toggle
<Checkbox defaultChecked>동의합니다</Checkbox>
<Radio name="plan" value="pro">Pro</Radio>
<Toggle defaultChecked>다크 모드</Toggle>Select
<Select
label="카테고리"
options={[
{ value: 'design', label: '디자인' },
{ value: 'dev', label: '개발' },
]}
onChange={(v) => setCat(v)}
/>Badge / Avatar
<Badge color="success">완료</Badge>
<Avatar src="/profile.jpg" alt="홍길동" />
<Avatar initials="HG" size="lg" />Card
<Card variant="elevated">
<Card.Title>Title</Card.Title>
<Card.Body>본문</Card.Body>
<Card.Footer>
<Button>확인</Button>
</Card.Footer>
</Card>Modal / Drawer
<Modal open={open} onClose={() => setOpen(false)}>
<Modal.Header>제목</Modal.Header>
<Modal.Body>본문</Modal.Body>
<Modal.Footer><Button>확인</Button></Modal.Footer>
</Modal>
<Drawer open={open} onClose={...} position="right">
<Drawer.Header>필터</Drawer.Header>
<Drawer.Body>...</Drawer.Body>
<Drawer.Footer>...</Drawer.Footer>
</Drawer>Toast
<ToastContainer position="top-right">
{toasts.map((t) => (
<Toast key={t.id} type={t.type} onClose={() => remove(t.id)}>
{t.message}
</Toast>
))}
</ToastContainer>Tooltip
<Tooltip content="설정" position="bottom">
<button>⚙️</button>
</Tooltip>Tabs / Menu
<Tabs defaultValue="all">
<Tabs.List>
<Tabs.Trigger value="all">전체</Tabs.Trigger>
<Tabs.Trigger value="active">활성</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="all">...</Tabs.Content>
</Tabs>
<Menu>
<Menu.Item shortcut="Cmd+E">편집</Menu.Item>
<Menu.Divider />
<Menu.Item type="destructive">삭제</Menu.Item>
</Menu>Spinner / Alert
<Spinner size="md">Loading...</Spinner>
<Alert severity="warning" title="저장되지 않은 변경사항"
action={{ label: '저장', onClick: save }}
onClose={() => setOpen(false)}>
이 화면을 떠나면 변경사항이 사라집니다.
</Alert>접근성
모든 컴포넌트는 다음을 자동으로 처리합니다:
- ARIA 역할 + 속성
- 키보드 네비게이션 (Tabs · Menu · Select · Modal · Drawer)
- Focus trap + body scroll lock (Modal · Drawer)
- Portal 렌더링 (Modal · Drawer · Toast · Tooltip)
prefers-reduced-motion대응
상세 props/타입은 IDE의 IntelliSense (TypeScript) 또는 dist/index.d.ts 참조.
데모 페이지
demo/index.html을 브라우저로 열면 모든 컴포넌트의 인터랙티브 카탈로그 + 다크 토글을 볼 수 있습니다.
파이프라인
Figma Variables / Text Styles / Effect Styles
↓ Tokens Studio plugin (Sync + Push 버튼)
tokens.json (main)
↓ GitHub Actions 자동 실행
build/css/, build/ts/ 자동 commit
↓ npm install
자사 제품 (DuoCodi, DuoAcademy) / B2B 외주상세 셋업: docs/tokens-setup.md
폴더 구조
brand-assets/
├── tokens.json # ⭐ Source of truth (Tokens Studio 출력, W3C DTCG)
├── src/ # ⭐ React 컴포넌트 소스
│ ├── index.ts # public API
│ └── components/Button/ # Button.tsx + Button.css
├── build/ # 자동 생성 (CSS 토큰)
│ ├── css/light.css, dark.css
│ └── ts/*.ts, *.d.ts
├── dist/ # 자동 생성 (컴파일된 컴포넌트, tsup 출력)
│ ├── index.js (ESM), index.cjs (CJS)
│ ├── index.d.ts
│ └── index.css # 모든 컴포넌트 CSS 통합본
├── demo/index.html # 토큰 시각화 (Dark 토글)
├── scripts/build-tokens.mjs # Style Dictionary 빌드
├── tsup.config.ts # 컴포넌트 빌드 설정
├── .github/workflows/ # 자동 빌드 워크플로우
├── docs/ # 셋업 가이드
├── logos/ # 로고 (예정)
└── icons/ # 아이콘 (예정)로컬에서 빌드 (수동)
GitHub Actions가 자동 빌드하지만, 로컬에서 검증하려면:
npm install # 최초 1회
npm run build # tokens.json → build/, src/ → dist/
npm run build:tokens # 토큰만
npm run build:components # 컴포넌트만운영 규칙
main: Tokens Studio가 직접 push. 자동 빌드 트리거.feat/*: 도구 추가, 폴더 구조 변경 등 인프라 작업.- 자동화 범위: Tokens Studio Push 이후부터 build/ 갱신까지. Figma → Tokens Studio sync만 수동.
Owner
| 역할 | 이름 | GitHub |
|---|---|---|
| Primary | 최건의 | choiguneui |
| Secondary | 박도은 (Dean) | ilm52626 |
라이선스
내부 사용 (Private). © 2024-2026 비앤브이솔루션
