YumYum 디자인 시스템 — 상태 디자인 (Empty / Loading / Error)
냠냠픽업 디자인 시스템 State Design 가이드 작성일: 2026-05-13 최종 갱신: 2026-05-18 — Skeleton 배경색 #E8E5DE → #E5E5E5 cool gray v3 마이그레이션 버전: v3.0 (cool gray v3 시리즈)
1. 디자인 원칙
1.1 핵심 컨셉
- 같은 레이아웃 패턴 — Icon + Heading + Description + CTA (3가지 상태 공통)
- 친근한 톤 (Empty), 안내하는 톤 (Error) — 비난 X, 격려/해결책 O
- CTA는 항상 다음 행동 명시 — 사용자가 막히지 않게
- Loading은 Skeleton 우선 — 인지된 속도 향상
1.2 왜 이게 중요한가
Empty/Loading/Error는 UX의 "엣지 케이스"지만, 실제로 사용자가 자주 만나는 화면. 잘 만들면 답답한 순간을 좋은 경험으로 전환 가능. 디자인 시스템에서 미리 정의해두면 일관성과 품질 모두 확보.
2. 공통 레이아웃
3가지 상태 모두 같은 패턴 사용:
[ Icon (48-64px) ]
[ Heading ]
[ Description ]
[ CTA Button ]2.1 Specs
| 요소 | Spec |
|---|---|
| Icon | 48-64px · Secondary(neutral-500) 또는 Disabled(neutral-400) |
| Heading | heading-sm (18px SemiBold) 또는 heading-md (22px) |
| Description | body-sm (14px Regular) · neutral-500 · 2줄 이내 |
| CTA Button | Primary Medium · 명확한 동사 |
| 영역 padding | space-xl (24px) 이상 |
| Heading-Description gap | space-xs (4px) |
| Description-CTA gap | space-lg (16px) |
3. Empty State — 친근한 톤
사용자가 컨텐츠 없는 화면을 봤을 때. 다음 행동으로 자연스럽게 안내.
3.1 YumYum 주요 케이스
| 상황 | Icon | Heading | Description | CTA |
|---|---|---|---|---|
| 즐겨찾기 비어있음 | ti-heart | 즐겨찾기가 비어있어요 | 마음에 드는 매장을 즐겨찾기에 담아보세요 | 매장 둘러보기 |
| 주문 내역 없음 | ti-shopping-bag | 아직 주문 내역이 없어요 | 매장가격 그대로, 첫 주문을 시작해보세요 | 메뉴 보러가기 |
| 검색 결과 없음 | ti-search | 검색 결과가 없어요 | 다른 키워드로 다시 검색해보시겠어요? | 필터 변경 |
| 장바구니 비어있음 | ti-shopping-cart | 장바구니가 비어있어요 | 맛있는 메뉴를 담아볼까요? | 메뉴 둘러보기 |
| 알림 없음 | ti-bell | 새 알림이 없어요 | 새로운 소식이 도착하면 알려드릴게요 | (CTA 없음) |
| 쿠폰 없음 | ti-ticket | 사용 가능한 쿠폰이 없어요 | 이벤트를 통해 쿠폰을 받아보세요 | 이벤트 보기 |
3.2 메시지 톤 가이드
❌ "아무것도 없습니다" ✅ "X가 비어있어요, Y해보세요"
❌ "데이터가 없음" ✅ "아직 주문 내역이 없어요"
❌ 비난하는 어조 ✅ 격려하고 다음 단계 제시
❌ 평서체 ("~합니다") ✅ 친근체 ("~해요")
4. Loading State — 3가지 방법
4.1 Skeleton ⭐ (가장 추천)
콘텐츠 구조를 미리 보여줌. 인지된 속도가 빨라짐.
Specs:
- Background:
neutral-200#E5E5E5 - Border radius: 실제 콘텐츠와 동일
- Animation: opacity 1 ↔ 0.4 (1.5s ease-in-out infinite)
- 위치/크기: 실제 콘텐츠와 정확히 일치
적용처:
- 매장 카드 리스트
- 메뉴 카드 그리드
- 주문 내역
- 마이페이지
CSS 예시:
@keyframes skeleton-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
.skeleton {
background: var(--color-neutral-200);
border-radius: var(--radius-xs);
animation: skeleton-pulse 1.5s ease-in-out infinite;
}4.2 Spinner — 짧은 로딩
작은 영역, 2초 이내 완료 예상되는 작업.
Specs:
- Size: 20-24px
- Track color:
neutral-200 - Active color:
neutral-800 - Border width: 2px
- Animation: 0.8s linear infinite rotation
적용처:
- 버튼 안 (결제 처리 중)
- 인라인 로딩
- 작은 영역 (입력 검증 중)
CSS 예시:
@keyframes spinner {
to { transform: rotate(360deg); }
}
.spinner {
width: 20px;
height: 20px;
border: 2px solid var(--color-neutral-200);
border-top-color: var(--color-neutral-800);
border-radius: 50%;
animation: spinner 0.8s linear infinite;
}4.3 Progress Bar — 실제 진행률
명확한 % 표시 가능한 작업.
Specs:
- Height: 6px
- Track:
neutral-200 - Fill:
yellow-500(Brand 컬러) - Border radius:
radius-full
적용처:
- 이미지 업로드
- 파일 다운로드
- 단계별 폼 진행률
5. Error State — 안내하는 톤
문제 상황을 명확히 알리고, 해결 방법과 재시도 옵션 제공.
5.1 YumYum 주요 케이스
| 상황 | Icon | Heading | Description | CTA |
|---|---|---|---|---|
| 네트워크 끊김 | ti-wifi-off | 연결 상태를 확인해주세요 | 인터넷이 불안정해요. 다시 시도해주세요 | 다시 시도 |
| 결제 실패 | ti-alert-triangle | 결제에 실패했어요 | 카드 정보를 확인하고 다시 시도해주세요 | 다시 시도 |
| 404 페이지 | ti-mood-confuzed | 페이지를 찾을 수 없어요 | 주소가 잘못되었거나 삭제된 페이지예요 | 홈으로 |
| 서버 오류 | ti-refresh-alert | 매장 정보를 불러올 수 없어요 | 잠시 후 다시 시도해주세요 | 이전으로 / 다시 시도 |
| 권한 없음 | ti-lock | 접근 권한이 없어요 | 로그인 후 다시 이용해주세요 | 로그인 |
5.2 에러 메시지 톤 가이드
❌ "잘못된 요청입니다" ✅ "X 때문에 문제가 생겼어요, Y해보세요"
❌ "Error 500: Internal Server Error" ✅ "잠시 후 다시 시도해주세요"
❌ 사용자 잘못으로 느껴지는 표현 ✅ 시스템 문제임을 부드럽게 안내
재시도 옵션 필수: 사용자가 막히지 않게.
5.3 인라인 에러 (폼 내부)
폼 안에서의 에러는 별도 처리. 무채색 시스템 유지:
- Input border:
1.5px solid neutral-800(두꺼운 검정) - 메시지:
neutral-800+ti-alert-triangle아이콘 - 색이 아닌 두꺼운 보더 + 아이콘으로 표현
<input type="text" class="input-error">
<div class="error-message">
<i class="ti ti-alert-triangle"></i>
<span>올바른 이메일 형식이 아닙니다</span>
</div>6. 사용 원칙 (3가지 공통)
6.1 일관성
- 같은 레이아웃 패턴 유지 (Icon + Heading + Description + CTA)
- 같은 영역 크기 (Empty와 Error는 거의 동일하게 보여야)
- Skeleton은 실제 콘텐츠와 정확히 같은 위치
6.2 톤
- Empty: 친근하고 격려하는 톤
- Loading: (텍스트 거의 없음, 시각적 신호만)
- Error: 안내하고 사용자 잘못 아니라는 인상
6.3 CTA
- 항상 다음 행동 명시
- 동사로 시작 ("둘러보기", "다시 시도", "메뉴 보기")
- "확인" 같은 막연한 표현 X
6.4 아이콘
- 48-64px이 적절. 너무 크면 부담
- Stratis UI Icons에서 의미가 명확한 것 선택
- Secondary 또는 Disabled 컬러 (강조하지 X)
6.5 Loading 우선순위
- Skeleton (가능하면 항상)
- Progress (실제 진행률 알 때)
- Spinner (위 둘이 안 맞을 때)
7. 컴포넌트 조합 매트릭스
| 상태 | 사용 토큰 |
|---|---|
| Empty | Icon (48-64px, neutral-400/500) + heading-sm + body-sm + Button Medium |
| Loading Skeleton | neutral-200 bg + animation |
| Loading Spinner | neutral-200/800 + animation |
| Progress | neutral-200 track + yellow-500 fill + radius-full |
| Error | Icon (48-64px, neutral-500) + heading-sm + body-sm + Button Medium |
| Inline Error | Input(1.5px neutral-800 border) + alert-triangle + neutral-800 text |
8. 다음 단계
상태 디자인까지 정리되면 디자인 시스템의 "엣지 케이스"까지 다 잡힘. 남은 후속 작업:
- [ ] Motion — 애니메이션 duration, easing (transition, slide, fade)
- [ ] Accessibility Guidelines — 접근성 체크리스트
- [ ] 실제 화면 디자인 적용 — 만든 시스템으로 핵심 화면 만들기
이 문서는 살아있는 문서입니다. 새로운 Empty/Error 케이스 발견 시 업데이트해주세요.