From 6bdce2c1ed3d7458a7188068bf915993bab1daa0 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Tue, 19 May 2026 19:02:47 +0000 Subject: [PATCH] fix: make tutor chat close X actually close the panel Root cause: .tutor-chat__panel sets `display: flex`, which has the same specificity as the UA stylesheet's `[hidden] { display: none }` rule. Because author stylesheets win cascade ties over UA, the `hidden` attribute was a no-op and the panel never actually hid when the X was clicked. Changes - tutor-chat.css: add `.tutor-chat__panel[hidden] { display: none }` so the hidden attribute reliably hides the panel; bump panel z-index to 61 so it is unambiguously above the FAB (both were 60). - tutor-chat.js: add `type="button"` to FAB and close to keep behavior predictable; make the close SVG non-interactive (pointer-events="none", focusable="false") so the click target is always the button; call preventDefault on both, and stopPropagation on the close click. - index.html + sw.js: bump cache-busting versions so the SW picks up the fixed assets. - tests: two new static checks asserting the regression cannot return: the [hidden] CSS rule must be present, and the close button must be wired with toggle(false, ...). --- backend/tests/test_frontend_integration.py | 20 ++++++++++++++++++++ frontend/index.html | 4 ++-- frontend/sw.js | 2 +- frontend/tutor-chat.css | 8 +++++++- frontend/tutor-chat.js | 17 ++++++++++++----- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/backend/tests/test_frontend_integration.py b/backend/tests/test_frontend_integration.py index fa9a171..b2fb10a 100644 --- a/backend/tests/test_frontend_integration.py +++ b/backend/tests/test_frontend_integration.py @@ -82,6 +82,26 @@ def test_index_html_references_chat_assets() -> None: assert 'meta name="tutor-backend"' in index +def test_chat_panel_hidden_attribute_works() -> None: + """Regression: the panel's `display: flex` overrides the UA stylesheet's + `[hidden] { display: none }` rule because they share specificity, so + clicking the close X never actually hid the panel. The CSS must re-assert + `display: none` for the hidden state.""" + css = (FRONTEND_DIR / "tutor-chat.css").read_text(encoding="utf-8") + assert re.search( + r"\.tutor-chat__panel\[hidden\]\s*\{[^}]*display\s*:\s*none", + css, + ), "tutor-chat.css must re-assert display:none for .tutor-chat__panel[hidden]" + + +def test_chat_close_button_is_wired() -> None: + """The close X must have a click handler that calls toggle(false, ...).""" + js = (FRONTEND_DIR / "tutor-chat.js").read_text(encoding="utf-8") + assert "tutorChatClose" in js + assert "closeBtn.addEventListener('click'" in js or 'closeBtn.addEventListener("click"' in js + assert "toggle(false" in js + + def test_chat_js_posts_to_api_chat() -> None: js = (FRONTEND_DIR / "tutor-chat.js").read_text(encoding="utf-8") # The module must POST to /api/chat with a JSON body containing `messages`. diff --git a/frontend/index.html b/frontend/index.html index 4470db0..0390259 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -79,7 +79,7 @@ - +