Skip to content

Staging#109

Merged
gkorland merged 3 commits intomainfrom
staging
Aug 23, 2025
Merged

Staging#109
gkorland merged 3 commits intomainfrom
staging

Conversation

@gkorland
Copy link
Contributor

@gkorland gkorland commented Aug 22, 2025

Summary by CodeRabbit

  • New Features
    • Added a collapsible left toolbar with a burger toggle; opens on desktop, collapses on mobile.
    • Moved the theme toggle into the left toolbar.
  • Style
    • Refined mobile layout: smoother transitions, adjusted paddings, and consistent button sizing.
    • Updated toolbar visuals when collapsed/expanded; removed “pressed” styling from toolbar buttons.
  • Bug Fixes
    • Improved small-screen usability: prevents horizontal overflow, ensures inputs and controls fit within the viewport, and stabilizes chat/header layouts.
  • Accessibility
    • Made the menu button keyboard-focusable (tab navigation).

@vercel
Copy link

vercel bot commented Aug 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
queryweaver Ready Ready Preview Comment Aug 22, 2025 6:18pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 22, 2025

Walkthrough

Implements a collapsible left toolbar with a burger toggle, removes active-state styling for toolbar buttons, adds mobile-responsive CSS for chat and layout, and injects JS to manage open/close state with media-query awareness and a minimal window.__leftToolbar API.

Changes

Cohort / File(s) Summary
Left toolbar collapse/toggle CSS
app/public/css/buttons.css
Removes .toolbar-button[aria-pressed="true"]. Adds #left-toolbar.collapsed state, hides toolbar buttons when collapsed, positions a dedicated #burger-toggle-btn, and introduces mobile rules via @media (max-width: 767px) to toggle collapsed/not-collapsed behaviors.
Chat mobile spacing
app/public/css/chat-components.css
Adds @media (max-width: 768px) to reduce chat paddings, constrain widths, hide horizontal overflow, and transition margin-left to align with toolbar presence.
Global mobile responsive/layout updates
app/public/css/responsive.css
Adds body/container adjustments for left-toolbar-open state on mobile: shifts content, constrains widths, adjusts backgrounds, refactors header control layouts, and refines breakpoints (including a narrower 480px block) with input/button sizing updates.
Left toolbar template and behavior
app/templates/components/left_toolbar.j2
Removes logo slot, adds burger toggle button, relocates theme toggle into toolbar, minor icon/markup updates, makes menu button focusable, and adds an IIFE script that manages toolbar open/close state, ARIA/title updates, media-query responsiveness, pointer handling, and exposes window.__leftToolbar API.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant B as Burger Button
  participant LT as Left Toolbar (nav#left-toolbar)
  participant BD as Body (document.body)
  participant MQ as MediaQuery (min-width:768px)
  participant API as window.__leftToolbar

  note over MQ,LT: Initialize on load
  MQ->>API: Determine default state (desktop=open, mobile=collapsed)
  API->>LT: Add/Remove .collapsed
  API->>BD: Add/Remove .left-toolbar-open
  API->>B: Set aria-pressed/expanded, title

  U->>B: pointerdown (toggle)
  B->>API: toggle()
  API->>LT: Toggle .collapsed
  API->>BD: Toggle .left-toolbar-open
  API->>B: Update ARIA/title

  MQ-->>API: change (viewport resized)
  API->>LT: Sync state for breakpoint
  API->>BD: Sync body class
  API->>B: Sync ARIA/title
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • galshubeli

Poem

A tap on the bun, the toolbar slides wide,
I twitch with delight as icons now hide.
On phones I hop light, margins in flow,
A moon-sun waltz in responsive glow.
Burger goes click—left pane says hi!
Carrots align; no overflow—oh my! 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/public/css/responsive.css (1)

58-63: Unify all remaining 768px media queries to 767px for consistency.

There are multiple blocks still using @media (max-width: 768px). Align them all to 767px to avoid the 768px overlap with desktop logic.

Example (apply similarly to all blocks listed in this comment):

-@media (max-width: 768px) {
+@media (max-width: 767px) {

Also applies to: 65-79, 81-99, 101-177, 179-200, 203-208, 211-224, 225-256, 258-264, 267-287, 291-296, 299-305, 308-314

🧹 Nitpick comments (7)
app/public/css/chat-components.css (2)

36-47: Remove no-op transition or make it effective.

.chat-container transitions margin-left here, but this selector never changes margin-left in this file. The shift is applied to #container in responsive.css. Keep transitions only where properties actually change to avoid confusion and unnecessary paint costs.

Apply:

   .chat-container {
@@
-    /* Ensure content is accessible when toolbar is open */
-    transition: margin-left 220ms ease;
+    /* No margin-left transition here: #container owns the shift */

31-48: Respect prefers-reduced-motion for smoother accessibility.

Mobile introduces several transitions. Offer an opt-out for motion-sensitive users.

Append right after this block:

+@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
+  .chat-container { transition: none !important; }
+}
app/public/css/responsive.css (2)

22-23: Add prefers-reduced-motion guard for layout shifts.

The container shifts via margin-left animation. Honor users who prefer reduced motion.

Append:

+@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
+  #container,
+  .chat-container {
+    transition: none !important;
+  }
+}

Also applies to: 225-231


133-149: Review responsive header sizing at narrow viewports (≤320px)

The three header controls at app/public/css/responsive.css (lines 133–149) each have flex: 1 and min-width: 0 but are capped at 30%/35%/35% of the container—with a gap of 8 px between items—so at a 320 px viewport you end up with:

  • Container content width: 320 px – (2×10 px padding) = 300 px
  • Total max-width: 30%·300 px + 35%·300 px + 35%·300 px = 300 px
  • Total gaps: 2×8 px = 16 px
    → 300 px + 16 px = 316 px > 300 px available

This will force at least one control below its cap and risks visible overflow or clipping.

• Pinpoint locations:
– app/public/css/responsive.css:133–135 (#graph-select max-width: 30%)
– app/public/css/responsive.css:137–142 (#custom-file-upload max-width: 35%)
– app/public/css/responsive.css:146–149 (.dropdown-container max-width: 35%)

• Next steps:

  1. Manually test the chat header at exactly 320 px (e.g. using your browser’s device toolbar) and confirm there’s no horizontal scroll or clipped controls.
  2. If you see overflow, consider either:
    • Reducing the caps (for example, 28%/32%/32%), or
    • Allowing the controls to wrap (e.g. add flex-wrap: wrap below 360 px), or
    • Introducing a tighter media query (@media (max-width: 360px) { … }) with adjusted layout
app/public/css/buttons.css (1)

362-375: Use a shared CSS variable for the 48px toolbar width and honor reduced motion.

You hard-code 48px repeatedly. Switch to a custom property with a fallback and add a motion guard.

Apply representative changes (repeat similarly for all 48px instances in this file):

-#left-toolbar {
+/* Use var with fallback in case :root isn't loaded yet */
 #left-toolbar {
   position: fixed;
   top: 0px;
   bottom: 0px;
-  width: 48px;
+  width: var(--left-toolbar-width, 48px);
@@
-#left-toolbar.collapsed #burger-toggle-btn {
+#left-toolbar.collapsed #burger-toggle-btn {
   display: flex;
-  width: 48px;
-  height: 48px;
+  width: var(--left-toolbar-width, 48px);
+  height: var(--left-toolbar-width, 48px);
@@
-#left-toolbar:not(.collapsed) {
+#left-toolbar:not(.collapsed) {
-  width: 48px;
+  width: var(--left-toolbar-width, 48px);
-  padding: 6px 6px;
+  padding: 6px 6px;

And append once:

+@media (prefers-reduced-motion: reduce) {
+  #left-toolbar { transition: none !important; }
+  #left-toolbar.collapsed { transition: none !important; }
+}

Also applies to: 393-438

app/templates/components/left_toolbar.j2 (2)

75-92: Optionally hide collapsed toolbar from the accessibility tree.

When collapsed, most buttons are display:none, but marking the nav as inert/hidden avoids accidental AT navigation into the container.

Apply inside setOpen:

 function setOpen(open) {
   if (open) {
     nav.classList.remove('collapsed');
     document.body.classList.add('left-toolbar-open');
+    nav.removeAttribute('inert');
+    nav.removeAttribute('aria-hidden');
@@
   } else {
     nav.classList.add('collapsed');
     document.body.classList.remove('left-toolbar-open');
+    nav.setAttribute('inert', '');
+    nav.setAttribute('aria-hidden', 'true');

Note: inert is broadly supported now; degrades harmlessly if unsupported.


94-104: Persist user preference across reloads (optional).

Mobile users expect the last open/closed state to stick.

Append minimal persistence:

-    try {
-        setOpen(mq.matches);
+    try {
+        const saved = localStorage.getItem('leftToolbarOpen');
+        setOpen(saved != null ? saved === '1' : mq.matches);
     } catch (e) {
         // fail-safe: keep open
         setOpen(true);
     }
@@
     function setOpen(open) {
         if (open) {
@@
         } else {
@@
         }
+        try { localStorage.setItem('leftToolbarOpen', open ? '1' : '0'); } catch {}
     }

I can wire this and add a Cypress/Playwright check if you’d like.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9dbd577 and f2fba00.

📒 Files selected for processing (4)
  • app/public/css/buttons.css (1 hunks)
  • app/public/css/chat-components.css (1 hunks)
  • app/public/css/responsive.css (3 hunks)
  • app/templates/components/left_toolbar.j2 (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: e2e-tests
  • GitHub Check: e2e-tests
🔇 Additional comments (2)
app/public/css/buttons.css (1)

393-438: Approve: mobile collapsed/open behavior is thoughtfully handled.

The collapsed state with pointer-events gating and explicit visibility of the burger works well on touch targets. Good job keeping “no-JS” mobile fallback coherent.

app/templates/components/left_toolbar.j2 (1)

94-111: Approve: robust mq listener (new/old APIs) and clean state sync.

Nice use of addEventListener('change') with addListener fallback and centralized setOpen to update DOM + ARIA state.

Comment on lines +381 to +391
#left-toolbar.collapsed #burger-toggle-btn {
display: flex;
width: 48px;
height: 48px;
margin: 6px 0;
position: absolute;
top: 6px;
left: 6px;
z-index: 9999; /* keep on top so it's always clickable */
pointer-events: auto;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Lower burger z-index to fit your stacking context (avoid covering modals).

Burger uses z-index: 9999, while modals/buttons are in the ~100–2000 range. This can put the burger above dialogs/tooltips unintentionally.

Apply:

 #left-toolbar.collapsed #burger-toggle-btn {
   display: flex;
   width: 48px;
   height: 48px;
   margin: 6px 0;
   position: absolute;
   top: 6px;
   left: 6px;
-  z-index: 9999; /* keep on top so it's always clickable */
+  z-index: 2001; /* above header buttons (2000), below modals as needed */
   pointer-events: auto;
 }

Scan z-index usage to confirm the scale:


🏁 Script executed:

#!/bin/bash
rg -nP 'z-index\s*:\s*\d+' app/public/css | sort -t: -k3,3n

Length of output: 848


Lower burger toggle z-index to sit below modals and above header buttons

The #left-toolbar.collapsed #burger-toggle-btn is currently set to z-index: 9999, which will render it above all modals (whose highest z-index in app/public/css/modals.css is 3000) and risk covering dialogs or tooltips. We should reduce it to 2001 so it still appears above header buttons (z-index 2000) but below any modal layers.

Affected location:

  • File: app/public/css/buttons.css
    Lines: ~381–391

Proposed change:

 #left-toolbar.collapsed #burger-toggle-btn {
   display: flex;
   width: 48px;
   height: 48px;
   margin: 6px 0;
   position: absolute;
   top: 6px;
   left: 6px;
-  z-index: 9999; /* keep on top so it's always clickable */
+  z-index: 2001; /* above header buttons (2000), below modals (>=3000) */
   pointer-events: auto;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#left-toolbar.collapsed #burger-toggle-btn {
display: flex;
width: 48px;
height: 48px;
margin: 6px 0;
position: absolute;
top: 6px;
left: 6px;
z-index: 9999; /* keep on top so it's always clickable */
pointer-events: auto;
}
#left-toolbar.collapsed #burger-toggle-btn {
display: flex;
width: 48px;
height: 48px;
margin: 6px 0;
position: absolute;
top: 6px;
left: 6px;
z-index: 2001; /* above header buttons (2000), below modals (>=3000) */
pointer-events: auto;
}
🤖 Prompt for AI Agents
In app/public/css/buttons.css around lines 381 to 391 the
#left-toolbar.collapsed #burger-toggle-btn rule sets z-index: 9999 which forces
the burger toggle above modals; change that z-index to 2001 so the toggle
remains above header buttons (z-index 2000) but beneath modal layers (max
z-index ~3000) — update the z-index value in that rule to 2001 and keep the rest
of the rule unchanged.

Comment on lines +31 to +48
@media (max-width: 768px) {
.chat-messages {
padding: 2px;
}

.chat-container {
padding-right: 10px;
padding-left: 10px;
padding-top: 10px;
padding-bottom: 10px;
/* Ensure no horizontal overflow */
max-width: 100vw;
overflow-x: hidden;
box-sizing: border-box;
/* Ensure content is accessible when toolbar is open */
transition: margin-left 220ms ease;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix 768 vs 767 breakpoint mismatch (off-by-one at exactly 768px).

JS uses (min-width: 768px) for “desktop”, and buttons.css uses @media (max-width: 767px) for “mobile”. Here you use @media (max-width: 768px), which causes the mobile chat rules to apply at exactly 768px while the toolbar treats 768px as desktop. Unify to 767px to avoid layout jitter at 768px.

Apply:

-@media (max-width: 768px) {
+@media (max-width: 767px) {
🤖 Prompt for AI Agents
In app/public/css/chat-components.css around lines 31 to 48, the media query
uses @media (max-width: 768px) which conflicts with other files that treat 768px
as desktop; change the breakpoint to @media (max-width: 767px) so mobile styles
apply up to 767px and 768px is consistently handled as desktop; update that
single media rule and verify related comments remain accurate.

Comment on lines +5 to +15
/* When left toolbar is open, push content to make room */
body.left-toolbar-open .chat-container {
max-width: calc(100vw - 48px);
}

/* Ensure body doesn't overflow */
body {
max-width: 100vw;
overflow-x: hidden;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize breakpoint and de-duplicate the “48px” constant via a CSS variable.

  • Breakpoint: Align with JS/buttons (desktop ≥ 768, mobile ≤ 767). Use max-width: 767px here.
  • DRY: The left toolbar width (48px) is hard-coded multiple times. Use a shared custom property so updates don’t require multi-file edits.

Apply:

-@media (max-width: 768px) {
+@media (max-width: 767px) {
-  body.left-toolbar-open .chat-container {
-    max-width: calc(100vw - 48px);
-  }
+  body.left-toolbar-open .chat-container {
+    max-width: calc(100vw - var(--left-toolbar-width, 48px));
+  }
@@
-  #container {
+  #container {
     width: 100%;
     max-width: 100vw;
     overflow-x: hidden;
     box-sizing: border-box;
     transition: margin-left 220ms ease;
   }
@@
-  body.left-toolbar-open #container {
-    margin-left: 48px;
-    width: calc(100% - 48px);
-    max-width: calc(100vw - 48px);
-  }
+  body.left-toolbar-open #container {
+    margin-left: var(--left-toolbar-width, 48px);
+    width: calc(100% - var(--left-toolbar-width, 48px));
+    max-width: calc(100vw - var(--left-toolbar-width, 48px));
+  }

And near the top of a globally loaded CSS (or here if that’s acceptable):

+:root {
+  /* Single source of truth for the mobile toolbar width */
+  --left-toolbar-width: 48px;
+}

Also applies to: 16-24, 25-31, 37-41, 43-54

🤖 Prompt for AI Agents
In app/public/css/responsive.css around lines 5 to 15, the CSS uses a hard-coded
48px toolbar width and an inconsistent breakpoint; create a custom property
(e.g., --left-toolbar-width: 48px) near the top of a globally loaded CSS file
(or at the top of this file) and replace all literal 48px occurrences with
calc(var(--left-toolbar-width)); update the responsive breakpoint to use
max-width: 767px for mobile (and ensure any corresponding media queries follow
desktop ≥768px / mobile ≤767px logic), and apply the same replacement for the
other affected ranges (lines 16-24, 25-31, 37-41, 43-54).

Comment on lines +6 to +13
<button id="burger-toggle-btn" class="action-button toolbar-button" title="Open menu" aria-label="Open menu">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="6" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="11" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="16" width="18" height="2" rx="1" fill="currentColor" />
</svg>
</button>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add aria-controls and initial aria-expanded for the burger button.

Improves AT context and aligns with the toggling behavior you already implement.

Apply:

-<button id="burger-toggle-btn" class="action-button toolbar-button" title="Open menu" aria-label="Open menu">
+<button id="burger-toggle-btn"
+        class="action-button toolbar-button"
+        title="Open menu"
+        aria-label="Open menu"
+        aria-controls="left-toolbar"
+        aria-expanded="false">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button id="burger-toggle-btn" class="action-button toolbar-button" title="Open menu" aria-label="Open menu">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="6" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="11" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="16" width="18" height="2" rx="1" fill="currentColor" />
</svg>
</button>
<button id="burger-toggle-btn"
class="action-button toolbar-button"
title="Open menu"
aria-label="Open menu"
aria-controls="left-toolbar"
aria-expanded="false">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="6" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="11" width="18" height="2" rx="1" fill="currentColor" />
<rect x="3" y="16" width="18" height="2" rx="1" fill="currentColor" />
</svg>
</button>
🤖 Prompt for AI Agents
In app/templates/components/left_toolbar.j2 around lines 6 to 13, the burger
toggle button is missing ARIA attributes: add aria-controls="<id-of-side-menu>"
referencing the id of the element the button toggles and set an initial
aria-expanded="false" on the button; ensure the referenced side menu element has
the same id and update aria-expanded to "true"/"false" when the menu is
opened/closed by your existing toggle logic.

Comment on lines +15 to +19
<button id="theme-toggle-btn" class="action-button toolbar-button" title="Toggle Theme"
aria-label="Toggle theme" aria-pressed="false" tabindex="-1">
<svg class="theme-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle class="sun" cx="12" cy="12" r="5" stroke="currentColor" stroke-width="2"/>
<path class="sun" d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72l1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" stroke="currentColor" stroke-width="2"/>
<path class="moon" d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" fill="currentColor"/>
<svg class="theme-icon" width="18" height="18" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<circle class="sun" cx="12" cy="12" r="5" stroke="currentColor" stroke-width="2" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Keyboard accessibility: remove tabindex="-1" from toolbar items (or implement a roving tabindex).

With tabindex="-1", Theme and Schema buttons are unreachable via Tab. Either remove the attribute or implement full roving tabindex with Arrow key handling.

Apply minimal fix:

-<button id="theme-toggle-btn" class="action-button toolbar-button" title="Toggle Theme"
-                aria-label="Toggle theme" aria-pressed="false" tabindex="-1">
+<button id="theme-toggle-btn" class="action-button toolbar-button" title="Toggle Theme"
+                aria-label="Toggle theme" aria-pressed="false">
@@
-<button class="action-button toolbar-button" id="schema-button" title="Schema" aria-label="Open schema"
-                aria-pressed="false" tabindex="-1">
+<button class="action-button toolbar-button" id="schema-button" title="Schema" aria-label="Open schema"
+                aria-pressed="false">

If you prefer roving tabindex, I can provide a compact handler.

Also applies to: 48-50

🤖 Prompt for AI Agents
In app/templates/components/left_toolbar.j2 around lines 15-19 (and also lines
48-50), toolbar buttons currently use tabindex="-1", which prevents keyboard Tab
focus; remove the tabindex="-1" attributes from these button elements so they
become tabbable by default (or, if you opt for a roving tabindex solution,
implement a single tabindex="0" for the active item plus Arrow key handlers to
move focus and update tabindex values accordingly). Ensure all toolbar buttons
are reachable via Tab after the change.

Comment on lines +94 to +111

// Media query: desktop when >= 768px (adjust if your breakpoints differ)
const mq = window.matchMedia('(min-width: 768px)');

// Initialize based on media query: desktop -> open, mobile -> closed
try {
setOpen(mq.matches);
} catch (e) {
// fail-safe: keep open
setOpen(true);
}

// Listen for viewport changes and update default state accordingly
if (typeof mq.addEventListener === 'function') {
mq.addEventListener('change', (ev) => setOpen(ev.matches));
} else if (typeof mq.addListener === 'function') {
mq.addListener((ev) => setOpen(ev.matches));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid preventing focus for mouse users; restrict pointerdown handling to touch/pen only.

e.preventDefault() on pointerdown suppresses focus for mouse clicks and may harm accessibility. Use it only for touch/pen to avoid double-toggles; let mouse clicks focus the button.

Apply:

-  btn.addEventListener('pointerdown', function (e) {
-      // Prevent unwanted focus/ghost clicks and handle touch/pen/mouse uniformly
-      e.preventDefault();
-      handleToggleEvent();
-      // ignore the following 'click' event which may also fire
-      ignoreNextClick = true;
-  });
+  btn.addEventListener('pointerdown', function (e) {
+      if (e.pointerType === 'touch' || e.pointerType === 'pen') {
+          e.preventDefault();        // avoid 300ms delay / ghost click
+          handleToggleEvent();
+          ignoreNextClick = true;    // consume the synthesized click
+      }
+  });

Also applies to: 119-135

🤖 Prompt for AI Agents
In app/templates/components/left_toolbar.j2 around lines 94-111 (and also apply
same fix to 119-135), the current pointerdown handler calls e.preventDefault()
unconditionally which prevents mouse clicks from focusing the button; change the
handler to only call e.preventDefault() when the pointer is touch or pen (e.g.
if (e.pointerType === 'touch' || e.pointerType === 'pen') { e.preventDefault();
}) so mouse pointer events still allow normal focus and keyboard accessibility
while preventing double-toggle on touch/pen.

@gkorland gkorland merged commit 7710f34 into main Aug 23, 2025
14 of 16 checks passed
This was referenced Aug 24, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant