Skip to content

Update site navigation#982

Merged
tannerlinsley merged 17 commits into
mainfrom
taren/nav-mega-menu
Jun 15, 2026
Merged

Update site navigation#982
tannerlinsley merged 17 commits into
mainfrom
taren/nav-mega-menu

Conversation

@tannerlinsley

@tannerlinsley tannerlinsley commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

  • Replaces the left-nav structure with a top mega-menu hierarchy for Libraries, Learn, Community, Tools, Merch, and Support.
  • Groups library links by stack category, links category labels to their stack pages, and keeps Libraries as a direct link to /libraries.
  • Simplifies the mobile menu with collapsible groups, subtle section borders, and fixed positioning.
  • Adds a pre-hydration desktop hover fallback, glass menu styling, site blur/tint on hover, and keeps the active dropdown hover area scoped to the card.
  • Removes the library version suffix from the navbar title area and adjusts workshop full-width sections for the simplified layout.

Validation

  • pnpm test
  • In-app browser DOM checks for top-level nav labels, Support/About merge, Libraries/category hrefs, and dropdown pointer-event scoping.

Note: pnpm test passes with existing lint warnings in shop/admin utility files unrelated to this navigation change.

Summary by CodeRabbit

  • New Features
    • Redesigned navigation with a typed, data-driven responsive mega-menu (desktop glass overlay + mobile drawer), including grouped resources and “Docs” links.
  • Style
    • Added an animated navigation underline and smoother mega-menu panel/background transitions, with reduced-motion support.
  • Bug Fixes
    • Navbar titles are now consistent across versioned routes (no longer dependent on the selected version).
  • Chores
    • Adjusted spacing for full-width “w-screen” workshop sections for more consistent layout.

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces the previous flyout/mobile-menu navbar with a typed, data-driven mega menu system. New internal components handle animated pane transitions, desktop triggers, mobile collapsible groups, and library browsing. CSS view-transition animations and panel visibility rules are added with dark-mode and reduced-motion support. Library navbar titles are simplified to remove version props, and workshop layout overrides are updated to remove sidebar width offsets.

Changes

Mega Menu Navigation Overhaul

Layer / File(s) Summary
Navbar imports, menu types, constants, and data structures
src/components/Navbar.tsx
Adds flushSync import, updates lucide-react icon imports for mega-menu UI, defines menu key types, pane direction/state enums, layout measurements, NAV_GROUPS configuration, and helper functions for deriving library groups and "Docs" URLs from librariesByGroup.
Mega menu CSS triggers, panels, animations, and overlays
src/styles/app.css
Adds all .ts-mega-* selectors for trigger underlines, fallback elements, panel open/close states, and view-transition animations. Implements glass overlay visuals with dark-mode overrides, structural positioning for panel and content, and prefers-reduced-motion handling.
Collapsible trigger button props and handlers
src/components/Collapsible.tsx
Expands CollapsibleTriggerProps to accept full React.ButtonHTMLAttributes, enabling type, onClick, onMouseDown, and other standard button props. Implements event propagation stoppage and proper handler invocation.
Navbar state management, refs, and lifecycle hooks
src/components/Navbar.tsx
Introduces activeMenuKey state, refs for nav container/mega-panel/layout, and close-timer management. Reads router location via useLocation to dismiss menu on route change, syncs navbar height CSS variable, and manages delayed close with cancellation on pointer activity.
Navbar header, desktop primary nav, mobile button, and global handlers
src/components/Navbar.tsx
Reworks header with simplified LogoSection, desktop primary <nav> rendering NAV_GROUPS as mapped items with pointer/focus handlers, mobile drawer button, global Escape and outside pointerdown dismissal, and auth/login control wiring.
Desktop mega-menu glass panel and mobile collapsible drawer
src/components/Navbar.tsx
Implements desktop mega-menu overlay with computed positioning and glass background, mobile drawer using Collapsible component, site tint/blur backdrop, and AiDockMount lazy integration.
DesktopNavTrigger, DesktopNavFallback, MobileMenuGroup
src/components/Navbar.tsx
Implements desktop trigger rendering as Link or button with pointer/focus handlers, fallback container holding MegaMenuContent in glass panel, and mobile collapsible groups with onNavigate close.
MegaMenuContentTransition pane animation and MegaMenuContent routing
src/components/Navbar.tsx
Tracks previous/current activeMenuKey, constructs enter/exit/current pane records with direction, delays transition to set panes to current, and conditionally renders MegaMenuContent per pane. Routes to LibrariesMenuContent or renders section headers and MenuItemLink rows.
LibrariesMenuContent, LibraryMenuGroup, and library items
src/components/Navbar.tsx
LibrariesMenuContent renders grouped categories with per-category links and "All Libraries" item, optionally including desktop MenuRail. LibraryMenuGroup renders category headers with libraries underneath. LibraryMenuItem displays links with color styling, badges, trimmed names, and derived Docs links.
MenuRail card/item and MenuItemLink row rendering
src/components/Navbar.tsx
MenuRail renders as compact mobile item or desktop card with eyebrow/title/description. MenuItemLink builds row layout with icon/badge/description, renders external <a> (new tab, noopener noreferrer) for non-mailto destinations or TanStack Link for internal routes.
LibraryNavbarTitle component signature and markup update
src/routes/-library-landing-route.tsx
Removes version prop, eliminates resolvedVersion calculation and version spans, simplifies Link className to whitespace-nowrap while retaining gradient library-name display.
Library landing route navbar title updates (17 routes)
src/routes/{ai,cli,config,db,devtools,form,hotkeys,intent,pacer,query,ranger,router,start,store,table,virtual,workflow}.$version.index.tsx
Updates all 17 library-specific NavbarTitle components to render LibraryNavbarTitle with only libraryId prop, removing Route.useParams() calls for version extraction.
Workshop full-width section responsive overrides removal
src/routes/workshops.tsx
Removes md:w-[calc(100vw-250px)] and md:mx-[...] responsive overrides from four full-width sections while retaining base w-screen/negative margin behavior.

Sequence Diagram

sequenceDiagram
  participant User
  participant DesktopNavTrigger
  participant Navbar
  participant MegaMenuContentTransition
  participant MegaMenuContent

  User->>DesktopNavTrigger: pointerenter / focus
  DesktopNavTrigger->>Navbar: onOpen(menuKey, direction)
  Navbar->>Navbar: cancelCloseTimer, setActiveMenuKey, recalcLayout
  Navbar->>MegaMenuContentTransition: activeMenuKey, direction, layout
  MegaMenuContentTransition->>MegaMenuContent: render pane (view-transition animates)
  MegaMenuContent->>MegaMenuContent: switch libraries vs general group

  User->>DesktopNavTrigger: pointerleave
  DesktopNavTrigger->>Navbar: scheduleClose(CLOSE_DELAY_MS)
  Navbar->>Navbar: closeTimer fires → setActiveMenuKey(null)
  MegaMenuContentTransition->>MegaMenuContent: pane animation → hidden

  User->>Navbar: Escape keydown / outside pointerdown
  Navbar->>Navbar: clearTimer, setActiveMenuKey(null), closeMobileDrawer
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • TanStack/tanstack.com#970: This PR updates the LibraryNavbarTitle component signature by removing the version prop that was used in related library route changes, directly affecting the same component API.
  • TanStack/tanstack.com#935: Both PRs touch the navbar's social dropdown trigger and menu styling logic, making them code-level related in the navigation component layer.

Suggested reviewers

  • KevinVandy
  • schiller-manuel

Poem

🐇 Hop, hop—the menu's new!
Mega panes slide left and right,
Glass overlays shimmer so bright,
View-transitions dance without care,
Libraries grouped, version-free, fair.
The navbar blooms—magnifique!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "Update site navigation" is clearly related to the main objective of this PR, which comprehensively rebuilds the site navigation from a left-nav to a top mega-menu structure across the entire codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 taren/nav-mega-menu

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

@tannerlinsley tannerlinsley marked this pull request as ready for review June 14, 2026 09:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/routes/-library-landing-route.tsx (1)

116-121: ⚡ Quick win

Remove the stale required version prop from LibraryNavbarTitle props.

Line 120 still requires version: string, but this component no longer reads or renders version data. Keeping it required preserves an unnecessary contract and forces avoidable prop plumbing.

Proposed diff
 export function LibraryNavbarTitle({
   libraryId,
 }: {
   libraryId: LandingLibraryId
-  version: string
 }) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/-library-landing-route.tsx` around lines 116 - 121, The
LibraryNavbarTitle function component has a stale version property in its props
type definition that is no longer used by the component. Remove the version:
string line from the props type destructuring in the LibraryNavbarTitle function
signature, keeping only the libraryId property which is actually being used.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Navbar.tsx`:
- Around line 1022-1032: When activeKey becomes null in the useLayoutEffect
hook, the panes remain mounted and focusable for MEGA_MENU_PANEL_CLOSE_MS even
though they are visually hidden via CSS, creating an accessibility issue. Fix
this by either calling setPanes([]) synchronously when activeKey becomes null
(removing the setTimeout delay) or immediately mark the closing pane as
non-focusable/inert before the timeout begins. This same issue appears at two
locations in the file around lines 1022-1032 and lines 1090-1096, so apply the
same fix to both useLayoutEffect hooks that handle pane closure.
- Around line 981-1000: The MobileMenuGroup component currently wraps the entire
group header in a CollapsibleTrigger, which makes the group label a disclosure
button rather than a direct link to group.to. To fix this, restructure the
CollapsibleTrigger to separate the navigation link from the expansion
affordance. Make the group label itself a direct link using group.to, and move
the collapsible trigger functionality (the arrow icon or expand indicator) to a
separate clickable element that controls the disclosure without triggering
navigation. This way users can directly navigate to Libraries on mobile while
still having the ability to expand the menu group.
- Around line 924-945: The Link and button trigger elements in the Navbar
component are declaring aria-haspopup="menu" and aria-expanded attributes, but
the popup content is regular navigation content that doesn't follow menu widget
patterns with proper focus management. Remove both aria-haspopup="menu" and
aria-expanded attributes from the Link and button elements since the popup
doesn't implement true menu semantics and focus continues in normal document
order.

In `@src/styles/app.css`:
- Line 145: The background property value `currentColor` is using incorrect
casing according to Stylelint's value-keyword-case rule. Change `currentColor`
to `currentcolor` (all lowercase) in the background property to normalize the
keyword casing and resolve the lint violation.

---

Nitpick comments:
In `@src/routes/-library-landing-route.tsx`:
- Around line 116-121: The LibraryNavbarTitle function component has a stale
version property in its props type definition that is no longer used by the
component. Remove the version: string line from the props type destructuring in
the LibraryNavbarTitle function signature, keeping only the libraryId property
which is actually being used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 72d59333-7132-498a-b1d6-723b4e2606ec

📥 Commits

Reviewing files that changed from the base of the PR and between 762e5d8 and 432bef0.

📒 Files selected for processing (4)
  • src/components/Navbar.tsx
  • src/routes/-library-landing-route.tsx
  • src/routes/workshops.tsx
  • src/styles/app.css

Comment thread src/components/Navbar.tsx
Comment thread src/components/Navbar.tsx
Comment thread src/components/Navbar.tsx Outdated
Comment thread src/styles/app.css Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Collapsible.tsx`:
- Around line 94-98: The onClick handler in the Collapsible component calls
toggle() before the consumer's onClick callback, preventing consumers from
canceling the toggle via event.preventDefault(). Reorder the logic in the
onClick handler to invoke the consumer's onClick callback first, then check if
event.defaultPrevented is true before calling toggle(). This allows consumers to
prevent toggling when needed by calling preventDefault() in their onClick
handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98aa73ba-3ee2-461d-95dd-e9e7cd86173c

📥 Commits

Reviewing files that changed from the base of the PR and between 432bef0 and bb8a16d.

📒 Files selected for processing (21)
  • src/components/Collapsible.tsx
  • src/components/Navbar.tsx
  • src/routes/-library-landing-route.tsx
  • src/routes/ai.$version.index.tsx
  • src/routes/cli.$version.index.tsx
  • src/routes/config.$version.index.tsx
  • src/routes/db.$version.index.tsx
  • src/routes/devtools.$version.index.tsx
  • src/routes/form.$version.index.tsx
  • src/routes/hotkeys.$version.index.tsx
  • src/routes/intent.$version.index.tsx
  • src/routes/pacer.$version.index.tsx
  • src/routes/query.$version.index.tsx
  • src/routes/ranger.$version.index.tsx
  • src/routes/router.$version.index.tsx
  • src/routes/start.$version.index.tsx
  • src/routes/store.$version.index.tsx
  • src/routes/table.$version.index.tsx
  • src/routes/virtual.$version.index.tsx
  • src/routes/workflow.$version.index.tsx
  • src/styles/app.css
💤 Files with no reviewable changes (1)
  • src/routes/-library-landing-route.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/styles/app.css
  • src/components/Navbar.tsx

Comment on lines 94 to 98
onClick={(e) => {
e.stopPropagation()
toggle()
onClick?.(e)
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Honor consumer click cancellation before toggling.

On Line 96, toggle() runs before the consumer onClick (Line 97). With the new button-props API, consumers cannot prevent toggling via event.preventDefault(), which makes the trigger hard to compose in controlled flows.

Suggested fix
       onClick={(e) => {
         e.stopPropagation()
-        toggle()
-        onClick?.(e)
+        onClick?.(e)
+        if (!e.defaultPrevented) {
+          toggle()
+        }
       }}
📝 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
onClick={(e) => {
e.stopPropagation()
toggle()
onClick?.(e)
}}
onClick={(e) => {
e.stopPropagation()
onClick?.(e)
if (!e.defaultPrevented) {
toggle()
}
}}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Collapsible.tsx` around lines 94 - 98, The onClick handler in
the Collapsible component calls toggle() before the consumer's onClick callback,
preventing consumers from canceling the toggle via event.preventDefault().
Reorder the logic in the onClick handler to invoke the consumer's onClick
callback first, then check if event.defaultPrevented is true before calling
toggle(). This allows consumers to prevent toggling when needed by calling
preventDefault() in their onClick handler.

@tannerlinsley tannerlinsley merged commit dccfc63 into main Jun 15, 2026
9 checks passed
@tannerlinsley tannerlinsley deleted the taren/nav-mega-menu branch June 15, 2026 02:45
@coderabbitai coderabbitai Bot mentioned this pull request Jun 15, 2026
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