# PourGauge Đồng hồ rót trà ở quầy: giữ tay để rót, thả khi mức trà tới vạch xanh ở khoảng 80%. ## Khi nào dùng - Rót trà từ hũ vào ly: nhấn giữ hũ (hoặc nút "Nhấn giữ để rót") rồi thả đúng cửa sổ đích. - Chỉ hiển thị mức (không rót) thì dùng `tt-progress`; gauge này luôn có cửa sổ đích. ## Biến thể | Biến thể | Lớp | Dùng khi | |---|---|---| | Cỡ sân khấu | `tt-pour` | Rộng 170px như game (`.q3gauge`) | | Rộng hết khung | `tt-pour tt-pour--fluid` | Preview, màn nhỏ hoặc khi cần thanh lớn hơn | ## Cấu trúc ```html
``` `__track` là rãnh `wood-dark` (JS thêm `role="progressbar"`), `__level` là mức trà (gradient `pour-low` → `pour-mid` 60% → `pour-high` 80%; bốn theme gốc: `pour-low` = `warn`, `pour-high` = `target`), `__target` là cửa sổ đích viền 3px `on-fill`. Nút giữ dùng lại `tt-button`; có thể thay bằng chính hũ trà của quầy qua `opts.hold`. ## Trạng thái | Trạng thái | Hiệu ứng | |---|---| | `is-pouring` | Đang giữ tay; nút có `aria-pressed="true"` | | `is-hit` | Thả trong cửa sổ đích: chữ kết quả `mint` | | `is-miss` | Thả ngoài cửa sổ hoặc tràn: chữ kết quả `warn` | ## Hành vi JS `TTMU.pourGauge(root, opts)` → `{ fill, pouring, target, setTarget([lo, hi]), reset(), destroy() }` hoặc `null` nếu đã gắn. ```js TTMU.pourGauge(el, { target: [0.74, 0.86], // mặc định: left 74% + width 12% của .q3ok speed: 0.54, // mức đầy mỗi giây (tick() của game) onStop: function (r) { /* r = { fill, hit, spill } */ } }); ``` - `pointerdown` bắt đầu rót; `pointerup`, `pointerleave`, `pointercancel`, `blur` (nút, cửa sổ, tab ẩn) dừng. Space hoặc Enter giữ cũng rót, thả phím thì dừng. - Cập nhật bằng `requestAnimationFrame` theo thời gian thật (mỗi khung tối đa 100ms); mức đầy tối đa 1.02, trên 1.0 là tràn (`spill`). - Rót tiếp từ mức hiện có (như ly đang đầy dở); `reset()` để về 0. `hit` = không tràn và `fill` nằm trong `[lo, hi]`. - Chữ kết quả đổi bằng `opts.labels` (`idle`, `pouring`, `hit`, `low`, `high`, `spill`). ## Token sử dụng `wood-dark`, `pour-low`, `pour-mid`, `pour-high` (gradient mức trà), `on-fill`, `mint` (trúng), `warn` (trượt), `soft`, `radius-6`, `space-10`; nút dùng `pink` qua Button. ## Khả năng tiếp cận - Rãnh là `role="progressbar"` (`aria-valuenow` = phần trăm mức trà); kết quả đọc qua vùng `role="status"`. - Bàn phím: Tab tới nút, giữ Space/Enter để rót. Kết quả trúng/trượt luôn có chữ, không chỉ màu. - Nút có `touch-action: none`, chặn menu giữ lâu và chọn chữ để thao tác chạm không bị cuộn trang. ## Nên / Không nên | Nên | Không nên | |---|---| | Đặt `target` đúng cửa sổ vạch xanh đang hiển thị | Để cửa sổ CSS khác với `target` trong JS | | Gọi `reset()` khi đổ ly hoặc lấy ly mới | Gắn lại `pourGauge` lên cùng phần tử mà không `destroy()` | ## Nguồn `.q3gauge`, `.q3lv`, `.q3ok` — css/style.css dòng 648–650; rót ở `tick()` trong js/game.js dòng 7619 (0,54 mỗi giây, kẹp 1,02, tràn khi quá 1). - Chấm điểm ở `sealServe()`: lệch quá 0,14 so với 0,8 (tức ngoài 0,66–0,94) hoặc tràn thì khách bị trừ sao; vạch xanh 0,74–0,86 là vùng ngắm lý tưởng nên `hit` chặt hơn mức bị phạt. - Cửa sổ đích: viền `#fff` đổi `on-fill`, rãnh `#5b3f25` đổi `wood-dark`, gradient `#e2574c/#f4b73a/#5aae86` đổi `pour-low/pour-mid/pour-high` (bốn theme gốc: `warn/pour-mid/target`, nên màu giữ nguyên; ở `hc` hai đầu sáng hơn để đạt 3:1 trên gỗ). - Nút "Nhấn giữ để rót" và nhãn kết quả là phần thêm của DS (game rót bằng cách giữ chính hũ trà).