Skip to content

fix(mobile): don't open the sidebar drawer while selecting message text#5585

Open
BrunooMoniz wants to merge 1 commit into
odysseus-dev:devfrom
BrunooMoniz:fix/mobile-select-drawer
Open

fix(mobile): don't open the sidebar drawer while selecting message text#5585
BrunooMoniz wants to merge 1 commit into
odysseus-dev:devfrom
BrunooMoniz:fix/mobile-select-drawer

Conversation

@BrunooMoniz

Copy link
Copy Markdown
Contributor

Summary

On mobile, dragging to extend a text selection inside a chat message opened the left sidebar drawer. The swipe-to-open gesture in _initChatSwipeToOpenSidebar (static/js/sidebar-layout.js) armed for any one-finger horizontal drag that started anywhere over #chat-container, so growing a selection to copy a reply was captured as an edge-swipe and popped the drawer open over the text you were selecting. This PR gates the gesture so it arms only from a narrow 24px strip at the screen's left/right edge and bails whenever a text selection is active at touch start or appears/grows during the drag. A drag that starts over a message body is now left entirely to native text selection, while a genuine edge-swipe still opens the drawer on either side and the hamburger button and backdrop-tap close path are unchanged. The gesture is already mobile-only (gated to viewports narrower than 768px), so desktop is unaffected.

Target branch

  • This PR targets dev, not main. All PRs land in dev; main is curated by the maintainer at each release. If your PR is on main by accident, click "Edit" on this PR and change the base.

Linked Issue

Fixes #5584

Type of Change

  • Bug fix (non-breaking — fixes a confirmed issue)
  • New feature (non-breaking — adds new behaviour)
  • Breaking change (changes or removes existing behaviour)
  • Refactor / cleanup (behaviour unchanged)
  • Documentation only
  • CI / tooling / configuration

Checklist

  • I searched open issues and open PRs — this is not a duplicate.
  • This PR targets dev
  • My changes are limited to the scope described above — no unrelated refactors or whitespace changes mixed in.
  • I actually ran the app (docker compose up or uvicorn app:app) and verified the change works end-to-end. Type-checks and unit tests are not enough.

How to Test

Steps a reviewer can reproduce (full app):

  1. docker compose up -d --build, open the chat on a phone (or in DevTools with mobile/touch emulation and the viewport narrower than 768px).
  2. Send any prompt, wait for a reply, then press on the reply text and drag horizontally across it to select it (as you would to copy it).
  3. On current dev: the left sidebar drawer slides open over the message and the selection is interrupted. With this branch: the text selection extends normally and the drawer stays closed. A deliberate swipe from the very left/right screen edge still opens the drawer, and the hamburger button and backdrop tap still open/close it.

What was verified for this change:

  • The behaviour was confirmed in a mobile browser (WebKit, 390px) — current dev (before, drag-to-select opens the drawer) vs this branch (after, the selection stays and the drawer stays closed). See the screenshots below.
  • node --check static/js/sidebar-layout.js — passes.
  • python -m pytest tests/test_sidebar_swipe_js.py — 5 passed. The test loads the real module under Node and dispatches synthetic touch events: a mid-content selection drag, an edge-start drag with a live selection, and a selection that grows mid-drag all keep the drawer closed; a genuine left-edge and right-edge swipe both still open it. The three selection cases fail on current dev (the drawer opens) and pass on this branch, so the test pins the fix.
  • The change is limited to one client-side module plus its new test, so the rest of the pytest suite is unaffected.

Files changed:

  • static/js/sidebar-layout.js — the swipe-to-open handler now arms only from a narrow edge strip (EDGE_ZONE) and bails on an active or growing text selection (hasTextSelection); no styling, markup, or other behaviour changes.
  • tests/test_sidebar_swipe_js.py — a Node-driven regression test (same subprocess pattern as tests/test_markdown_rendering_js.py) that dispatches synthetic touch events against the real module.

Visual / UI changes — REQUIRED if you touched anything that renders

Anything that changes what the UI looks like — buttons, icons, padding, colors, fonts, spacing, layout, CSS, HTML, SVG, or any static/js/ module that draws to the DOM — needs all of the following.

  • Screenshot or short clip of the change in the running app, attached below. Mobile screenshot too if the change affects mobile.
    • How the screenshots were captured: the real static/js/sidebar-layout.js module and static/style.css rendered in WebKit at a mobile viewport (390x844) on the default dark theme, showing the drawer-open (before, current dev) vs drawer-closed with the selection intact (after, this branch). The gesture is mobile-only (gated below 768px), so there is no desktop case to show.
  • Style match: the change uses Odysseus's existing visual language. Specifically:
    • Reuse existing CSS variables (--red, --fg, --bg, --card, --border, etc.) — do not introduce new color values, font sizes, or spacing units.
    • Reuse existing button/input/card/border classes. Don't invent parallel styling.
    • No Unicode emoji in UI or code. Use inline SVG (matching the monochrome icon style already in static/index.html) or plain text.
    • Monospaced font (Fira Code) for primary UI text. Don't override.
    • Dark theme is the default; any light-mode work must be wired through the existing theme system, not hard-coded.
    • This change adds no CSS, markup, colors, fonts, or components — it only guards an existing touch gesture, so the visual language is unchanged.
  • No new component patterns. If a similar widget already exists in the app, extend it instead of writing a parallel one.
  • I am not an LLM agent submitting a bulk PR. If you are, please open an issue describing the problem first — bulk auto-generated PRs that don't match the project's visual style are closed on sight, even when the underlying fix is correct.

Screenshots / clips

Mobile — before (current dev)

select drawer before, mobile

Mobile — after (this PR)

select drawer after, mobile

On mobile, dragging to extend a text selection inside a chat message opened
the left sidebar drawer. The swipe-to-open gesture in
_initChatSwipeToOpenSidebar (static/js/sidebar-layout.js) armed for any
horizontal drag that started anywhere over the chat content, so growing a
selection to copy it was captured as an edge-swipe and popped the drawer open.

Arm the gesture only from a narrow 24px strip at the screen's left/right edge,
and bail whenever a text selection is active at touchstart or appears/grows
during the drag. A drag that starts over a message body is now left entirely to
native text selection, while a genuine edge-swipe still opens the drawer on
either side and the hamburger and backdrop-close paths are unchanged.

Adds tests/test_sidebar_swipe_js.py, which loads the real module under Node,
dispatches synthetic touch events, and asserts a mid-content selection drag
keeps the drawer closed while a true edge-swipe still opens it.
@github-actions github-actions Bot added the ready for review Description complete — ready for maintainer review label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review Description complete — ready for maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dragging to select message text opens the sidebar drawer on mobile

1 participant