---
url: https://docs.nemo12.com/design-system/scorecards/learn-ielts-grammar-topic.md
description: >-
  Bảng điểm 25 yếu tố cho một chủ đề ngữ pháp IELTS (/ielts/grammar/<topic>):
  chấm theo Focus Order và Information Load, kèm việc cần sửa.
---

# Bảng điểm: learn `/ielts/grammar/<topic>` (SRC-1303)

Màn: một chủ đề ngữ pháp của sân luyện IELTS (vd. "Must and have to", `/ielts/grammar/articles`).
Mã nguồn: trang đã gỡ ở SRC-1337 (11.10.2026), ô luyện nay ở `apps/learn/src/grammar/practice.tsx`, shell `apps/learn/src/ielts/Shell.tsx`
→ `journeys/IeltsJourneyShell.tsx` → `components/JourneyShell.tsx`. Chuẩn và thang chấm:
[focus-and-load.md](../focus-and-load.md). Skill: `/ui-audit-25`.

| Lượt | Ngày | Điểm | Ghi chú |
| --- | --- | --- | --- |
| 0 (trước khi sửa) | 09.10.2026 | 29/50 | ảnh chủ dự án + đọc mã + Playwright 375/1440 |
| 1 (sau lô 1) | 09.10.2026 | 39/50 | lô 1 dưới đây |
| 2 (sau lô 2) | 09.10.2026 | 49/50 | lô 2 dưới đây; đo lại bằng Playwright 375/1440 |
| 3 (sau lô 3) | 09.10.2026 | 50/50 | lô 3 dưới đây |

## Hai câu bắt buộc

* **Nhìn đâu trước? (lượt 0)** ở 1440px mắt bị kéo giữa hai cột: h1 bên trái và thẻ "YOUR STATUS" năm
  dòng bên phải; thanh bước sáng "2 Choose what to practise" trong khi learner đã ở trong bài. Ở 375px
  thẻ trạng thái đứng **trên** h1, nên thứ đầu tiên learner đọc là Membership, không phải bài học.
  Xong 5/5 thì nút tô đầy duy nhất là "Làm lại": việc chính chỉ ngược về sau.
* **Bao nhiêu thứ? (lượt 0)** trong tầm nhìn đầu ở 375px: vệt đường dẫn, thẻ trạng thái (5 dòng),
  khối tiêu đề, công thức, nút chính = 5 khối trước khi tới phần bài, trong đó một khối (thẻ trạng thái)
  lặp nguyên văn trên mọi trang luyện (L5).
* **Sau lô 1:** h1 → công thức → một nút tô đầy → câu dẫn "Cần ôn trước khi làm?" → bốn mục gập; không
  còn cột phải; thanh bước sáng "Practise". e2e `ieltsGrammarFocus.spec.ts` giữ thứ tự `y` và đúng một
  nút tô đầy ở 375 và 1440. Từ 10.10.2026 (SRC-1321) hàng 2 của Learn là bốn kỹ năng, nên ở trang ngữ
  pháp không pill nào sáng (e2e đếm `aria-current=step` = 0).
* **Sau lô 2:** ở 375px tầm nhìn đầu có đúng 5 khối: vệt đường dẫn (chỉ `Grammar`), khối tiêu đề
  (`header[data-part=grammar-title]`: kicker, h1, tên tiếng Việt = ba lớp, L2), công thức, hàng nút chính
  (nút + `n/5 tasks done` đứng cạnh), câu dẫn + bốn mục gập. Một nút tô đầy. Tên chủ đề nói một lần (h1).
  e2e mới trong `ieltsGrammarFocus.spec.ts` giữ cả L1 (đếm khối) lẫn L5 (vệt không chứa chữ của h1).

## 25 yếu tố

| # | Yếu tố | Lượt 0 | Lượt 1 | Lượt 2 | Lượt 3 | Bằng chứng / luật |
| --- | --- | --- | --- | --- | --- | --- |
| 1 | Information Architecture | partial | partial | pass | pass | vệt đường dẫn dừng ở trang cha `Grammar`; tên chủ đề chỉ ở h1 (L5), e2e lọc `nav[aria-label=Breadcrumb]` theo chữ h1 = 0 |
| 2 | Navigation | fail | pass | pass | pass | `journeyOfPath` trả `step: "choose"` cho mọi trang luyện → nay `practise` (F5) |
| 3 | Layout | fail | pass | pass | pass | `StatusCard` ở mọi trang luyện, cột `17rem` bên phải → bỏ ở trang luyện (F7) |
| 4 | Visual Hierarchy | partial | pass | pass | pass | xong 5/5: nút tô đầy là "Làm lại" → nay "Chủ đề tiếp theo", "Làm lại" viền (F1, F4) |
| 5 | Responsive Design | fail | partial | pass | pass | e2e đếm khối trong tầm nhìn đầu ở 375px: 4 khối trong cột + vệt = 5 (L1); `scrollWidth` 375 |
| 6 | Interaction Pattern | pass | pass | pass | pass | `Fold` gập mặc định, mở một mục không mở mục khác (L4) |
| 7 | User Flow | fail | pass | pass | pass | xong 5/5 không có đường sang chủ đề sau trừ khi bấm "Làm lại" rồi làm hết lần nữa (F4) |
| 8 | Affordance | partial | partial | pass | pass | công thức: nền `bg-muted` + vạch trái `border-l-4`, không còn viền bốn cạnh như ô nhập (e2e kiểm lớp `border`) |
| 9 | Feedback | pass | pass | pass | pass | "Correct / Not yet" + lời giải ngay sau Kiểm tra |
| 10 | State | partial | partial | pass | pass | `useGrammarDone` trả thêm `loaded`; chưa về thì ô nút giữ `Skeleton` cùng cỡ nút `lg` và dòng tiến độ giữ khung chờ; e2e chặn API rồi thả, nhãn chỉ hiện một lần ("Làm tiếp level 3") |
| 11 | Design System | pass | pass | pass | pass | shadcn `Button`/`Card`, token |
| 12 | Components | partial | partial | pass | pass | `Fold` dựng trên shadcn `Accordion` (Radix), cho mọi nơi dùng `Fold` (cả `/grammar`) |
| 13 | UI Patterns | pass | pass | pass | pass | ví dụ và lỗi hay gặp theo card-patterns (example, compare) |
| 14 | Forms | partial | partial | pass | pass | Enter trong ô điền chỗ trống gọi `check()` (bỏ qua khi đang gõ IME), `enterKeyHint="done"`; e2e gõ "an" + Enter thấy "Correct" |
| 15 | Data Display | partial | partial | pass | pass | dòng phụ chỉ còn tên tiếng Việt; tiến độ `n/5 tasks done` đứng cạnh nút chính (`data-part=grammar-progress`), header giữ ba lớp (L2, e2e đếm 3 con) |
| 16 | Onboarding | fail | pass | pass | pass | bốn mục gập không có câu dẫn, trông như việc phải làm → câu dẫn tiếng Việt (F6) |
| 17 | Empty State | pass | pass | pass | pass | chủ đề không có: "Không tìm thấy chủ đề này." |
| 18 | Error Handling | partial | partial | pass | pass | màn không tìm thấy: h1 "Topic not found", câu tiếng Việt, nút "Về danh sách ngữ pháp" về `/ielts/grammar` (e2e) |
| 19 | Accessibility | partial | partial | pass | pass | Radix gắn `aria-controls` trỏ tới panel khi mở, nút nằm trong heading; e2e mở mục và tìm panel theo id |
| 20 | Personalization | pass | pass | pass | pass | tiến độ thật của learner (máy + máy chủ) |
| 21 | Typography | pass | pass | pass | pass | kicker, h1 `text-3xl`, dòng phụ: ba lớp (L2) |
| 22 | Color | pass | pass | pass | pass | một màu nhấn cho nút chính; đúng/sai có chữ đi kèm |
| 23 | Spacing | pass | pass | pass | pass | `mt-4/6/10` theo thang |
| 24 | Iconography | partial | partial | pass | pass | `ChevronDownIcon` của lucide (qua shadcn), xoay 180 độ khi mở |
| 25 | Motion | partial | partial | partial | pass | gập/mở cả chiều cao lẫn độ mờ qua preset `Collapse` mới trong `Motion.tsx` (motion, `useReducedMotion` cho chuyển tức thì); `Fold` ép mount panel Radix để `Collapse` chạy cả lúc đóng và kết thúc bằng `display: none`; e2e: không còn lớp `animate-accordion`, đóng lại thì `display: none`, giảm chuyển động thì mở ngay |

## Lô đã sửa

| Lô | Ngày | PR | Yếu tố | Thay đổi |
| --- | --- | --- | --- | --- |
| 1 | 09.10.2026 | session/ui-review-skill | 2, 3, 4, 7, 16 (5 một phần) | pass | vệt đường dẫn dừng ở trang cha `Grammar`; tên chủ đề chỉ ở h1 (L5), e2e lọc `nav[aria-label=Breadcrumb]` theo chữ h1 = 0 |
| 3 | 09.10.2026 | session/ui-audit-pass3 | 25 | preset `Collapse` (motion, tôn trọng giảm chuyển động) thay keyframe `accordion-down/up` cho `Fold`; e2e trong `ieltsGrammarFocus.spec.ts` |

## Còn lại

Không còn yếu tố partial hay fail. Hai điều nói thẳng để điểm không bị hiểu rộng hơn sự thật:

1. Preset `Collapse` mới chỉ gắn vào `Fold` (màn này và `/ielts/grammar`). Các `Accordion` khác của
   learn (`IeltsGap`, `LabPlayer`, `CurriculumOutline`) vẫn dùng `AccordionContent` của shadcn với
   keyframe tw-animate-css; chúng không thuộc màn này, đổi chúng là một lô riêng.
2. Khung chờ tiến độ chỉ hiện khi đã đăng nhập. Yếu tố 21, 22 vẫn chấm bằng mắt qua ảnh chụp 375/1440,
   không có e2e riêng.

Lượt 1 thấy `/ielts/today` tràn ngang 15px ở 375px: đã sửa trong lô 2, xem
[bảng điểm `/ielts/today`](./learn-ielts-today.md).
