# HourBars

값 축이 있는 막대 차트다. 학습 시간(시간·분)이나 푼 문제 수를 날짜별로 보여 주고, 고른 막대 위에 말풍선이 뜬다.

- 분류: 차트
- 가져오기: `import { HourBars } from '@/ui/charts'`
- 코드 위치: `apps/mobile/src/ui/charts.tsx:207` (Mordy 저장소 60df633)
- 웹 페이지: https://developers.moring.co/tds/components/hour-bars

## 미리보기

실제 컴포넌트를 그린 화면은 https://developers.moring.co/tds/components/hour-bars 에서 볼 수 있다. 서비스 색 선택기로 Mordy, Morit 색을 바꿔 볼 수 있다.

## 언제 쓰는가

### 쓴다
- 일별·주별 학습 시간 또는 푼 문제 수를 비교할 때 쓴다.
- `format="count"`는 문제 수, `"time"`(기본)은 초 단위 학습 시간이다.
- 목표선(`goal`)을 점선으로 그을 수 있다.

### 쓰지 않는다
- 시간 순서가 없는 항목 비교에는 쓰지 않는다.
- 막대가 14개를 넘으면 쓰지 않는다. `labelEvery`로 라벨을 줄이거나 `AreaLine`을 쓴다.
- 말풍선 없이 값을 숨기지 않는다. 막대를 눌러 값을 볼 수 있게 한다.

## 종류

| 이름 | 설명 |
| --- | --- |
| 기본 | 둥근 막대(모서리 = 폭의 절반). 고른 막대는 `gradient`, 나머지는 `primary` 20~34% 투명. |
| block | 리포트 모양. 각진 막대(모서리 7), 네이비 말풍선, 고른 요일 라벨이 `primary`. |
| 축 형식 | `time`: 0h·1h·2h… 또는 분. `count`: 0·중간값·최댓값(정수). |

## 크기

| 이름 | 값 | 설명 |
| --- | --- | --- |
| 기본 | 막대 높이 140, 막대 폭 22 | 위쪽 34는 말풍선 자리다. |

## 상태

| 상태 | 모습과 동작 |
| --- | --- |
| 막대 선택 | 막대를 누르면 그 막대가 진해지고 위에 말풍선("2시간 34분", "48문제")이 뜬다. 다시 누르면 해제. |
| 값 0 | 높이 4의 `track` 점선 막대. |

## 사용 방법

### 학습 시간

```tsx
import { HourBars } from '@/ui/charts';

<HourBars
  data={days.map((d) => ({ label: d.weekday, value: d.seconds }))}
  selected={sel}
  onSelect={setSel}
  bubble={sel != null ? durationShort(days[sel].seconds) : null}
/>
```

### 푼 문제 수와 목표선

```tsx
<HourBars format="count" goal={50} block data={days.map((d) => ({ label: d.weekday, value: d.answered }))} selected={sel} onSelect={setSel} bubble={`${days[sel]?.answered}문제`} />
```

### 속성(props)

| 이름 | 타입 | 기본값 | 필수 | 설명 |
| --- | --- | --- | --- | --- |
| `data` | `{ label: string; value: number; part?: number; part2?: number; a11y?: string }[]` | — | 필수 | 막대 목록. 각 항목: `label`, `value`(초 또는 개수), `part`/`part2`(위·아래에 겹쳐 그릴 부분 값), `a11y`(접근성 이름). |
| `height` | `number` | `140` | 선택 | 막대 영역 높이(px). 기본 140. |
| `selected` | `number \| null` | — | 선택 | 선택된 막대의 번호(없으면 `null`). |
| `onSelect` | `(i: number) => void` | — | 선택 | 막대를 눌렀을 때 번호와 함께 호출된다. |
| `bubble` | `string \| null` | — | 선택 | 선택된 막대 위에 띄울 글자. |
| `labelEvery` | `number` | `1` | 선택 | N번째 막대마다 라벨을 쓴다. 기본 1. |
| `barWidth` | `number` | `22` | 선택 | 막대 폭(px). 기본 22. |
| `format` | `'time' \| 'count'` | `'time'` | 선택 | `"time"`(기본) 또는 `"count"`. |
| `goal` | `number \| null` | — | 선택 | 목표 값. 점선으로 긋는다. |
| `bubbleColor` | `string` | `color.primary` | 선택 | 말풍선 색. 기본 `color.primary`. |
| `block` | `boolean` | — | 선택 | `true`이면 리포트 모양. |
| `partColor` | `string` | — | 선택 | `part` 부분의 색. |
| `part2Color` | `string` | — | 선택 | `part2` 부분의 색. |

## 치수와 토큰

| 항목 | 값 |
| --- | --- |
| 축 | 시간: 1시간 이상이면 `0h 1h 2h…`(최대 3단계), 미만이면 15분 단위. 문제 수: 0·중간·최대의 정수 |
| 막대 | 폭 22, 최소 높이 폭 × 0.6, 선택 안 된 막대 `primary` 20%→34%, 선택 `gradient` |
| 격자선 | `line` 투명도 0.7, 목표선 `mint` 점선 1.6(5 4) |
| 말풍선 | 높이 26, 모서리 13(`block`은 9), `primary`(`block`은 네이비), 글자 `caption` Bold white |

## 접근성

- 각 막대는 `button`이고 이름은 `a11y` 또는 라벨이다. 웹 미리보기는 "{요일}, {값}"으로 읽는다.
- 값은 말풍선 글자와 축 숫자로 확인할 수 있다. 색만으로 전달하지 않는다.

### 글자 색 대비

| 쓰임 | 글자색 | 바탕 | Mordy 라이트 | Mordy 다크 | Morit 라이트 | Morit 다크 | 기준 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 말풍선 글자 (11.5px 굵게) | `onPrimary` | `primary` | 3.93:1 미달 | 3.31:1 미달 | 4.60:1 통과 | 7.25:1 통과 | 4.5:1 |
| 축 숫자 (11.5px) | `textTertiary` | `surface` | 2.53:1 미달 | 3.50:1 미달 | 2.97:1 미달 | 4.45:1 미달 | 4.5:1 |

## 잘한 예와 잘못한 예

- 잘한 예: 요일 라벨과 값 말풍선을 함께 둔다.
- 잘못한 예: 막대가 너무 많으면 라벨이 겹친다.

## 함께 보는 컴포넌트

- [AreaLine](https://developers.moring.co/tds/components/area-line.md): 누적 값을 선과 옅은 면으로 보여 주는 차트다. 모든 점에 점이 찍히고 마지막 점에 말풍선이 뜬다. 리포트의 누적 문제 수, 누적 학습 시간에 쓴다.
- [Sparkline](https://developers.moring.co/tds/components/sparkline.md): 정답률 같은 작은 추이를 보여 주는 선 그림이다. 값이 없는 날은 선이 끊기고, 마지막 점이 크게 표시된다.
- [CalendarHeat](https://developers.moring.co/tds/components/calendar-heat.md): 한 달 달력에서 날마다 공부한 시간을 색의 진하기(5단계)로 보여 주는 차트다.
