Skip to content

refactor: refactoring navbars#1195

Open
jderochervlk wants to merge 25 commits intomasterfrom
vlk/refactor-navigation
Open

refactor: refactoring navbars#1195
jderochervlk wants to merge 25 commits intomasterfrom
vlk/refactor-navigation

Conversation

@jderochervlk
Copy link
Collaborator

@jderochervlk jderochervlk commented Feb 16, 2026

This refactors the navbar to not be so brittile and depend on checking height for layouts. The main change is using the modern html dialog component for the mobile menus and switching the header to use sticky to stay in place. Now the content body doesn't need to add margin or padding to account for any headers, they just show up above and can stack easily.

There will be some more refactors soon to split up the mdx route, but one thing at a time.

AI summary This pull request introduces significant improvements to the navigation and documentation layout, particularly around the API and documentation pages. It adds new responsive navigation bar tests, refactors and enhances the tertiary navbar and sidebar for API and docs routes, and automates the management of Vitest screenshot updates. Additionally, it updates the routing and configuration for better scalability and maintainability.

Navigation and Layout Enhancements:

  • Introduced and integrated NavbarSecondary and NavbarTertiary components across API and documentation routes, providing consistent breadcrumbs, sidebar content, and edit links for improved user navigation and editing experience. The sidebar now adapts based on route and viewport, supporting mobile drawer toggling and version selection. (app/routes/ApiRoute.res, app/routes/MdxRoute.res, app/routes/SyntaxLookupRoute.res, [1] [2] [3] [4] [5] [6]
  • Refactored the main app layout to simplify the root structure and ensure the new navbars are rendered appropriately. (app/root.res, [1] [2]

Testing and Automation Improvements:

  • Added comprehensive, responsive UI tests for NavbarPrimary and NavbarTertiary, covering desktop, tablet, and mobile scenarios, including screenshot assertions for visual regression testing. (__tests__/NavbarPrimary_.test.res, __tests__/NavbarTertiary_.test.res, [1] [2]
  • Automated the process of committing and pushing updated Vitest screenshots after test runs, ensuring that visual changes are consistently tracked in CI. (.github/workflows/pull-request.yml, [1] [2]

Routing and Configuration Updates:

  • Improved route definitions by precomputing mdxRoutes and streamlining their inclusion, and added support for a new "guide" section in the markdown and routing configuration. (app/routes.res, react-router.config.mjs, [1] [2] [3]
  • Updated the test script to always update screenshots on CI runs, and adjusted test/dev dependencies configuration for clarity. (package.json, rescript.json, [1] [2]

Component and Internal Refactoring:

  • Simplified the ApiDocs.SidebarTree and RightSidebar components to remove unused props and streamline sidebar rendering logic. (src/ApiDocs.res, [1] [2]

Miscellaneous:

@fhammerschmidt
Copy link
Member

this broke the version dropdown

@jderochervlk
Copy link
Collaborator Author

this broke the version dropdown

Fixed and I added a unit test.

@jderochervlk jderochervlk requested a review from Copilot February 18, 2026 14:32
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors navigation/layout to rely on sticky headers and dialog-based mobile menus instead of dynamically measuring header heights, alongside adding browser-based Vitest UI coverage for the new nav components.

Changes:

  • Introduces new Primary/Secondary/Tertiary navbar components and migrates routes/layouts to use them.
  • Reworks sidebar/mobile drawer behavior using dialog (and updates related CSS).
  • Adds Vitest browser setup/config and new UI/screenshot tests for nav and version selection.

Reviewed changes

Copilot reviewed 45 out of 52 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
vitest.setup.mjs Loads global CSS for Vitest browser runs.
vitest.config.mjs New Vitest browser (Playwright) configuration.
vitest.config.js Removes old Vitest config in favor of .mjs.
vite.config.mjs Reorders plugins and removes unused reactRefreshHost config.
styles/main.css Updates Tailwind sources and adds dialog/popover + scroll-lock styling.
src/layouts/SidebarLayout.resi Adjusts SidebarLayout public API and exports breadcrumbs module.
src/layouts/SidebarLayout.res Removes height-based offsets and old mobile navbar block; simplifies layout.
src/layouts/MainLayout.res Removes extra top margin now that header is sticky.
src/layouts/LandingPageLayout.res Fixes malformed Playground URL query string.
src/layouts/DocsLayout.res Removes breadcrumb/editHref plumbing from DocsLayout.
src/layouts/CommunityLayout.res Removes breadcrumbs prop usage to match new navbar approach.
src/layouts/ApiOverviewLayout.resi Exposes categories for route-side rendering.
src/layouts/ApiOverviewLayout.res Drops breadcrumbs usage and relies on tertiary navbar instead.
src/layouts/ApiLayout.resi Removes optional breadcrumbs prop from API layout signature.
src/layouts/ApiLayout.res Removes breadcrumbs prop usage when rendering SidebarLayout.
src/components/VersionSelect.res Uses useId to generate unique popover IDs per instance.
src/components/Search.res Tweaks search button/icon classes.
src/components/NavbarUtils.res Adds shared navbar helpers + dialog open/close/toggle utilities.
src/components/NavbarTertiary.res Adds tertiary sticky navbar with dialog-based mobile drawer.
src/components/NavbarSecondary.res Adds secondary sticky navbar for docs-related sections.
src/components/NavbarPrimary.resi Exposes primary navbar component interface.
src/components/NavbarPrimary.res Adds primary sticky navbar + mobile overlay toggle.
src/components/NavbarMobileOverlay.res Adds dialog-based mobile overlay navigation menu.
src/components/BreadCrumbs.res Adds simple pathname-derived breadcrumbs component.
src/common/Util.res Removes debug logging.
src/bindings/Vitest.res Expands vitest-browser bindings (viewport, locators, screenshots).
src/bindings/ReactRouter.res Adds Link onClick + aria-label support and BrowserRouter binding.
src/SyntaxLookup.res Removes extra top spacing to match sticky nav behavior.
src/Playground.res Removes top margin now that header is sticky.
src/Packages.res Removes wrapper spacing container to match new header stacking.
src/Blog.res Removes wrapper spacing container to match new header stacking.
src/ApiDocs.res Simplifies sidebar tree for desktop and removes mobile sidebar toggling logic.
package.json Changes CI test script to always update screenshots.
functions/ogimage/[[path]]/index.png.res Removes debug logging.
app/routes/SyntaxLookupRoute.res Adds secondary navbar to syntax lookup route.
app/routes/MdxRoute.res Adds secondary/tertiary navbars and mobile sidebar content for docs/API MDX.
app/routes/DocsOverview.res Removes extra top margin to match sticky nav behavior.
app/routes/ApiRoute.res Adds secondary/tertiary navbars and sidebar content for API route.
app/routes.res Precomputes mdx routes list for cleaner route definition.
app/root.res Removes previous overlay/scroll-lock provider and renders NavbarPrimary globally.
tests/VersionSelect_.test.res Adds browser tests for VersionSelect popover behavior.
tests/NavbarTertiary_.test.res Adds responsive + screenshot tests for tertiary navbar/drawer.
tests/NavbarPrimary_.test.res Adds responsive + screenshot tests for primary navbar/mobile overlay.
tests/Example.test.res Removes example test file.
.github/workflows/pull-request.yml Auto-commits updated Vitest screenshots after CI test run.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +46
<li className=base>
<Link
prefetch={#intent}
to=#"/blog"
className={linkOrActiveLinkSubroute(~target=#"/blog", ~route)}
>
{React.string("Blog")}
</Link>
</li>
<li className=base>
<Link
prefetch={#intent}
to=#"/community/overview"
className={linkOrActiveLink(~target=#"/community/overview", ~route)}
>
{React.string("Community")}
</Link>
</li>
<li className=base>
<Link
prefetch={#intent}
to=#"/packages"
className={linkOrActiveLink(~target=#"/packages", ~route)}
>
{React.string("Packages")}
</Link>
</li>
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Only the “Playground” link closes the mobile overlay (onClick=toggleMobileOverlay), but the other in-app links don’t. Because the overlay component is mounted globally (in NavbarPrimary), navigation won’t automatically unmount/close the dialog, so the overlay can remain open after route changes. Add an onClick handler to close the overlay for all navigation links (and consider doing the same for external links).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

~editHref: string=?,
// (Sidebar, toggleSidebar) ... for toggling sidebar in mobile view
~sidebarState: (bool, (bool => bool) => unit),
~sidebarState: (bool, (bool => bool) => unit)=?,
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

This interface marks sidebarState as an optional labeled argument (=?), but the implementation uses a default value (~sidebarState=(false, _ => ())) and treats it as a non-option tuple. This mismatch is likely to cause a signature/type mismatch. Make the .resi match the implementation (remove =? and keep the tuple type), or change the implementation to accept an option<...> and handle None.

Suggested change
~sidebarState: (bool, (bool => bool) => unit)=?,
~sidebarState: (bool, (bool => bool) => unit),

Copilot uses AI. Check for mistakes.

let leftContent = await screen->getByTestId("navbar-primary-left-content")

await element(leftContent->getByText("Docs"))->toBeVisible
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

getByText / getByLabelText are defined in src/bindings/Vitest.res as returning promise<element>, but these calls aren’t awaited before passing into element(...). This will either fail to type-check or behave incorrectly at runtime. Also, the aria-label in the component is "GitHub" (capital H), while the test uses "Github", so the query will fail even after awaiting.

Copilot uses AI. Check for mistakes.

let rightContent = await screen->getByTestId("navbar-primary-right-content")

await element(rightContent->getByLabelText("Github"))->toBeVisible
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

getByText / getByLabelText are defined in src/bindings/Vitest.res as returning promise<element>, but these calls aren’t awaited before passing into element(...). This will either fail to type-check or behave incorrectly at runtime. Also, the aria-label in the component is "GitHub" (capital H), while the test uses "Github", so the query will fail even after awaiting.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,23 @@
import { defineConfig } from "vitest/config";
import { playwright, defineBrowserCommand } from "@vitest/browser-playwright";
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

defineBrowserCommand is imported but not used anywhere in this (new) config file. Drop the unused import to keep the config minimal and avoid lint/typecheck noise.

Suggested change
import { playwright, defineBrowserCommand } from "@vitest/browser-playwright";
import { playwright } from "@vitest/browser-playwright";

Copilot uses AI. Check for mistakes.
${isDocRoute(~route=pathname) ? "top-28" : "top-16"}`}
>
<div className="flex items-center h-full w-full max-w-1280 m-auto">
<button className="md:hidden mr-3" onClick={toggleMobileTertiaryDrawer}>
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The mobile drawer toggle button lacks an accessible name (no ariaLabel / aria-label), so screen readers won’t know what it does. Add an aria label (and consider setting type_="button" to avoid accidental form submission if this navbar is ever rendered inside a form).

Suggested change
<button className="md:hidden mr-3" onClick={toggleMobileTertiaryDrawer}>
<button
className="md:hidden mr-3"
onClick={toggleMobileTertiaryDrawer}
ariaLabel="Toggle navigation menu"
type_="button">

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Feb 18, 2026

@jderochervlk I've opened a new pull request, #1198, to work on those changes. Once the pull request is ready, I'll request review from you.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions
Copy link

Cloudflare deployment

Deployement ID: 743feab0-38ab-4c17-ae5f-4b7ca37a1e40
Deployment Environment: preview

⛅️ wrangler 4.63.0 (update available 4.66.0)
─────────────────────────────────────────────
✨ Compiled Worker successfully
Uploading... (6810/7224)
Uploading... (6948/7224)
Uploading... (7086/7224)
Uploading... (7224/7224)
✨ Success! Uploaded 414 files (6810 already uploaded) (3.68 sec)

✨ Uploading _redirects
✨ Uploading Functions bundle
🌎 Deploying...
✨ Deployment complete! Take a peek over at https://743feab0.rescript-lang.pages.dev
✨ Deployment alias URL: https://vlk-refactor-navigation.rescript-lang.pages.dev

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.

3 participants

Comments