The walkthrough section: a reading-order nav plus one numbered collapsible chapter per layer (first chapter open). Each chapter shows the canonical rationale, its tasks/criteria, `depends_on` anchor links to earlier chapters, and the per-file diffs scoped to that layer's files.
(report: &TriageReport)
| 619 | /// rationale, its tasks/criteria, `depends_on` anchor links to earlier |
| 620 | /// chapters, and the per-file diffs scoped to that layer's files. |
| 621 | fn render_walkthrough(report: &TriageReport) -> String { |
| 622 | // layer id → (1-based chapter number, title) for depends_on anchors. |
| 623 | let chapter_of: BTreeMap<&str, (usize, &str)> = report |
| 624 | .walkthrough |
| 625 | .iter() |
| 626 | .enumerate() |
| 627 | .map(|(i, l)| (l.id.as_str(), (i + 1, l.title.as_str()))) |
| 628 | .collect(); |
| 629 | |
| 630 | let mut h = String::new(); |
| 631 | h.push_str("<section id=\"walkthrough\">\n<h2>Walkthrough</h2>\n"); |
| 632 | h.push_str("<p class=\"tour-intro\">Guided reading order — foundations first.</p>\n"); |
| 633 | |
| 634 | // Reading-order nav. |
| 635 | h.push_str("<ol class=\"toc\">\n"); |
| 636 | for (i, layer) in report.walkthrough.iter().enumerate() { |
| 637 | h.push_str(&format!( |
| 638 | "<li><a href=\"#chapter-{}\">{}</a></li>\n", |
| 639 | i + 1, |
| 640 | html_escape(&layer.title) |
| 641 | )); |
| 642 | } |
| 643 | h.push_str("</ol>\n"); |
| 644 | |
| 645 | for (i, layer) in report.walkthrough.iter().enumerate() { |
| 646 | let n = i + 1; |
| 647 | let open = if i == 0 { " open" } else { "" }; |
| 648 | h.push_str(&format!( |
| 649 | "<details class=\"chapter\" id=\"chapter-{n}\"{open}>\n" |
| 650 | )); |
| 651 | h.push_str(&format!( |
| 652 | "<summary><span class=\"chapter-num\">{n}</span> <span class=\"chapter-title\">{}</span> <span class=\"stat\">{} file(s) · {} change(s)</span></summary>\n", |
| 653 | html_escape(&layer.title), |
| 654 | layer.files.len(), |
| 655 | layer.changes.len() |
| 656 | )); |
| 657 | h.push_str(&format!( |
| 658 | "<p class=\"rationale\">{}</p>\n", |
| 659 | html_escape(&layer.rationale) |
| 660 | )); |
| 661 | |
| 662 | // depends_on → anchor links to the chapters this one builds on. |
| 663 | if !layer.depends_on.is_empty() { |
| 664 | h.push_str("<div class=\"chapter-deps\">builds on: "); |
| 665 | let mut first = true; |
| 666 | for dep in &layer.depends_on { |
| 667 | if !first { |
| 668 | h.push_str(" · "); |
| 669 | } |
| 670 | first = false; |
| 671 | match chapter_of.get(dep.as_str()) { |
| 672 | Some((dn, title)) => h.push_str(&format!( |
| 673 | "<a href=\"#chapter-{dn}\">{dn}. {}</a>", |
| 674 | html_escape(title) |
| 675 | )), |
| 676 | // A dep outside the rendered set (defensive): plain text. |
| 677 | None => h.push_str(&html_escape(dep)), |
| 678 | } |
no test coverage detected