MarketPilot Design System

UI 컴포넌트 & 스타일 가이드

v1.2

Colors

Core

Primary#00B0F0
Primary Hover#009dd6
Primary Light#e6f7fd
Destructive#ef4444
Success#22c55e
Warning#f59e0b
Background#ffffff
Foreground#0a0a0a
Muted#f5f5f5
Muted FG#737373
Border#e5e5e5
Accent#f5f5f5

Social / Brand

Aa
Kakao#FEE500
Aa
Kakao Hover#FDD835
Aa
YouTube#FF0000
Aa
YouTube Hover#cc0000

Glow / Shadow

Glow--shadow-glow
Glow LG--shadow-glow-lg
Primary--shadow-primary

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)

Button

Variants

Gradient & Highlight

Sizes

States

Badge

Default
Secondary
Outline
Destructive
Success
Warning

Input & Textarea

Input

Textarea

Select

Radix Select

Card

기본 카드

카드 설명 텍스트

카드 본문 콘텐츠가 여기에 들어가요.

액션 카드

Footer가 있는 카드

버튼이 있는 카드 예시예요.

통계 카드

1,234

총 주문 수

Avatar

User
CN
MP
AB
XL

Table

주문번호상품상태금액
ORD-001N플레이스 트래픽
완료
50,000원
ORD-002블로그 리뷰
진행중
120,000원
ORD-003인스타 팔로워
취소
30,000원

Tabs

첫 번째 탭 콘텐츠예요. 개요 정보가 표시돼요.

Dialog

범용 모달 컴포넌트. body scroll lock 내장.hideCloseButton,overlayClassName,closeOnOverlayClick props 지원.

Props: hideCloseButton X 버튼 숨김 | overlayClassName 오버레이 스타일 (예: bg-black/40) | closeOnOverlayClick=false 오버레이 클릭 닫기 비활성화

ConfirmDialog

확인/경고 모달. Dialog 래핑. async onConfirm 시 자동 로딩 상태.
import { ConfirmDialog } from '@/components/ui/confirm-dialog'

Props: onConfirm Promise 반환 시 자동 로딩 | confirmVariant "destructive" | "default" | "outline" | loading 외부 로딩 제어

SuccessDialog

성공/완료 모달. 아이콘 + 제목 + 설명 + 액션 버튼. Dialog 래핑.
import { SuccessDialog } from '@/components/ui/success-dialog'

Props: icon "success" (녹색) | "warning" (주황) | actions { label, onClick, variant? }[] | children 추가 콘텐츠 삽입 가능

LoadingOverlay

로딩 차단 오버레이. 닫기 불가, 자동 소멸. body scroll lock 내장.
import { LoadingOverlay } from '@/components/ui/loading-overlay'

Props: open 표시 여부 | message 메인 메시지 | description 보조 설명 | progressPercent 0~100 진행 바 | footer 하단 추가 콘텐츠

Sheet

Dropdown Menu

Popover

기본 Popover는 padding이 0이에요. 콘텐츠마다 p-3·w-[min(18rem,calc(100vw-2rem))] 등을 명시해야 해요. 간단한 (i) 아이콘 + 설명 패턴은 아래 InfoPopover 사용.

InfoPopover

(i) 아이콘을 누르면 상세 안내가 뜨는 헬퍼예요. padding·모바일 안전 폭·접근성이 미리 적용돼 있어요.
import { InfoPopover } from '@/components/ui/info-popover'

주문 접수 안내

Calendar

2026년 5월

DatePickerInput

날짜 선택 입력 컴포넌트. Calendar + Popover 조합. YYYY-MM-DD 형식으로 값을 주고받아요.
import { DatePickerInput } from '@/components/ui/date-picker-input'

Props: value YYYY-MM-DD | onChange (YYYY-MM-DD) => void | minDate / maxDate 범위 제한 | disabled

Skeleton

Separator

Horizontal

위 영역

아래 영역

Vertical

왼쪽
가운데
오른쪽

ScrollArea

오버플로우 스크롤 영역. 긴 콘텐츠를 제한된 높이 안에서 스크롤할 때 사용해요.
import { ScrollArea } from '@/components/ui/scroll-area'

항목 1
태그
항목 2
태그
항목 3
태그
항목 4
태그
항목 5
태그
항목 6
태그
항목 7
태그
항목 8
태그
항목 9
태그
항목 10
태그
항목 11
태그
항목 12
태그
항목 13
태그
항목 14
태그
항목 15
태그

className으로 높이 제한. 내부 콘텐츠가 넘치면 자동 스크롤.

ProgressLog

진행 로그 컴포넌트. 실시간 작업 상태를 시각화해요. 새 로그 추가 시 자동 스크롤.
import { ProgressLog } from '@/components/ui/progress-log'

Card 래핑 (기본)

키워드 분석 로그

키워드 분석을 시작했어요.14:30:01
총 15개 키워드를 수집��어요.14:30:03
파이가 순위 데이터를 분석하고 있어요...14:30:05
3개 키워드에서 순위 하락이 감지됐��요.14:30:08
분석 리포트가 생성됐어요.14:30:12

bare 모드 (카드 없이)

키워드 분석을 시작했어요.14:30:01
총 15개 키워드를 수집��어요.14:30:03
파이가 순위 데이터를 분석하고 있어요...14:30:05
3개 키워드에서 순위 하락이 감지됐��요.14:30:08
분석 리포트가 생성됐어요.14:30:12

Props: logs ProgressLogEntry[] | title 카드 헤더 제목 | maxHeight 최대 높이 (px) | bare 카드 없이 로그만 렌더링

ProgressLogEntry: message + type (info/success/error) + time? + detail? (접이식 상세)

MarkdownContent

마크다운 렌더링 컴포넌트. 파이 AI 응답, 채팅 말풍선 등에서 사용해요.
import { MarkdownContent } from '@/components/ui/markdown-content'

렌더링 결과

분석 결과를 알려드릴게요.

현재 등록된 키워드 중 상위 3개 키워드의 순위 변동이에요:

키워드현재 순위변동
강남 맛집3위+2
홍대 카페7위-1
성수동 브런치12위신규

순위가 상승한 키워드가 있어요. 자세한 내용은 리포트를 확인해주세요.

ranking_score 기반으로 계산됐어요.

원본 마크다운

**분석 결과를 알려드릴게요.**

현재 등록된 키워드 중 상위 3개 키워드의 순위 변동이에요:

| 키워드 | 현재 순위 | 변동 |
|--------|----------|------|
| 강남 맛집 | 3위 | +2 |
| 홍대 카페 | 7위 | -1 |
| 성수동 브런치 | 12위 | 신규 |

> 순위가 상승한 키워드가 있어요. 자세한 내용은 리포트를 확인해주세요.

`ranking_score` 기반으로 계산됐어요.

지원 문법: 볼드, 이탤릭, 리스트, 테이블, 인라인 코드, 코드 블록, 블록인용, 링크 (새 탭), 수평선.
플러그인: remark-gfm (GitHub Flavored Markdown — 테이블, 취소선 등)

Spacing & Border Radius

Border Radius

sm6px
md8px
lg12px
xl16px
full9999px

Shadow

sm
default
md
lg

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

?hover 시 scale(1.15) 확대. 클릭 시 pulse 애니메이션.

<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/에 있어요.

전체 화면 구조

Header로고 · 네비 · 알림벨 · 유저메뉴
Sidebar
메뉴 1
메뉴 2
메뉴 3
Page Content
각 페이지의 고유 콘텐츠 영역

모바일: Sidebar → Sheet(슬라이드)로 전환. components/layout/mobile-nav.tsx

주문 폼 레이아웃 (3단)

왼쪽: 폼 영역 (col-span-2)
계정 정보 카드
요청사항 카드
오른쪽: Sticky 사이드바
신청 요약 + CTA

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'

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'

캠페인은 내가 직접 관리
💰광고비의 최대 8% 환급
🎁환급금은 마켓파일럿 포인트로 지급
🔄신청 1회 → 매월 자동 적용

EligibilityCard

환급 가능/불가 항목을 체크/X 아이콘으로 보여주는 정보 카드.
import { EligibilityCard } from '@/components/service-page/EligibilityCard'

환급 가능 광고 영역
파워링크
쇼핑검색광고
브랜드검색광고
GFA (디스플레이)
플레이스 검색광고
파워콘텐츠 (블로그)

환급 불가 영역만 집행 중이라면 신청해도 환급이 발생하지 않아요.

MobileBottomCTA

모바일에서만 표시되는 하단 고정 CTA 바. 데스크탑에서는 숨겨져요.
import { MobileBottomCTA } from '@/components/service-page/MobileBottomCTA'

모바일 기기(768px 미만)에서만 보여요. 화면 하단에 고정된 카드 형태의 CTA 버튼이에요.
Props: visible, label, onClick, loading, disabled, children (왼쪽 정보 영역)

Pricing

포인트/가격 표시 규칙. @repo/sharedformatPoint 사용.

포인트 표시

단가50P
할인가
100P80P
총 결제 금액3,500P

환급률/뱃지 표시

최대 8% 환급
신청 무료
50% 할인
무료

// 포맷 함수 (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 조합이에요.

기본 업로드 버튼

선택된 파일 없음

업로드 완료 상태

product-image-final.jpg

// 패턴: 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

버튼, 히어로 배경, 오버레이에 사용하는 그라데이션 팔레트예요.

버튼 그라데이션

Bluefrom-primary to-[#0066FF]
Warmfrom-[#FF6B6B] to-[#FF8E53]
Purplefrom-[#7C3AED] to-[#DB2777]

배경 그라데이션

Hero Purple
Subtle Primary

오버레이 투명도

20%
30%
50%
White 90%

모달 딤: bg-black/50, 가벼운 딤: bg-black/20

InlineAlert

페이지 내 인라인 알림 카드. 현재 어드민에는 Alert 컴포넌트가 있고, web에서는 수동으로 조합해 사용해요.

이관 신청이 완료됐어요.
결제 처리 중 오류가 발생했어요.
포인트가 부족해요. 충전 후 다시 시도해주세요.
이 서비스는 영업일 기준 1~2일 내 처리돼요.

// 색상 패턴 규칙 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~) = 데스크탑.

브레이크포인트

모바일< 768px
기본 스타일
데스크탑≥ 768px
md: 접두어

자주 쓰는 반응형 패턴

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 → 데스크탑 12px
fixed 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/)에만 있는 컴포넌트. 웹에서 필요하면 참고해서 추가할 수 있어요.

Alertalert.tsx

인라인 알림 (success/error/warning/info). 닫기 버튼, 아이콘, 제목 지원.

저장됐어요.
Switchswitch.tsx

토글 스위치 (default/small). SwitchRow로 라벨+설명 조합 가능.

OFFON
Tooltiptooltip.tsx

호버 툴팁. top/bottom/left/right 4방향. 최대 260px.

툴팁 내용이에요
NumberInputnumber-input.tsx

콤마 포맷 숫자 입력. min/max 검증. 1000 → 1,000 자동 변환.

Timing

프로젝트에서 사용하는 애니메이션 타이밍 가이드라인이에요.

용도DurationEasing예시
호버/포커스0.2sease버튼 hover scale, 카드 shadow
모달/시트 진입0.3sease-outDialog, Sheet 열기
아이콘 펄스0.4seaseservice-detail-help-icon 클릭
스크롤 이동smoothscrollIntoView({ behavior: 'smooth' })
시머 효과2.5sease-in-outbtn-glow shimmer
글로우 펄스2sease-in-outbtn-glow box-shadow 호흡
스피너1slinearanimate-spin (Loader2)

원칙: 인터랙션 피드백은 0.2s, 패널 전환은 0.3s, 장식 애니메이션은 2~2.5s infinite.