Skip to content

Guided Journey · Cổng đọc, card skill và trang lesson ​

Một phần của Guided Journey pattern (SRC-1253). Cổng đọc ở learn và Marlins, card skill, level, chỉ báo, nội dung của bước và trang chi tiết lesson có card Activity.

10. Cổng đọc: phần ngắn, ba câu, chỉ báo tổng (SRC-1268) ​

Chủ dự án 06.10.2026, áp cho mọi lesson AI Teen: một bài đọc dài là một bài không ai đọc hết. Mẫu này cắt bài thành nhiều phần ngắn, mỗi phần một bước có tên của Progress Bar, và đặt một cổng sau mỗi phần. (Khoá bố mẹ Marlins dùng cùng mẫu, xem §10b.)

text
Phần 2/4 · Prompt là lời giao việc               (chữ của phần, một hai khối; trang lesson §9a)
[ Mình đọc xong rồi, kiểm tra nhanh nhé ]
        |
  3 câu siêu ngắn, mỗi câu 3 phương án ngắn       "2/3 câu đã chọn"   [Nộp bài] (khoá tới khi đủ 3)
        |
  +-- 3/3 câu đúng -> lời giải của cả 3 câu -> [Sang phần 3]   (phần này "xong")
  +-- 2/3 câu đúng -> chỉ con số đó          -> nút kiểm khoá + "Làm lại sau 2:41" (180 giây); [Sang phần 3] vẫn bấm được
  1. Phần là một bước của thanh, có tên (tên đầy đủ trên máy lớn, Phần k dưới sm). Không phần nào khoá (chủ dự án 08.10.2026, SRC-1294, AI Teen): cổng là phép kiểm tuỳ chọn, chỉ quyết định phần "xong"; đường sang phần sau luôn có (nút ghost cạnh nút cổng). Khoá bố mẹ Marlins (§10b) chưa đổi.
  2. Nút cổng luôn ở cuối phần, đúng một câu, giọng học sinh. Trong lúc chờ, nút vẫn đứng đó nhưng khoá.
  3. Quiz đúng 3 câu, mỗi câu 3 nút chọn (role="radio", cao tối thiểu 44px); "Nộp bài" khoá tới khi đủ.
  4. Kết quả chỉ là tổng ("2/3 câu đúng"). Câu hỏi ĐÓNG LẠI ngay khi nộp, không có hiệu ứng thoát: để lựa chọn còn nằm trên màn cạnh con số tổng là nói gián tiếp câu nào sai.
  5. Lời giải chỉ khi 3/3: đáp án đúng và một câu vì sao, cho cả ba câu.
  6. Chờ 180 giây kể từ lúc lượt trượt kết thúc, giờ SERVER; client chỉ đếm ngược phần còn lại. Tải lại trang hay đổi máy không xoá được thời gian chờ.
  7. Làm lại cùng 3 câu, thứ tự phương án xáo lại và không trùng lượt trước.
  8. Phần đã qua mở để đọc lại mãi, nhãn "Đã qua" và nút sang phần sau, không kiểm tra lại.

Hiện thực (AI Teen). apps/learn/src/aiTeen/gate.ts (luật thuần), ReadingGate.tsx (giao diện), useGates.ts (trí nhớ), journeys.ts (bước thanh); chi tiết dữ liệu và API ở SDD-043 §10. Luật soạn câu: CD-8c.

10b. Cổng đọc ở khoá bố mẹ Marlins (SRC-1265) ​

Chủ dự án 06.10.2026, áp đầu tiên cho mọi chỗ học của khoá bố mẹ Marlins: một bài đọc dài là một bài không ai đọc hết. Mẫu này cắt bài thành nhiều phần ngắn và đặt một cổng sau mỗi phần.

text
Phần 3/8 · Ví dụ 1          (chữ của phần, vài câu)
[ Tôi đọc xong rồi, kiểm tra nhanh ]
        |
  3 câu siêu ngắn, mỗi câu 3 phương án ngắn      "Đã trả lời 2/3 câu"   [Nộp bài] (khoá tới khi đủ 3)
        |
  +-- 3/3 câu đúng -> lời giải của cả 3 câu -> [Sang phần tiếp]  (phần sau mở)
  +-- 2/3 câu đúng -> chỉ con số đó          -> [Làm lại sau 2:41] (khoá 180 giây) -> [Làm lại]
  1. Phần là một bước của Progress Bar, có tên ("Chuyện quen", "Ví dụ 1", "Hiểu lầm 2"); mỗi lúc chỉ hiện một phần. Phần chưa mở là bước khoá; mở thẳng URL của nó thì gặp thẻ "Phần này mở khi bạn đúng cả ba câu kiểm tra nhanh của phần trước" kèm nút về phần đang đọc.
  2. Nút cổng luôn ở cuối phần, đúng một câu: "Tôi đọc xong rồi, kiểm tra nhanh". Chữ của phần vẫn nằm trên khi quiz mở ra.
  3. Quiz đúng 3 câu, mỗi câu 3 nút chọn (role="radio", cao tối thiểu 44px). "Nộp bài" bị khoá tới khi đủ 3 câu, cạnh nó là "Đã trả lời n/3 câu".
  4. Kết quả chỉ là tổng ("2/3 câu đúng"). Không tô xanh đỏ từng câu, không "Câu 2 sai", không lời giải: biết câu nào sai thì lần sau chỉ cần đổi một đáp án, và quiz thành trò dò mìn.
  5. Lời giải chỉ khi 3/3: hiện cả ba câu, đáp án đúng và một câu vì sao.
  6. Thời gian chờ 180 giây kể từ lúc lần trượt kết thúc, nút đếm ngược "Làm lại sau m:ss", kèm dòng "Lần trước: 2/3 câu đúng. Đọc lại phần trên trong lúc chờ nhé." Thời gian chờ giữ ở server (tải lại trang, đổi máy không xoá được); trình duyệt chỉ giữ bản sao dự phòng, gộp lại luôn lấy bản dài hơn.
  7. Làm lại có thể là cùng 3 câu; thứ tự phương án được xáo theo số lần làm (lần đầu giữ thứ tự soạn).
  8. Phần đã qua mở để đọc lại mãi, hiện "Bạn đã qua phần này" và nút sang phần tiếp, không quiz lại.

Hiện thực. Luật thuần ở apps/marlins/src/lessonGate.ts (lessonParts, partStates, gateResult, choiceOrder, mergeMemo), giao diện ở apps/marlins/src/courseJourneys/LessonGate.tsx, trí nhớ ở useLessonGates.ts, API ở workers/api/src/modules/parent/lesson-gates.ts. Dùng lại mẫu ở chỗ khác: giữ nguyên tám điểm trên, đổi nguồn câu hỏi. Luật soạn câu: CD-8b.

11. Card skill · level · chỉ báo (SRC-1278) ​

Chủ dự án 07.10.2026, dùng đầu tiên ở màn Mục tiêu và Mình đang ở đâu? của unit AI Teen (SDD-043 §13). Dùng khi learner cần chọn MỤC TIÊU hoặc tự khai CHỖ ĐANG ĐỨNG trên một khung năng lực có level, mà con số level trần ("Level 2") không nói được learner sẽ làm gì.

text
+-- <câu hỏi của card>                                       [ Sửa ] -+   <- ô cố định §2c
| <tóm tắt một dòng: gợi ý trước khi trả lời, kết quả sau khi lưu>    |
|---------------------------------------------------------------------|
| Skill 1 <tên skill>       <competency> · <area> · đo ở Level n      |
| [Level 1 · nhãn] [Level 2 · nhãn] [Level 3 · nhãn]  <- MỘT hàng     |
|  [x] chỉ báo       [ ] chỉ báo     [ ] chỉ báo                      |
|  [ ] chỉ báo                                                        |
| Skill 2 ...                                                         |
| 2/3 chỉ báo đã chọn              [Xác nhận]   (chỉ khi có trần)     |
+---------------------------------------------------------------------+
  • Skill → level → chỉ báo. Mỗi skill là một khối có tên (tên gốc của khung) và dòng phụ competency / area. Các level của skill đứng cạnh nhau trên MỘT hàng (lưới grid-flow-col): đọc các bậc cạnh nhau mới thấy bậc thang. Hàng hẹp hơn nội dung thì hàng cuộn ngang trong chính nó (overflow-x-auto, mỗi level tối thiểu 13rem), trang không bao giờ cuộn ngang.
  • Chỉ báo là ô tick (button role="checkbox", aria-checked, cao tối thiểu 44px), chữ là hành vi quan sát được. Lấy chỉ báo từ mô tả level CÓ THẬT của khung; khung chỉ có một câu mô tả thì chỉ tách ở chỗ câu nối hai việc riêng, còn lại để nguyên một chỉ báo và ghi khoảng trống vào SDD. Không tự soạn chỉ báo mới cho "đủ số"; chỉ soạn khi chủ dự án giao, và khi ấy chỉ báo mang nhãn nguồn (source: "nemo-draft") cho tới khi được duyệt, đặt ở id cũ nếu giữ nghĩa cũ, id mới nếu không (AI Teen: SDD-043 §13.5, SRC-1280).
  • Trần (tuỳ chọn). Card mục tiêu có trần (AI Teen: 3). Tick vượt trần bị chặn, các tick cũ giữ nguyên, và một lời nhắn role="alert" nói vì sao và cách làm ("Bỏ một chỉ báo đã chọn rồi mới chọn chỉ báo khác"); không bao giờ lặng lẽ bỏ tick cũ. Bộ đếm "n/3" ngay trên nút. Card tự khai chỗ đang đứng không có trần, và không tick gì cũng là một câu trả lời hợp lệ.
  • Chế độ đúng bảng §2c: tick vào bản nháp, "Xác nhận" lần đầu, rồi xem (ô tick tắt, tóm tắt nói kết quả) với "Sửa" ở ô cố định, đổi thành "Huỷ" + "Lưu" không xê dịch.
  • Lưu theo id ổn định của chỉ báo (<skill>:<level>:<n>), không theo vị trí; null = chưa xác nhận, khác [] = đã xác nhận mà không chọn. Server giữ lại luật trần.
  • Hiện thực: apps/learn/src/aiTeen/SkillGoalCards.tsx (SkillBoard, IndicatorCard), luật thuần ở apps/learn/src/aiTeen/skillGoals.ts. Khuôn gần nhất bên Marlins: trang khoá bố mẹ chọn tối đa 3 skill rồi một level mục tiêu (apps/marlins/src/courseJourneys/CoursePage.tsx); mẫu này đi sâu hơn một tầng, xuống chỉ báo của từng level.

11b. Nội dung của bước: Card patterns (SRC-1298) ​

Mỗi bước của một journey là một CHUỖI card, không phải một cột chữ: loại thông tin nào dùng pattern nào tra ở Card patterns (18 pattern, bảng tra bắt buộc). Điều hướng của journey ("Xong bước này", "Sang ...") đứng ngoài card.

12. Trang chi tiết lesson: card Activity bên trái, không thanh bước (SRC-1286) ​

Chủ dự án 07.10.2026. Áp cho trang chi tiết LESSON của mọi bề mặt dùng mẫu này (đầu tiên là AI Teen, SDD-043 §14). Đây là chuẩn; phần dựng của AI Teen 1 đi cùng PR tái cấu trúc SRC-1281. Trang unit và trang chương trình giữ bố cục §9 (ba hàng, có Progress Bar).

text
hàng 1   [logo] breadcrumb cấp v                                   [VI|EN] [tài khoản]
NavBar   [ 1 Activity A ✓ ] [ 2 Activity B ] [ 3 Activity C ]        (KHÔNG có hàng 3)
+-- card dính -------+   +-- vùng chính ---------------------------------------+
| 1 Activity A  ✓    |   | chỉ các bước của Activity đang chọn, xếp dọc       |
|   1 Bước     [x]   |   |   1 · <tên đầy đủ của bước>                         |
|   2 Bước      ✓    |   |   2 · ...                                           |
|   3 Bước  <- đang  |   |   3 · ...                                           |
| 2 Activity B   >   |   |   (nhóm B, C gập; không ổ khoá)                     |
+--------------------+   +-----------------------------------------------------+
điện thoại (< lg):  [ Activity A · Bước 3/5   v ]   <- sheet gọn dính ở đầu, mở ra là danh sách của card
  1. Không Progress Bar ở trang lesson; header chỉ còn hàng 1 và NavBar các Activity (số đứng đầu, xong = số + tick).
  2. Card cột trái (rộng 14rem, tối đa 240px, từ lg) liệt kê mọi Activity; đúng một nhóm mở: Activity hiện tại mở ra các Bước, mở nhóm khác thì nhóm kia gập. Mọi mục có số; xong = số + tick. Không ổ khoá, mọi bước tới được (SRC-1294). Hàng gọn, chữ nhỏ, không thanh cuộn trong: card cao bằng nội dung, cuộn theo trang, chỉ sticky khi vừa khung nhìn. Luật đo được: hierarchy.md §3.
  3. Tên trong card tối đa 3 chữ, ưu tiên 1-2. Dữ liệu bước khai tên ngắn riêng; tên đầy đủ là tiêu đề bước ở vùng chính. Test giữ trần.
  4. Vùng chính chỉ có bước của Activity đang chọn. Đổi Activity ở card hay NavBar là thay cả vùng chính và cuộn về đầu; card và NavBar đọc chung một trạng thái (Activity trong URL).
  5. Scroll-spy. Bước có mép trên vừa qua đáy header dính là bước hiện tại, sáng trong card (aria-current="step", vòng ring-accent). Bấm bước trong card: cuộn tới bằng scrollToCard (bù header, §2b), cập nhật {step} của URL bằng replaceState.
  6. Điện thoại (dưới lg): card thành một sheet gọn dính ngay dưới header, thu gọn mặc định (một dòng "Activity · Bước k/N" + chevron, Radix Collapsible, aria-expanded); chọn bước thì cuộn tới và thu lại. Vùng chạm ≥40px, trang không cuộn ngang ở 320/375px. Không dùng Sheet đáy: Sheet đáy đã là Mục lục.
  7. Ô tick của bước nằm trong card (và trong sheet): luật ở §12a.

Hiện thực dự kiến: dựng trên JourneyShell (bỏ hàng 3 khi trang truyền card), card là một component mới dùng chung ở apps/learn/src/components/, scroll-spy bằng IntersectionObserver với rootMargin âm đúng chiều cao header đo lúc chạy. Không thêm thư viện (motion + shadcn/ui + Tailwind).

12a. Tick bước: "Mình đã làm xong bước này" (SRC-1283) ​

Learner tick từng bước là đã làm xong; tiến độ lưu server theo learner. Ba loại bước, một luật xong:

LoạiXong khiÔ tick
có cổng đọc (§10)cổng qua 3/3không bấm được; tự tick khi qua; trước đó nói "Qua kiểm tra nhanh để xong phần này"
có câu kiểm máy chấmcâu đúng (hay mọi câu đã trả lời, với bước tổng kết)không bấm được; tự tick
tự làm (đọc câu hỏi, Mang theo, ví dụ, thực hành ngoài máy)learner tickbutton role="checkbox", aria-checked, vùng chạm ≥44px; bấm lại là bỏ
  • Tick không bao giờ là đường vòng qua cổng hay câu kiểm: server từ chối tick cho hai loại đầu.
  • Tick không đổi luật "qua" của lesson; card hiện "k/N bước" riêng với nhãn "đã qua".
  • Bước tự làm có thêm nút "Xong bước này" ở cuối bước trong vùng chính (cùng việc, rồi cuộn tới bước kế).
  • Khoá lưu theo id ổn định (slot lesson, id Activity, id Bước khai trong dữ liệu), không theo số hay vị trí.
  • Chưa có quyền lưu server (chưa ghi danh) thì giữ trong trình duyệt và nói rõ, ghi danh xong thì gửi lên.
  • Dữ liệu, API và quyền của AI Teen: SDD-043 §15.