From 63fb22b7eebb4e28da36b20beff19ad2fdb3678b Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Mon, 13 Apr 2026 00:08:30 -0700 Subject: [PATCH] fix: add table styles to .msg-body for readable bordered chat tables (fixes #341) (#345) * fix: add table CSS to .msg-body for readable bordered tables in chat (fixes #341) * fix: remove accidentally included ui.js and test_issue342.py from CSS-only PR * docs: combine v0.50.11 CHANGELOG entries, bump version badge * fix: restore ui.js from master (autolink already landed in #346) * fix: restore test_issue342.py deleted by cleanup commit (already on master) --------- Co-authored-by: Nathan Esquenazi --- CHANGELOG.md | 12 ++++-------- static/index.html | 2 +- static/style.css | 6 ++++++ tests/test_issue341.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 tests/test_issue341.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6601a9c..2b90c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,11 @@ --- +## [v0.50.11] Chat table styles + plain URL auto-linking (fixes #341, #342) -## [v0.50.11] Auto-link plain URLs in chat messages (fixes #342) - -- **Plain URLs in chat messages are now clickable** (`static/ui.js`): The `renderMd()` function previously only converted Markdown-style `[label](url)` links to `` tags. Bare URLs like `https://example.com` were rendered as plain text. A new autolink pass converts `https?://...` URLs to `` tags automatically. - - The pass runs after the `[label](url)` link pass and the `SAFE_TAGS` HTML-escape pass (protecting code blocks in `
`), but before the paragraph-wrapping stage.
-  - The same autolink pass is applied inside `inlineMd()` so URLs in list items, blockquotes, and table cells are linked too.
-  - Trailing punctuation (`.`, `,`, `;`, `:`, `!`, `?`, `)`) is stripped from the end of URLs to avoid linking sentence-ending characters.
-  - URLs are passed through `esc()` before placement in `href` and link text — no XSS risk.
-  - 7 new structural tests in `tests/test_issue342.py`; 809 tests total (up from 802)
+- **Tables in chat messages now render with visible borders** (`static/style.css`): The `.msg-body` area had no table CSS, so markdown tables sent by the assistant were unstyled and unreadable. Four new rules mirror the existing `.preview-md` table styles: `border-collapse:collapse`, per-cell padding and borders via `var(--border2)`, and an alternating-row tint. Two `:root[data-theme="light"]` overrides ensure the borders and header background adapt correctly in light mode. (fixes #341)
+- **Plain URLs in chat messages are now clickable** (`static/ui.js`): Bare URLs like `https://example.com` were rendered as plain text. A new autolink pass in `renderMd()` converts `https?://...` URLs to `` tags automatically. Runs after the SAFE_TAGS escape pass (protecting code blocks), before paragraph wrapping. Also applied inside `inlineMd()` so URLs in list items, blockquotes, and table cells are linked too. Trailing punctuation stripped; `esc()` applied to both href and link text. (fixes #342)
+  - 11 new tests (4 in `tests/test_issue341.py`, 7 in `tests/test_issue342.py`); 813 tests total (up from 802)
 
 ## [v0.50.10] Title auto-generation fix + mobile close button (PR #333)
 
diff --git a/static/index.html b/static/index.html
index 9eec0a4..cf7e8cf 100644
--- a/static/index.html
+++ b/static/index.html
@@ -526,7 +526,7 @@
                 
System
- v0.50.10 + v0.50.11
diff --git a/static/style.css b/static/style.css index 991b577..8ca8be2 100644 --- a/static/style.css +++ b/static/style.css @@ -66,7 +66,9 @@ :root[data-theme="light"] .panel-icon-btn:hover{background:rgba(0,0,0,.06);} :root[data-theme="light"] .file-item:hover{background:rgba(0,0,0,.04);} :root[data-theme="light"] .preview-md th{background:rgba(0,0,0,.04);} + :root[data-theme="light"] .msg-body th{background:rgba(0,0,0,.04);} :root[data-theme="light"] .preview-md td{border-color:rgba(0,0,0,.08);} + :root[data-theme="light"] .msg-body td{border-color:rgba(0,0,0,.08);} :root[data-theme="light"] .preview-badge.code{background:rgba(0,0,0,.05);} :root[data-theme="light"] .ctx-ring-center{background:var(--bg);color:#5a544a;} :root[data-theme="light"] .ctx-ring-track{stroke:rgba(0,0,0,.12);} @@ -369,6 +371,10 @@ .msg-body blockquote{border-left:3px solid var(--blue);padding-left:14px;color:var(--muted);font-style:italic;margin:10px 0;} .msg-body a{color:var(--blue);text-decoration:underline;} .msg-body hr{border:none;border-top:1px solid var(--border);margin:14px 0;} + .msg-body table{border-collapse:collapse;width:100%;margin:8px 0;font-size:12px;} + .msg-body th{background:rgba(255,255,255,.07);padding:6px 10px;text-align:left;font-weight:600;border:1px solid var(--border2);} + .msg-body td{padding:5px 10px;border:1px solid rgba(255,255,255,.06);} + .msg-body tr:nth-child(even){background:rgba(255,255,255,.03);} .msg-files{display:flex;flex-wrap:wrap;gap:6px;padding-left:30px;margin-bottom:10px;} .msg-file-badge{display:flex;align-items:center;gap:5px;background:rgba(124,185,255,0.1);border:1px solid rgba(124,185,255,0.25);border-radius:6px;padding:4px 9px;font-size:12px;color:var(--blue);} .thinking{display:flex;align-items:center;gap:5px;color:var(--muted);font-size:13px;padding-left:30px;} diff --git a/tests/test_issue341.py b/tests/test_issue341.py new file mode 100644 index 0000000..63bf0b0 --- /dev/null +++ b/tests/test_issue341.py @@ -0,0 +1,34 @@ +"""Tests for GitHub issue #341: .msg-body table CSS styles.""" +import os + +CSS_PATH = os.path.join(os.path.dirname(__file__), "..", "static", "style.css") + + +def _read_css(): + with open(CSS_PATH, "r") as f: + return f.read() + + +def test_msg_body_table_css_present(): + css = _read_css() + assert ".msg-body table" in css, ".msg-body table rule missing from style.css" + assert "border-collapse:collapse" in css, "border-collapse:collapse missing from style.css" + + +def test_msg_body_table_th_td_present(): + css = _read_css() + assert ".msg-body th" in css, ".msg-body th rule missing from style.css" + assert ".msg-body td" in css, ".msg-body td rule missing from style.css" + + +def test_msg_body_table_tr_stripe_present(): + css = _read_css() + assert ".msg-body tr:nth-child(even)" in css, ".msg-body tr:nth-child(even) rule missing from style.css" + + +def test_msg_body_light_theme_overrides(): + css = _read_css() + assert ':root[data-theme="light"] .msg-body th' in css, \ + 'Light-theme override for .msg-body th missing from style.css' + assert ':root[data-theme="light"] .msg-body td' in css, \ + 'Light-theme override for .msg-body td missing from style.css'