Information Hierarchy và Visual Hierarchy (SRC-1294)
Chủ dự án 08.10.2026: màn lesson của AI Teen (AI Teen 2 · Unit 1 · Lesson 2) nói cùng một điều hai ba lần (danh sách activity ở card giữa trang VÀ ở thẻ trái, kicker lặp câu hỏi của lesson, dòng "Tìm hiểu sâu: ..." lặp tên activity) và chồng bảy lớp chữ lên đầu trang. Trang này là chuẩn cho mọi màn AI Teen (chương trình, course, unit, lesson) và cho mọi màn mới dùng Guided Journey. Nó là một phần của DS-001; chỗ nào nói khác guided-journey.md thì trang này thắng về thứ bậc, guided-journey.md thắng về cấu trúc journey.
Luật có mã (H-I* thông tin, H-V* thị giác, H-S* thẻ bên) để test, review và commit trỏ tới. Luật nào đo được thì có cột "Đo bằng".
1. Information Hierarchy: nói gì, theo thứ tự nào
Bốn bậc quan trọng, luôn theo thứ tự này từ trên xuống:
| Bậc | Câu learner đang hỏi | Ở đâu trên màn | Ví dụ ở lesson |
|---|---|---|---|
| 1. Em đang ở đâu? | "Đây là màn gì?" | header (breadcrumb cấp) + h1 | Lesson 2/4 · 1 Bắt đầu |
| 2. Làm gì bây giờ? | "Bước kế của mình là gì?" | ngay dưới h1; bước hiện tại sáng; đúng một nút chính | bước đang đọc, nút "Xong bước này" |
| 3. Thông tin hỗ trợ | "Mình cần biết gì để làm?" | thân màn, mở sẵn nhưng gọn | outcomes, sản phẩm, concept |
| 4. Tra cứu | "Muốn xem kỹ thì xem ở đâu?" | thu gọn mặc định hoặc một link | Skills của course, Learning Cycle |
| Mã | Luật | Đo bằng |
|---|---|---|
| H-I1 | Một thông điệp chính mỗi màn, và nó là h1. Màn nào cần hai h1 là màn đang chứa hai màn. | e2e: đúng 1 h1 trong [data-part=journey-content] |
| H-I2 | Thứ tự bốn bậc ở bảng trên. Tra cứu không đứng trên việc cần làm (trang course: danh sách unit trước, outcomes sau, Skills thu gọn cuối). | review |
| H-I3 | Header của nội dung tối đa ba lớp: một kicker (tuỳ chọn), h1, một dòng phụ. Câu hỏi, tóm tắt, chặng vòng học không chồng thêm lên đó. | e2e: tối đa 1 [data-kicker] |
| H-I4 | Mở sẵn hay thu gọn. Bậc 1-2 luôn hiện. Bậc 3 hiện nhưng gọn: danh sách ngắn, không card riêng cho mỗi mẩu. Bậc 4 thu gọn mặc định (Accordion) hoặc nằm sau một link. | review; e2e: outcomes của lesson không có viền card |
| H-I5 | Không nói một điều hai lần trên cùng màn. Danh sách activity chỉ ở thẻ trái; câu hỏi của lesson chỉ ở một tiêu đề; concept chỉ một chỗ; tên activity không lặp trong dòng giải thích. | e2e: không [data-activity] trong vùng chính; câu hỏi xuất hiện đúng 1 lần |
| H-I6 | Số mục mỗi bậc: tối đa 7 mục cùng cấp trong một danh sách điều hướng (activity, journey, bước của một activity); tối đa 5 mục hỗ trợ (outcomes) hiện cùng lúc, hơn nữa thì thu gọn phần dư. | test thuần đếm activity và bước (journeys.test.ts) |
| H-I7 | Nhãn ngắn: tên trong thẻ bên và menu 1-3 chữ (đã có test); kicker 1-4 chữ (§2b); nhãn nút 1-4 chữ cộng mũi tên. | journeys.test.ts, review |
2. Visual Hierarchy: trông thế nào
2a. Thang chữ: đúng năm cấp, không cấp thứ sáu
Hằng số ở apps/learn/src/components/hierarchy.ts (T.page, T.section, ...). Màn dùng hằng số, không tự viết text-3xl font-bold.
| Cấp | Thẻ | Class Tailwind | Cỡ / đậm | Dùng cho |
|---|---|---|---|---|
| Page title | h1 | text-2xl sm:text-3xl font-bold leading-tight | 24/30px, 700 | thông điệp chính, đúng một |
| Section title | h2 | text-xl font-semibold leading-snug | 20px, 600 | một bước của lesson, một khối của trang |
| Card title | h3 | text-base font-semibold | 16px, 600 | tiêu đề trong khối, nhãn trên một danh sách ngắn |
| Body | p | text-base | 16px, 400 | chữ thường |
| Meta | p, span | text-sm text-muted-foreground | 14px, 400 (600 khi là nhãn) | dòng phụ, số đếm, gợi ý |
| Kicker | p[data-kicker] | text-sm font-semibold uppercase tracking-wider text-muted-foreground | 14px, 600 (sàn chữ 14px của SRC-1293) | xem §2b |
| Mã | Luật | Đo bằng |
|---|---|---|
| H-V1 | Tối đa ba cấp tiêu đề (h1, h2, h3). Cần h4 là khối đang lồng quá sâu: hạ thành nhãn Meta đậm. | e2e: không h4-h6 hiện trong nội dung |
| H-V2 | Một chỗ dùng accent mỗi màn cho hành động chính hoặc mục hiện tại: tối đa MỘT nút tô đầy (data-variant = accent hay default) trong tầm nhìn. Trang lesson là một trang cuộn nhiều bước: chỉ bước đang đọc (scroll-spy) mang nút tô đầy, bước khác dùng outline. Mục hiện tại ở thẻ bên tô accent; đó là chỗ thứ hai DUY NHẤT được tô, vì nó là "em đang ở đâu". | e2e: đếm nút tô đầy giao với khung nhìn ≤ 1 |
| H-V3 | Vai màu: foreground cho chữ chính; muted-foreground cho Meta, kicker, số thứ tự; accent cho hiện tại và hành động chính; destructive chỉ cho lỗi hệ thống (DS-001 §7.3). Không dùng màu để phân cấp chữ ngoài hai mức foreground / muted. Tương phản chữ ≥ 4.5:1 (Meta cũng vậy). | DS-001 §2·1, review |
| H-V4 | Thang khoảng cách (Tailwind, bội số 4px): trong một khối gap-1/space-y-1 (4px) giữa tiêu đề và dòng phụ; space-y-3/4 (12-16px) giữa các phần của một khối; space-y-10 (40px) giữa các bước của lesson và các khối lớn của trang. Không giá trị lẻ (mt-[13px]). | review |
| H-V5 | Card lồng tối đa một cấp: một card không chứa card. Trong card dùng đường kẻ (border-t), nền nhạt hoặc danh sách. | review |
| H-V6 | Icon: chỉ lucide, aria-hidden khi đã có chữ; 14-16px trong thẻ bên và nhãn, 16px trong nút; một icon mỗi hàng; không icon trang trí đứng một mình không có chữ (trừ nút icon có aria-label). Không còn icon ổ khoá trong lesson (§3). | e2e: không svg.lucide-lock trong lesson |
2b. Kicker (eyebrow)
| Mã | Luật |
|---|---|
| H-V7 | Tối đa một kicker mỗi màn, chỉ đứng trên h1, 1-4 chữ, nói VỊ TRÍ (Lesson 2/4, Unit 1 · Mục tiêu, Practice), không nói lại tiêu đề hay câu hỏi. h2 không có kicker; số "Phần 2/4" của một phần đọc là dòng Meta dưới h2. |
| H-V8 | Nhãn trong card không viết HOA kiểu kicker: dùng Card title hoặc Meta đậm, chữ thường. |
3. Thẻ bên (sidebar) của trang lesson
Áp cho thẻ Activity bên trái (guided-journey §12, SDD-043 §14). Chủ dự án 08.10.2026: thẻ cũ quá to, mọi nhóm mở cùng lúc, có thanh cuộn riêng.
| Mã | Luật | Đo bằng |
|---|---|---|
| H-S1 | Cột hẹp: 14rem (224px), tối đa 240px; không lề ngoài thừa (p-2, cột lưới sát mép trái của khung nội dung). | e2e: bề rộng thẻ ≤ 240px |
| H-S2 | Hàng gọn: activity 36px, bước 32px trên máy lớn (lg); chữ 14px cho activity và bước (sàn chữ SRC-1293), số muted; thụt 12px với một đường kẻ trái. Dưới lg (sheet) mọi vùng chạm ≥ 40px. | e2e 375px: mọi nút hiện ≥ 40px |
| H-S3 | Đúng một nhóm mở: nhóm của activity hiện tại; bấm tiêu đề nhóm khác thì mở nhóm ấy (và đi tới activity ấy), nhóm kia gập. Nút tiêu đề có aria-expanded + aria-controls; nhóm gập vẫn trong DOM (hidden). | e2e: đúng 1 [data-step-list]:not([hidden]) sau mỗi lần bấm |
| H-S4 | Không thanh cuộn trong: thẻ cao bằng nội dung, cuộn theo trang; chỉ sticky khi nó vừa khung nhìn dưới header (đo lúc chạy). | e2e: overflow-y không phải auto/scroll, scrollHeight ≤ clientHeight |
| H-S5 | Một chỗ tô: bước hiện tại nền accent; activity hiện tại chỉ đậm, không viền, không nền. Xong = dấu tick nhỏ, không đổi màu cả hàng (đây là card trái của lesson; NavBar và hàng bước thì KHÔNG có tick từ SRC-1300, xem guided-journey §9). | review |
| H-S6 | 375px: thẻ thành sheet gọn mở từ thanh dính "Activity · Bước"; cùng component, cùng luật một nhóm mở. | e2e 375px |
4. Áp vào bốn cấp AI Teen (08.10.2026)
| Màn | h1 | Kicker | Thứ tự dưới h1 | Đã bỏ |
|---|---|---|---|---|
| Chương trình (Learning) | đích của em | Lộ trình của em | nút Tiếp tục (nút tô duy nhất) → từng course với unit | nút Ghi danh tô đầy ở mỗi course (nay outline) |
| Course | tên course | không | danh sách unit → Course Outcomes (gọn, không card) → Skills (thu gọn) → link Learning Cycle | card bao outcomes; nút Learning Cycle đứng trên danh sách unit |
| Unit | Compelling Question | Unit n · Mục tiêu / Unit n · Học / Practice ... | khối skill → học gì / làm ra gì → nút chính | kicker hai vế ("Mục tiêu · Khi xong unit này"), nhãn HOA trong card, đoạn giải thích dài trên danh sách lesson |
| Lesson | {n} {Activity} | Lesson m/N | mỗi bước một h2; bước Câu hỏi: h2 = câu hỏi, một dòng tóm tắt, outcomes gọn, sản phẩm một dòng, concept | card "Learning Activities" (lặp thẻ trái), câu hỏi trong kicker, dòng chặng vòng học, card "Concept của lesson", chip concept lặp ở Mang theo, card "Sản phẩm của lesson", kicker trên mọi h2, ổ khoá |
4b. Nội dung trong card: Card patterns (SRC-1298)
Nội dung học (khối bài đọc, outcomes, sản phẩm, câu hỏi, kết quả) không vẽ tuỳ hứng: mỗi loại thông tin dùng đúng một pattern trong Card patterns, mỗi card một ý, gap-6/gap-8 giữa card. Nhãn trên card là T.meta, tiêu đề card là h3 T.card, nên luật một kicker và tối đa ba cấp tiêu đề ở trên vẫn giữ.
5. Hiện thực và kiểm chứng
- Thang chữ:
apps/learn/src/components/hierarchy.ts; tiêu đề màn và bước:apps/learn/src/aiTeen/StageHead.tsx(kicker chỉ khias="h1"). - Thẻ bên:
LessonOutline+FitStickytrongapps/learn/src/aiTeen/LessonPage.tsx. - e2e
apps/learn/e2e/aiTeen.spec.ts, khối "Information + Visual Hierarchy": một h1, h1-h3, một kicker, một nút tô đầy trong tầm nhìn ở chương trình, course, unit, lesson; lesson không lặp danh sách activity; thẻ ≤ 240px, không cuộn trong, đúng một nhóm mở, không ổ khoá; 375px sheet gọn, vùng chạm ≥ 40px. - Màn mới: skill
journey-design§3c bắt buộc đi qua bảng luật trên trước khi dựng.