# ThemePicker
Lưới ô chọn màu giao diện, mỗi ô là một vòng tròn chia đôi (nền / màu nhấn) của chính theme đó.
## Khi nào dùng
- Hộp thoại "Màu giao diện" trong Cài đặt.
- Năm theme: Kem sữa, Nâu cà phê, Sô cô la, Đêm dịu (bốn theme của game) và Tương phản cao (`hc`, theme do design system thêm, đạt ngưỡng tương phản AAA cho chữ (SC 1.4.6) và 3:1 cho viền, focus, đồ hoạ (SC 1.4.11) trên các preview, kể cả các trạng thái mở bằng JS có `data-audit-click`).
## Biến thể
| Biến thể | Lớp | Dùng khi |
|---|---|---|
| 3 cột | `tt-theme-picker` | Mặc định như game (lưới 3 cột, gap 8px). Với 5 theme thành 3 + 2: hàng dưới có hai ô căn trái và một ô trống ở cuối, nhìn vẫn cân vì mọi ô cùng bề rộng; đây là bố cục chuẩn cho 5 theme |
| 2 cột | `tt-theme-picker tt-theme-picker--two` | Chỉ hợp khi số theme chẵn; với 5 theme thành 2 + 2 + 1 và ô cuối mồ côi, nên tránh |
## Cấu trúc
```html
```
Ô màu mang `data-theme` của chính nó nên luôn hiện đúng màu theme đó, dù trang đang ở theme nào.
## Trạng thái
| Trạng thái | Hiệu ứng |
|---|---|
| Chưa chọn | Viền `line`, nền `bg` |
| `aria-checked="true"` | Viền `pink` và vòng 2px `pink` (`shadow-ring-pink`) |
| Focus bàn phím | Vòng `focus-ring` 3px |
## Hành vi JS
```js
TTMU.themePicker(root, { onChange: function (id) {} })
// → { value, set(id), destroy() } (gắn lần hai trả về null)
```
- Bấm nút → `TTMU.setTheme(id)`, cập nhật `aria-checked`, gọi `onChange(id)` (chỉ khi theme đổi; bấm lại theme đang chọn không gọi).
- **Quy ước `onChange`:** chỉ thao tác của người dùng mới gọi `onChange`, và chỉ khi giá trị thật sự đổi; `set(id)` từ code thì im lặng.
- Phím mũi tên chọn theme kế/trước (vòng tròn) và chuyển focus; chỉ nút đang chọn có `tabindex="0"`.
- Nếu `root` trống, JS tự dựng 5 nút từ `TTMU.themes`.
## Token sử dụng
`bg`, `pink`, `line`, `ink`, `outline`, `shadow-ring-pink`, `radius-14`, `radius-round`, `space-4/8/10`.
## Khả năng tiếp cận
- `role="radiogroup"` + `role="radio"` với `aria-checked`; mũi tên di chuyển lựa chọn.
- Tên theme (kể cả Tương phản cao) là chữ trong nút nên screen reader đọc được; ô màu chỉ trang trí.
## Nên / Không nên
| Nên | Không nên |
|---|---|
| Hiện tên theme dưới ô màu | Chỉ hiện màu không có chữ |
| Đặt `data-theme` lên ô màu | Dùng màu hex cố định cho ô màu |
## Nguồn
`.thg`, `.thb`, `.thb i`, `.thb.on` — css/style.css; `themeDlg()` — js/game.js.
- Game có 8 theme và vẽ ô màu bằng style nội tuyến; design system có 5 theme (4 theme của game cộng `hc`) và dùng `var(--bg)`/`var(--pink)` theo `data-theme`.
- Vòng ngoài ô màu `rgba(0,0,0,.12)` đổi sang `color-mix` với `outline`.
- `.thb.on` dùng `box-shadow:0 0 0 2px var(--pink)` = token `shadow-ring-pink`.