Colors
Typography
Font: Pretendard Variable
Heading 1 — 제목 텍스트 (4xl/bold)
Heading 2 — 제목 텍스트 (3xl/bold)
Heading 3 — 제목 텍스트 (2xl/semibold)
Heading 4 — 제목 텍스트 (xl/semibold)
Heading 5 — 제목 텍스트 (lg/medium)
Body — 본문 텍스트 (base/normal)
Small — 보조 텍스트 (sm/normal)
Caption — 캡션 텍스트 (xs/muted)
Variants
Gradient & Highlight
Sizes
States
Badge
Input & Textarea
Input
Textarea
Select
Radix Select
Card
기본 카드
카드 설명 텍스트
카드 본문 콘텐츠가 여기에 들어가요.
액션 카드
Footer가 있는 카드
버튼이 있는 카드 예시예요.
통계 카드
1,234
총 주문 수
Avatar

Table
| 주문번호 | 상품 | 상태 | 금액 |
|---|---|---|---|
| ORD-001 | N플레이스 트래픽 | 완료 | 50,000원 |
| ORD-002 | 블로그 리뷰 | 진행중 | 120,000원 |
| ORD-003 | 인스타 팔로워 | 취소 | 30,000원 |
Tabs
첫 번째 탭 콘텐츠예요. 개요 정보가 표시돼요.
Dialog
Sheet
Dropdown Menu
Popover
Calendar
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
Skeleton
Separator
Horizontal
위 영역
아래 영역
Vertical
Spacing & Border Radius
Border Radius
Shadow
States
서비스 전반에서 사용하는 로딩, 에러, 빈 상태 패턴이에요.
Loading — Spinner
Loader2 + animate-spin 조합. 버튼 내부에 넣어 비동기 처리 상태를 표시해요.
Loading — Skeleton 조합
카드 목록, 테이블 행, 상품 그리드 등 데이터 로딩 시 콘텐츠 형태에 맞춰 Skeleton을 배치해요.
Error States
경고(amber), 에러(red), 정보(blue) 3가지 스타일. border-[color]-200 bg-[color]-50/30 패턴.
Empty State
아직 주문 내역이 없어요
서비스를 이용하면 여기에 주문 내역이 표시돼요.
아이콘 + 제목 + 설명 + CTA 버튼 구성. 데이터가 없을 때 사용해요.
Toast
sonner 기반 토스트 알림. useToast() 훅으로 사용해요.import { useToast } from '@/hooks/use-toast'
const toast = useToast(); toast.success("저장이 완료됐어요."); toast.error("결제 처리 중 오류가 발생했어요."); toast.warning("포인트가 부족해요."); toast.info("새로운 알림이 있어요."); // API 에러 자동 번역 toast.errorFromApi(err, "기본 메시지");
translateErrorMessage()로 영문 API 에러를 자동 한글 변환해요 (Unauthorized → "로그인이 필요해요." 등).
Animations
globals.css에 정의된 커스텀 애니메이션이에요.
btn-glow (시머 + 글로우)
/* 사용법 */ <Button className="btn-glow">결제하기</Button> /* 효과: shimmer(빛 줄기 흐름) + glow-pulse(은은한 발광) */
service-detail-help-icon
<span className="service-detail-help-icon">?</span> /* 클릭 시 펄스: service-detail-help-icon--pulse 클래스 추가 */
animate-spin
Tailwind animate-spin — Loader2 아이콘과 함께 사용.
Forms
폼 필드 패턴: 필수 표시, 에러 메시지, 도움말 텍스트, 글자수 카운터.
필수 필드 + 도움말
카카오 비즈니스 → 광고계정 관리에서 확인할 수 있어요.
에러 상태 + 글자수 카운터
광고주ID는 숫자만 입력 가능해요.
16/1,000
동의 체크박스 패턴
Layout
서비스 페이지의 레이아웃 구조예요. 실제 컴포넌트는 components/layout/에 있어요.
전체 화면 구조
모바일: Sidebar → Sheet(슬라이드)로 전환. components/layout/mobile-nav.tsx
주문 폼 레이아웃 (3단)
grid grid-cols-1 md:grid-cols-3 — 모바일에서는 1단, 데스크탑에서는 3단. 오른쪽은 sticky top-20.
레이아웃 컴포넌트 목록
header.tsx로고, 네비, 알림벨, 유저메뉴, 포인트 잔액sidebar.tsxAPI 기반 동적 사이드바 메뉴mobile-nav.tsx모바일 햄버거 메뉴 (Sheet)notification-bell.tsx실시간 활동 알림announcement-bar.tsx상단 공지 배너server-status-banner.tsx서비스 점검 안내 배너SelectableCard
상품/옵션 선택에 사용하는 카드. 선택 시 파란 테두리 + 체크 아이콘이 표시돼요.import { SelectableCard } from '@/components/service-page/SelectableCard'
카카오 모먼트 광고비의 최대 8%를 환급받으세요.
카카오 키워드광고 광고비의 최대 8%를 환급받으세요.
카카오 브랜드검색 광고비의 최대 8%를 환급받으세요.
ProductCard
기존 상품 선택용 카드. SelectableCard보다 가볍고, ProductServicePage에서 사용돼요.import { ProductCard } from '@/components/service-page/ProductCard'
SelectableCard vs ProductCard: SelectableCard은 border-2 + 체크 아이콘으로 선택이 명확한 단독 선택 UI. ProductCard는 border-1로 가볍고, 리스트 내 빠른 선택에 적합해요.
SuccessModal
주문/신청 완료 시 표시하는 성공 모달. 녹색 체크 아이콘 + 제목 + 설명 + 액션 버튼.import { SuccessModal } from '@/components/service-page/SuccessModal'
ValuePropsGrid
서비스 핵심 혜택을 아이콘 + 텍스트 그리드로 보여주는 컴포넌트.import { ValuePropsGrid } from '@/components/service-page/ValuePropsGrid'
EligibilityCard
환급 가능/불가 항목을 체크/X 아이콘으로 보여주는 정보 카드.import { EligibilityCard } from '@/components/service-page/EligibilityCard'
환급 불가 영역만 집행 중이라면 신청해도 환급이 발생하지 않아요.
MobileBottomCTA
모바일에서만 표시되는 하단 고정 CTA 바. 데스크탑에서는 숨겨져요.import { MobileBottomCTA } from '@/components/service-page/MobileBottomCTA'
Props:
visible, label, onClick, loading, disabled, children (왼쪽 정보 영역)Pricing
포인트/가격 표시 규칙. @repo/shared의 formatPoint 사용.
포인트 표시
환급률/뱃지 표시
// 포맷 함수 (from @repo/shared) formatPoint(3500) → "3,500P" formatPoint(3500, true) → "3,500P" (suffix 포함) formatPrice(50000) → "50,000원" formatNumber(1234567) → "1,234,567"
Steps
서비스 진행 단계를 시각화하는 패턴이에요.
프로세스 스텝 (가로형)
진행 상태 스텝 (상태별 색상)
완료(CheckCircle2), 진행중(Loader2 spin), 대기(Circle)
Upload
파일 업로드 UI 패턴. hidden input + trigger button 조합이에요.
기본 업로드 버튼
업로드 완료 상태
// 패턴: hidden input + ref trigger <input ref={fileInputRef} type="file" accept="image/*" className="hidden" onChange={handleFileChange} /> <Button variant="outline" onClick={() => fileInputRef.current?.click()}> <Upload /> 파일 선택 </Button> // 업로드 API const formData = new FormData(); formData.append("files", file); formData.append("fileType", "npress-order"); await apiClient.upload("/v1/upload/files", formData);
Gradients
버튼, 히어로 배경, 오버레이에 사용하는 그라데이션 팔레트예요.
버튼 그라데이션
배경 그라데이션
오버레이 투명도
모달 딤: bg-black/50, 가벼운 딤: bg-black/20
InlineAlert
페이지 내 인라인 알림 카드. 현재 어드민에는 Alert 컴포넌트가 있고, web에서는 수동으로 조합해 사용해요.
// 색상 패턴 규칙 success: border-green-200 bg-green-50/30 + text-green-800 error: border-red-200 bg-red-50/30 + text-red-800 warning: border-amber-200 bg-amber-50/30 + text-amber-800 info: border-blue-200 bg-blue-50/30 + text-blue-800
Responsive
Tailwind 모바일 퍼스트 반응형 패턴. 기본 = 모바일, md: (768px~) = 데스크탑.
브레이크포인트
자주 쓰는 반응형 패턴
hidden md:flex모바일 숨김, 데스크탑 표시 (사이드바)md:hidden모바일만 표시 (햄버거 메뉴)grid-cols-1 md:grid-cols-3모바일 1단 → 데스크탑 3단grid-cols-2 sm:grid-cols-4모바일 2단 → 태블릿+ 4단p-3 md:p-6모바일 좁은 패딩 → 데스크탑 넓은 패딩text-[11px] md:text-xs모바일 11px → 데스크탑 12pxfixed bottom-16 ... md:hidden모바일 고정 CTA (MobileBottomCTA)TaskStatus
주문/태스크 처리 상태를 표시하는 뱃지 4종이에요.
// 상태 색상 규칙 PENDING: gray-100/600 + Clock PROCESSING: blue-50/600 + Loader2 spin COMPLETED: green-50/600 + CheckCircle2 FAILED: red-50/600 + XCircle
AdminRef
어드민(apps/admin/src/components/ui/)에만 있는 컴포넌트. 웹에서 필요하면 참고해서 추가할 수 있어요.
alert.tsx인라인 알림 (success/error/warning/info). 닫기 버튼, 아이콘, 제목 지원.
switch.tsx토글 스위치 (default/small). SwitchRow로 라벨+설명 조합 가능.
tooltip.tsx호버 툴팁. top/bottom/left/right 4방향. 최대 260px.
confirm-dialog.tsx삭제 등 위험 액션 확인 모달. async 처리, 로딩 상태 지원.
number-input.tsx콤마 포맷 숫자 입력. min/max 검증. 1000 → 1,000 자동 변환.
Timing
프로젝트에서 사용하는 애니메이션 타이밍 가이드라인이에요.
| 용도 | Duration | Easing | 예시 |
|---|---|---|---|
| 호버/포커스 | 0.2s | ease | 버튼 hover scale, 카드 shadow |
| 모달/시트 진입 | 0.3s | ease-out | Dialog, Sheet 열기 |
| 아이콘 펄스 | 0.4s | ease | service-detail-help-icon 클릭 |
| 스크롤 이동 | smooth | — | scrollIntoView({ behavior: 'smooth' }) |
| 시머 효과 | 2.5s | ease-in-out | btn-glow shimmer |
| 글로우 펄스 | 2s | ease-in-out | btn-glow box-shadow 호흡 |
| 스피너 | 1s | linear | animate-spin (Loader2) |
원칙: 인터랙션 피드백은 0.2s, 패널 전환은 0.3s, 장식 애니메이션은 2~2.5s infinite.