Skip to content

feat(site): mobile bottom nav + responsive fixes#10

Merged
michaelmcnees merged 5 commits into
mainfrom
feat/mobile-nav-improvements
Mar 24, 2026
Merged

feat(site): mobile bottom nav + responsive fixes#10
michaelmcnees merged 5 commits into
mainfrom
feat/mobile-nav-improvements

Conversation

@michaelmcnees

@michaelmcnees michaelmcnees commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replaces top mobile navigation with a fixed bottom navigation bar for better thumb reachability
  • Fixes event listener cleanup using cloneNode pattern to prevent duplicate handlers on Astro page transitions
  • Adds overflow-x-hidden on docs container and word-break: break-word for inline code on mobile
  • Normalizes breakpoints to md across bottom nav visibility and padding
  • Removes dead .table-wrapper CSS (no component uses it; :has(table) handles overflow)

Test plan

  • Verify bottom nav appears on mobile viewports and hides at md breakpoint
  • Confirm sidebar toggle works on docs pages without duplicate event listeners after navigating between pages
  • Check table overflow scrolls correctly on narrow screens
  • Verify inline code elements wrap properly on mobile
  • Confirm home and docs pages have correct bottom padding (no content hidden behind nav)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed horizontal overflow visibility on documentation pages.
    • Improved inline code wrapping on small screens.
    • Resolved mobile sidebar and bottom-nav interaction issues for more reliable open/close and overlay taps.
  • Style

    • Adjusted mobile navigation visibility breakpoint.
    • Updated responsive spacing on home and documentation layouts.

michaelmcnees and others added 3 commits March 24, 2026 09:12
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…achability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dead styles — no component or rehype plugin wraps tables in a
.table-wrapper div. The existing :has(table) rule handles overflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c82911c3-6725-4cd2-8091-10586db5e13e

📥 Commits

Reviewing files that changed from the base of the PR and between c527f88 and 7986f09.

📒 Files selected for processing (3)
  • site/src/components/Nav.astro
  • site/src/layouts/Docs.astro
  • site/src/pages/index.astro

📝 Walkthrough

Walkthrough

Cloned-and-replaced interactive DOM nodes for sidebar and nav, moved click handlers and ARIA updates to the clones or live queries, adjusted mobile visibility breakpoint for bottom nav, reduced bottom padding on docs pages and added overflow-x-hidden, and changed mobile inline-code wrapping to use break-word.

Changes

Cohort / File(s) Summary
Sidebar event handling
site/src/components/DocsSidebar.astro
Clones #sidebar-overlay (cloneNode(true)), replaces the original, wires mobile close behavior to the clone, and updates closeSidebar() to hide/set aria-hidden on the cloned overlay; uses addEventListener on the clone for clicks.
Nav event handling & mobile visibility
site/src/components/Nav.astro
Changed mobile bottom nav visibility from lg:hidden to md:hidden; removed early-exit requiring #sidebar-overlay; replaces #bottom-nav-docs-btn with a cloned node and moves ARIA init/toggle and click handling to that clone; click handler re-queries the live #sidebar-overlay and toggles hidden/aria-hidden.
Layout spacing & overflow
site/src/layouts/Docs.astro, site/src/pages/index.astro
Reduced default bottom padding from pb-20 to pb-16 while preserving lg:pb-0; added overflow-x-hidden to the Docs layout outer container.
Mobile code wrapping
site/src/styles/global.css
In the mobile media query, replaced overflow-wrap: anywhere + word-break: normal with overflow-wrap: break-word for .prose code to change inline code wrapping behavior on small screens.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant NavBtn as Nav Button (cloned)
    participant Sidebar as Docs Sidebar
    participant Overlay as `#sidebar-overlay` (live)

    User->>NavBtn: click
    NavBtn->>Overlay: query current '#sidebar-overlay'
    NavBtn->>Overlay: toggle hidden / set aria-hidden
    NavBtn->>Sidebar: toggle open state (aria-expanded)
    User->>Overlay: click
    Overlay->>Sidebar: invoke closeSidebar (handler on cloned overlay)
    Sidebar->>Overlay: set hidden / aria-hidden
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through DOMs and made a swap,
Cloned a button, then closed the gap.
Breakpoints trimmed and overflow tamed,
Inline code wraps now better named.
A tiny hop — the UI's changed, unframed.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: introducing mobile bottom navigation and making responsive fixes across multiple components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mobile-nav-improvements

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
site/src/components/Nav.astro (1)

78-107: ⚠️ Potential issue | 🟠 Major

Stale overlay reference: initNav captures the old overlay node after DocsSidebar replaces it.

DocsSidebar.astro clones and replaces #sidebar-overlay in its initSidebar() function, which runs synchronously on script load. Meanwhile, initNav() is deferred via requestAnimationFrame until the sidebar exists. By the time initNav runs and captures overlay (line 81), the original overlay has already been replaced by DocsSidebar, so all subsequent operations on overlay (lines 96-97, 103-104) target a detached DOM node.

🐛 Proposed fix: Re-query overlay inside the click handler
   newBtn.addEventListener('click', () => {
+    const overlay = document.getElementById('sidebar-overlay');
+    if (!overlay) return;
     const isOpen = !docsSidebar.classList.contains('-translate-x-full');
     if (isOpen) {
       docsSidebar.classList.add('-translate-x-full');
       docsSidebar.setAttribute('aria-hidden', 'true');
       docsSidebar.inert = true;
       overlay.classList.add('hidden');
       overlay.setAttribute('aria-hidden', 'true');
       newBtn.setAttribute('aria-expanded', 'false');
     } else {
       docsSidebar.classList.remove('-translate-x-full');
       docsSidebar.setAttribute('aria-hidden', 'false');
       docsSidebar.inert = false;
       overlay.classList.remove('hidden');
       overlay.setAttribute('aria-hidden', 'false');
       newBtn.setAttribute('aria-expanded', 'true');
     }
   });

And remove the early-exit check for overlay at line 82, or keep it as a sanity check for initial load:

-  if (!btn || !docsSidebar || !overlay) return;
+  if (!btn || !docsSidebar) return;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@site/src/components/Nav.astro` around lines 78 - 107, initNav currently
captures the overlay DOM node once (const overlay =
document.getElementById('sidebar-overlay')) but DocsSidebar.astro's initSidebar
may clone/replace that element, so the click handler operates on a stale
detached node; to fix, stop relying on the cached overlay inside initNav —
either remove the strict early-return for overlay or keep it as a sanity check,
and re-query document.getElementById('sidebar-overlay') inside the newBtn click
handler before toggling classes/aria attributes; make the same change for any
overlay operations (overlay.classList..., overlay.setAttribute...) so they
always target the current DOM node.
site/src/components/DocsSidebar.astro (1)

190-205: ⚠️ Potential issue | 🟠 Major

Stale closure reference: closeSidebar operates on the replaced overlay node.

After cloning and replacing the overlay at lines 200-201, the closeSidebar function still references the original overlay variable from the outer scope. When closeSidebar is called (via link clicks or the cloned overlay click), it will manipulate the old, removed DOM node instead of newOverlay.

🐛 Proposed fix
+  let currentOverlay = overlay;
+
   function closeSidebar() {
     mobileSidebar.classList.add('-translate-x-full');
     mobileSidebar.setAttribute('aria-hidden', 'true');
     mobileSidebar.inert = true;
-    overlay.classList.add('hidden');
-    overlay.setAttribute('aria-hidden', 'true');
+    currentOverlay.classList.add('hidden');
+    currentOverlay.setAttribute('aria-hidden', 'true');
     var menuBtn = document.getElementById('bottom-nav-docs-btn');
     if (menuBtn) menuBtn.setAttribute('aria-expanded', 'false');
   }

   const newOverlay = overlay.cloneNode(true);
   overlay.parentNode?.replaceChild(newOverlay, overlay);
+  currentOverlay = newOverlay;
   newOverlay.addEventListener('click', closeSidebar);

Alternatively, re-query the overlay by ID inside closeSidebar to always get the current DOM element:

♻️ Alternative fix using getElementById
   function closeSidebar() {
+    var currentOverlay = document.getElementById('sidebar-overlay');
     mobileSidebar.classList.add('-translate-x-full');
     mobileSidebar.setAttribute('aria-hidden', 'true');
     mobileSidebar.inert = true;
-    overlay.classList.add('hidden');
-    overlay.setAttribute('aria-hidden', 'true');
+    if (currentOverlay) {
+      currentOverlay.classList.add('hidden');
+      currentOverlay.setAttribute('aria-hidden', 'true');
+    }
     var menuBtn = document.getElementById('bottom-nav-docs-btn');
     if (menuBtn) menuBtn.setAttribute('aria-expanded', 'false');
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@site/src/components/DocsSidebar.astro` around lines 190 - 205, closeSidebar
currently closes the old replaced overlay because it references the outer-scope
overlay variable; update closeSidebar to operate on the live DOM element (e.g.,
re-query the overlay inside the function via document.getElementById or
document.querySelector) or update the outer overlay reference after cloning
(assign newOverlay back to overlay) so that closeSidebar, mobileSidebar link
handlers and the overlay click handler all act on the current node; target
symbols: function closeSidebar, overlay.cloneNode/replaceChild, newOverlay,
mobileSidebar.querySelectorAll.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@site/src/styles/global.css`:
- Around line 405-407: Update the .prose code CSS rule to remove the deprecated
word-break: break-word and use the standard overflow-wrap: break-word instead;
locate the CSS selector ".prose code" and replace the word-break declaration
with overflow-wrap: break-word (optionally keep a fallback like word-break:
normal if needed for older behavior).

---

Outside diff comments:
In `@site/src/components/DocsSidebar.astro`:
- Around line 190-205: closeSidebar currently closes the old replaced overlay
because it references the outer-scope overlay variable; update closeSidebar to
operate on the live DOM element (e.g., re-query the overlay inside the function
via document.getElementById or document.querySelector) or update the outer
overlay reference after cloning (assign newOverlay back to overlay) so that
closeSidebar, mobileSidebar link handlers and the overlay click handler all act
on the current node; target symbols: function closeSidebar,
overlay.cloneNode/replaceChild, newOverlay, mobileSidebar.querySelectorAll.

In `@site/src/components/Nav.astro`:
- Around line 78-107: initNav currently captures the overlay DOM node once
(const overlay = document.getElementById('sidebar-overlay')) but
DocsSidebar.astro's initSidebar may clone/replace that element, so the click
handler operates on a stale detached node; to fix, stop relying on the cached
overlay inside initNav — either remove the strict early-return for overlay or
keep it as a sanity check, and re-query
document.getElementById('sidebar-overlay') inside the newBtn click handler
before toggling classes/aria attributes; make the same change for any overlay
operations (overlay.classList..., overlay.setAttribute...) so they always target
the current DOM node.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 73bbced7-670e-46a9-a282-3b912bc7c0b5

📥 Commits

Reviewing files that changed from the base of the PR and between 957996c and 640031f.

📒 Files selected for processing (5)
  • site/src/components/DocsSidebar.astro
  • site/src/components/Nav.astro
  • site/src/layouts/Docs.astro
  • site/src/pages/index.astro
  • site/src/styles/global.css

Comment thread site/src/styles/global.css
- DocsSidebar: move cloneNode before closeSidebar so it references the
  live newOverlay node, not the detached original
- Nav: re-query overlay by ID inside click handler since DocsSidebar's
  initSidebar may clone/replace it after Nav caches the reference
- CSS: replace non-standard word-break: break-word with overflow-wrap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
site/src/components/DocsSidebar.astro (1)

93-96: ⚠️ Potential issue | 🟠 Major

Breakpoint mismatch leaves mobile sidebar inaccessible on tablets.

The mobile sidebar overlay and drawer use lg:hidden (visible until 1024px), but the bottom nav trigger button now uses md:hidden (hidden at 768px+). This creates a gap at 768px–1024px where the mobile sidebar exists but users have no way to open it.

Align the breakpoints: either change these to md:hidden to match the bottom nav, or change the bottom nav back to lg:hidden.

🔧 Proposed fix (align to md breakpoint)
 <!-- Mobile sidebar overlay -->
-<div id="sidebar-overlay" class="fixed inset-0 z-40 bg-black/50 hidden lg:hidden" aria-hidden="true"></div>
+<div id="sidebar-overlay" class="fixed inset-0 z-40 bg-black/50 hidden md:hidden" aria-hidden="true"></div>

 <!-- Mobile sidebar drawer -->
-<aside id="docs-sidebar-mobile" aria-hidden="true" inert class="fixed top-16 left-0 bottom-0 z-50 w-72 bg-surface-container-lowest border-r border-outline-variant transform -translate-x-full transition-transform duration-200 lg:hidden overflow-y-auto sidebar-mobile-bottom">
+<aside id="docs-sidebar-mobile" aria-hidden="true" inert class="fixed top-16 left-0 bottom-0 z-50 w-72 bg-surface-container-lowest border-r border-outline-variant transform -translate-x-full transition-transform duration-200 md:hidden overflow-y-auto sidebar-mobile-bottom">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@site/src/components/DocsSidebar.astro` around lines 93 - 96, The mobile
sidebar overlay (id="sidebar-overlay") and drawer (id="docs-sidebar-mobile") use
the lg:hidden breakpoint while the bottom-nav trigger uses md:hidden, creating
an inaccessible gap between 768–1024px; update the CSS utility classes on these
elements to use md:hidden (replacing lg:hidden) so the overlay, drawer and
trigger all share the same md breakpoint, or alternatively change the bottom-nav
trigger back to lg:hidden—make the breakpoint consistent across sidebar-overlay,
docs-sidebar-mobile, and the bottom-nav trigger.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@site/src/components/Nav.astro`:
- Line 38: The mobile bottom nav element with id "mobile-bottom-nav" uses the
class "md:hidden" which is inconsistent with the DocsSidebar (which uses
"lg:hidden"); update the nav's breakpoint class to match the sidebar (replace
"md:hidden" with "lg:hidden") so the mobile triggers and sidebar breakpoints are
aligned, and scan for any other mismatched breakpoint classes in the same
component to keep behavior consistent with DocsSidebar.

---

Outside diff comments:
In `@site/src/components/DocsSidebar.astro`:
- Around line 93-96: The mobile sidebar overlay (id="sidebar-overlay") and
drawer (id="docs-sidebar-mobile") use the lg:hidden breakpoint while the
bottom-nav trigger uses md:hidden, creating an inaccessible gap between
768–1024px; update the CSS utility classes on these elements to use md:hidden
(replacing lg:hidden) so the overlay, drawer and trigger all share the same md
breakpoint, or alternatively change the bottom-nav trigger back to
lg:hidden—make the breakpoint consistent across sidebar-overlay,
docs-sidebar-mobile, and the bottom-nav trigger.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 30353e04-3b4d-45e5-93ad-20aa30500df5

📥 Commits

Reviewing files that changed from the base of the PR and between 640031f and c527f88.

📒 Files selected for processing (3)
  • site/src/components/DocsSidebar.astro
  • site/src/components/Nav.astro
  • site/src/styles/global.css

Comment thread site/src/components/Nav.astro Outdated
The bottom nav used md:hidden while the sidebar used lg:hidden, creating
a gap between 768-1024px where the nav trigger disappeared but no
desktop sidebar existed. Align everything to lg.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@michaelmcnees michaelmcnees merged commit a996ec3 into main Mar 24, 2026
6 checks passed
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