Design System
When to Use
- Styling KKOOKK components with Tailwind CSS v4.0
- Implementing KKOOKK-specific layouts and interactions
- Adding accessibility (a11y) features
- Building mobile-optimized web UI
Core Design Principles
- Tactile Certainty (물리적 확신): Mimic physical stamp sensation through visual feedback
- Paperless Freedom (지갑의 자유): Light, mobile-first, no-install PWA experience
- Human Bridge (연결의 가치): Warm digital connection between owners and customers
UI Component Library
- Base: shadcn/ui (Radix UI primitives + Tailwind)
- Install components as needed:
npx shadcn@latest add button dialog ... - Components copied to
src/components/ui/— customize freely - Do NOT install other UI libraries without approval
When to Use shadcn/ui
| Use shadcn/ui | Build from scratch |
|---|---|
| Dialog, Modal, Sheet | Simple presentational components |
| Dropdown, Select, Combobox | KKOOKK-specific stamp card UI |
| Toast, Alert | Custom animations with Framer Motion |
| Form inputs (with validation) | Layout components |
Tailwind CSS v4.0
Configuration
All custom colors defined in frontend/src/assets/styles/index.css using @theme
Quick reference:
- Primary CTA:
bg-kkookk-orange-500(#FF4D00) - Owner:
bg-kkookk-indigo,text-kkookk-steel - Customer:
bg-kkookk-sand,text-kkookk-yellow - Background:
bg-kkookk-paper(#FAF9F6) - Text:
text-kkookk-navy(#1A1C1E)
shadcn/ui vs KKOOKK Colors
| Context | Use | Example |
|---|---|---|
| shadcn components | bg-primary, bg-destructive |
Dialog, Alert from shadcn |
| KKOOKK custom | bg-kkookk-orange-500 |
StampCard, custom buttons |
| Buttons | .btn-primary from index.css |
CTA buttons |
Why: shadcn uses CSS variables (--primary), custom components use direct color classes.
Class Organization Order
- Layout (flex/grid, position)
- Spacing (p/m/gap)
- Size (w/h)
- Typography (text-, font-)
- Colors (bg-, text-, border-*)
- Effects (shadow, rounded, opacity)
- States (hover:, focus:, active:, disabled:)
Conditional Classes
import { twMerge } from 'tailwind-merge';
<div className={twMerge(
"flex items-center p-4 rounded-xl",
isActive && "bg-kkookk-orange-500 text-white",
isDisabled && "opacity-50 cursor-not-allowed"
)}>
Pattern Extraction
If a class combination appears 3+ times, extract it to:
- A reusable component, OR
- A utility in
@layer utilities(see.btn-primaryinindex.css)
Color System
Color Usage
- Primary CTA:
bg-kkookk-orange-500(#FF4D00) - Owner UI: Indigo (#2E58FF) + Steel Gray (#64748B) - professional tone
- Customer UI: Sand (#F5F5F0) + Yellow (#FFD600) - warm, friendly
- Error:
text-kkookk-red(#DC2626) - Warning:
text-kkookk-amber(#F59E0B)
WCAG AAA Compliance
- Minimum 7:1 contrast ratio
- Navy Black on Paper White: 14.8:1 ✅
- Test under 400+ lux (outdoor)
Typography
Type Scale
| Category | Class | Size | Weight | Usage |
|---|---|---|---|---|
| Display Hero | text-6xl |
60px | ExtraBold (800) | Stamp count |
| Display Sub | text-4xl |
36px | ExtraBold (800) | Rewards |
| Heading 1 | text-2xl |
24px | SemiBold (600) | Page title |
| Heading 2 | text-xl |
20px | SemiBold (600) | Sections |
| Body 1 | text-base |
16px | Medium (500) | Main text |
| Body 2 | text-sm |
14px | Regular (400) | Supporting |
| Caption | text-xs |
12px | Regular (400) | Micro-copy |
Font: Pretendard Variable
Components
KKOOKK Stamp Card
<div className="p-4 rounded-2xl shadow-lg bg-white">
Buttons
Use utility classes from index.css:
.btn-primary- Orange CTA.btn-secondary- Indigo.btn-outline,.btn-ghost
Requirements:
- Height:
h-14(56px) - prevents accidental taps - Radius:
rounded-2xl(16px) - Active:
active:scale-95- tactile feedback - Anti-double-tap: Disable 300ms after click
const [isProcessing, setIsProcessing] = useState(false);
const handleClick = async () => {
if (isProcessing) return;
setIsProcessing(true);
try {
await action();
} finally {
setTimeout(() => setIsProcessing(false), 300);
}
};
Accessibility
Minimum Requirements
| Requirement | Implementation | KKOOKK Standard |
|---|---|---|
| Labels | <label htmlFor="id"> |
All inputs |
| Focus rings | focus:ring-4 focus:ring-kkookk-orange-500/50 |
All interactive |
| ARIA | aria-label, aria-modal |
Dialogs, icons |
| Touch targets | WCAG 44px minimum | 56px (h-14) |
| Contrast | WCAG AAA 7:1 | All text |
Focus States
<button className="focus:outline-none focus:ring-4 focus:ring-kkookk-orange-500/50 focus:ring-offset-2">
Form Labels
<label htmlFor="store-name" className="text-sm font-medium">매장 이름</label>
<input id="store-name" aria-required="true" aria-invalid={!!errors.storeName} />
{errors.storeName && <p id="store-name-error" className="text-sm text-kkookk-red">{errors.storeName.message}</p>}
Icon Buttons
<button aria-label="닫기"><CloseIcon /></button>
Keyboard Navigation
- Tab order must be logical
- Escape closes modals
- Enter/Space activates buttons
Animations
Signature: Stamp Impact
<motion.div animate={{ scale: [0.8, 1.1, 1.0] }} transition={{ duration: 0.2 }}>
Page Transitions
<motion.div initial={{ x: '100%' }} animate={{ x: 0 }} exit={{ x: '100%' }}>
Modal Slide-up
<motion.div initial={{ y: '100%' }} animate={{ y: 0 }} className="fixed inset-x-0 bottom-0 rounded-t-3xl">
Polling Pulse
<motion.div animate={{ scale: [1, 1.05, 1], opacity: [1, 0.8, 1] }} transition={{ duration: 1.5, repeat: Infinity }}>
State Matrix
| State | Classes | Usage |
|---|---|---|
| Default | shadow-md rounded-2xl |
Idle |
| Hover | hover:shadow-lg |
Desktop |
| Active | active:scale-95 |
Touch feedback |
| Loading | animate-pulse opacity-70 |
Processing |
| Disabled | opacity-50 cursor-not-allowed |
Unmet conditions |
Page Type Guidelines
Owner Pages (백오피스)
- Tone: Professional, efficient
- Colors: Indigo, Steel Gray
- Layout: Desktop-first, 2-3 column grid
- CTA: Top-right (+ New)
<div className="flex items-center justify-between mb-6">
<h1 className="text-2xl font-semibold">Title</h1>
<button className="btn-secondary">+ New</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
Customer Pages (지갑)
- Tone: Warm, encouraging
- Colors: Orange, Sand, Yellow
- Layout: Mobile-first, single column
- CTA: Fixed bottom, full width
<div className="px-4 pt-8 pb-6 text-center">
<p className="text-6xl font-extrabold text-kkookk-orange-500">12</p>
<p className="text-base text-kkookk-steel mt-2">개 적립</p>
</div>
<div className="fixed bottom-0 inset-x-0 p-4 bg-white border-t">
<button className="btn-primary w-full">Action</button>
</div>
Terminal Pages (단말)
- Tone: Clear, fast decisions
- Colors: White background, Orange accent
- Layout: Center-aligned, large elements
- CTA: Approval/Reject side-by-side
<div className="min-h-screen bg-white flex flex-col items-center justify-center p-6">
<div className="flex gap-4">
<button className="h-14 px-8 bg-kkookk-steel text-white">거절</button>
<button className="h-14 px-8 bg-kkookk-orange-500 text-white">승인</button>
</div>
</div>
Edge Cases
Empty State
<div className="flex flex-col items-center gap-4 py-8 text-center">
<EmptyIcon className="w-16 h-16 text-slate-400" />
<p className="text-base">아직 스탬프가 없어요</p>
<button className="btn-primary">첫 도장 모으러 가기</button>
</div>
Error State
<div className="flex flex-col items-center gap-4 py-8">
<ErrorIcon className="w-16 h-16 text-kkookk-red" />
<p className="text-base">네트워크 연결을 확인해주세요</p>
<button className="btn-primary" 시도</button>
</div>
Mobile Optimization
- Outdoor visibility: High contrast (Navy on Paper = 14.8:1)
- Touch targets: Minimum 56px (
h-14) - Spacing: Minimum 8px between targets (
gap-2) - Safe areas:
px-4horizontal margin - Mobile-first: Design for 375px, enhance for larger
Instructions for Claude
- Always check
index.cssfor colors and utilities - Apply class organization order for every component
- Use
twMergefor conditional classes - Extract patterns after 3+ repetitions
- Every CTA needs anti-double-tap (300ms disable)
- All interactive elements need focus rings
- Mobile-first: 375px base, enhance with
md:,lg: - If violates accessibility, suggest compliant alternative
- When creating pages: Match page type (Owner/Customer/Terminal) guidelines
- When adding animations: Use Framer Motion for complex, CSS classes for simple