").count();
+ assert_eq!(wrap_count, 2, "两个 table 应各自包裹, got: {}", result);
+ // 中间段落不被误包
+ assert!(result.contains("\n
间隔
\n"));
+ }
+
+ #[test]
+ fn wrap_tables_handles_multiline_table() {
+ // pulldown-cmark 产出的 table HTML 是单行无换行的,但正则用 (?s) 跨行兼容手写 HTML。
+ let html = "
";
+ let result = wrap_tables(html);
+ assert!(
+ result.starts_with("
")
+ && result.ends_with("
"),
+ "跨行 table 应整体包裹, got: {}",
+ result
+ );
+ }
+
+ #[test]
+ fn wrap_tables_does_not_touch_non_table_html() {
+ let html = "
段落
";
+ let result = wrap_tables(html);
+ assert_eq!(result, html, "无 table 时应原样返回");
+ }
+
+ #[test]
+ fn wrap_tables_then_clean_preserves_div_and_table() {
+ // 端到端:wrap → clean_html,确认 sanitizer 放行 div.table-wrap 与内部 table 结构。
+ let html = "
";
+ let wrapped = wrap_tables(html);
+ let cleaned = clean_html(&wrapped);
+ assert!(
+ cleaned.contains(r#"
"#),
+ "clean_html 应保留 table-wrap div, got: {}",
+ cleaned
+ );
+ assert!(
+ cleaned.contains("
"),
+ "clean_html 应保留 table 标签, got: {}",
+ cleaned
+ );
+ }
+
+ #[test]
+ fn render_markdown_table_wrapped_in_scroll_container() {
+ // 端到端:markdown table 经渲染管线后应被 table-wrap div 包裹。
+ let result = render_markdown_enhanced("| A | B |\n|---|---|\n| 1 | 2 |\n");
+ assert!(
+ result.html.contains(r#"
"#),
+ "markdown table 应被 table-wrap 包裹, got: {}",
+ result.html
+ );
+ assert!(result.html.contains("
"));
+ }
+
#[test]
fn slugify_heading_simple() {
assert_eq!(slugify_heading("Hello World"), "hello-world");
diff --git a/src/components/frontend_layout.rs b/src/components/frontend_layout.rs
index 15c1462..40470ed 100644
--- a/src/components/frontend_layout.rs
+++ b/src/components/frontend_layout.rs
@@ -60,7 +60,7 @@ pub fn FrontendLayout() -> Element {
ThemeToggle {}
},
}
- main { class: "flex-1 w-full max-w-4xl mx-auto px-6 py-6 md:py-12 overflow-hidden",
+ main { class: "flex-1 w-full max-w-4xl mx-auto px-6 py-6 md:py-12 overflow-x-clip",
SuspenseBoundary { fallback: move |_| route_skeleton(&route), Outlet:: {} }
}
Footer {}