Repository navigation
feat(docs): override Starlight header with a top-level site nav #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
7cc9584
feat(docs): override Starlight header with a top-level site nav
taitelee 7c86cc0
fix(docs): reduce header nav to a single Docs link and align the logo…
taitelee 4b304fc
feat(docs): redesign header — centered splash / full-width docs, comp…
taitelee 518e35e
fix(docs): gate expanded header search to >=50rem to avoid mobile ove…
taitelee 35ee725
style(docs): size the header nav link smaller than the WaveHouse word…
taitelee 30b2739
refactor(docs): remove the Get Started CTA from the site header
taitelee da82e98
Merge remote-tracking branch 'origin/main' into page-header
taitelee add31c3
fix(docs): expand splash search, align and restyle the header Docs link
taitelee c7a1371
Merge remote-tracking branch 'origin/main' into page-header
taitelee 390859f
fix(docs): sit the header Docs link flush on the wordmark baseline
taitelee eb8bccb
Merge origin/main into page-header: changelog _in wording fix (#376)
taitelee 58d7197
fix(docs): align header Docs link to wordmark baseline
taitelee d077ffd
fix(docs): use branding lockup image for the header logo, bottom-alig…
taitelee 8029e3b
fix(docs): center the header lockup in the bar and enlarge the Docs link
taitelee 1c7efd0
fix(docs): drop the header Docs link onto the logo wordmark baseline
taitelee d709f6f
fix(docs): align the header Docs link to the logo wordmark baseline
taitelee cd47715
fix(docs): center + underline the Docs link, drop the header width-swap
taitelee 8d19c33
fix(docs): track header nav aria-current across view transitions
taitelee 627444a
Merge remote-tracking branch 'origin/main' into page-header
taitelee 8228864
fix(docs): center the splash header, drop the Docs link underline
taitelee 65cf495
refactor(docs): inline-SVG Logo, robust Docs alignment, smooth width
taitelee 4283201
refactor(docs): inline-SVG Logo component, magic-number-free Docs ali…
taitelee c120d60
refactor(docs): inline-SVG Logo, robust Docs alignment, smooth width
taitelee 99737e3
fix(docs): reuse Logo in footer, hide lockup a11y dupe, harden aria-c…
taitelee bc7e15a
fixed footer misalignment
taitelee 305951c
fix(docs): valid standalone lockup SVG, full lockup + Docs nav on mobile
taitelee fb4ba11
fix(docs): valid standalone lockup SVG, full lockup on mobile
taitelee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| --- | ||
| // Custom header overriding Starlight's default. The layout is our own — its | ||
| // contents are held in a centered max-width column (matching the page content, | ||
| // à la ClickHouse/Supabase) rather than spanning edge to edge: brand + primary | ||
| // nav pinned left, controls + a "Get Started" call-to-action pinned right, with | ||
| // a compact icon search among the right-hand controls. Every control is still | ||
| // Starlight's own built-in, pulled in through its `virtual:starlight/components/*` | ||
| // import, so the SiteTitle/Search/Theme overrides and the Pagefind-search logic | ||
| // keep working untouched. The outer <header class="header"> (PageFrame — fixed | ||
| // position + full-width glass background) is not ours and stays as-is; only our | ||
| // inner content is column-constrained, so the bar itself still spans the page. | ||
| // | ||
| // Because the controls are Starlight built-ins re-rendered here, env.d.ts | ||
| // declares their virtual modules so `astro check` can resolve them. On | ||
| // @astrojs/starlight upgrades, re-check those component module paths. | ||
| // | ||
| // The left nav and the controls/CTA are hidden below Starlight's `md` (50rem): | ||
| // under 50rem the sidebar (a hamburger drawer) already carries navigation on | ||
| // doc pages, leaving the logo + the (always-visible) search button. | ||
| import config from "virtual:starlight/user-config"; | ||
|
|
||
| import LanguageSelect from "virtual:starlight/components/LanguageSelect"; | ||
| import Search from "virtual:starlight/components/Search"; | ||
| import SiteTitle from "virtual:starlight/components/SiteTitle"; | ||
| import SocialIcons from "virtual:starlight/components/SocialIcons"; | ||
| import ThemeSelect from "virtual:starlight/components/ThemeSelect"; | ||
| import { headerNav } from "../config/sidebar.ts"; | ||
|
|
||
| // Mirror of the package default: only render Search when Pagefind is enabled or | ||
| // the Search component has been overridden. | ||
| const shouldRenderSearch = | ||
| config.pagefind || | ||
| config.components.Search !== "@astrojs/starlight/components/Search.astro"; | ||
|
|
||
| // Highlight the active destination — exact match, or any nested page beneath it | ||
| // (so a "/guides" link stays current on "/guides/foo"). trailingSlash is | ||
| // "never", so strip a stray trailing slash before comparing, just in case. | ||
| const currentPath = Astro.url.pathname.replace(/(.)\/$/, "$1"); | ||
|
|
||
| // Primary call-to-action. Points at the docs entry point for now; repoint if a | ||
| // dedicated quickstart/install page lands. | ||
| const ctaHref = "/getting-started"; | ||
| --- | ||
|
|
||
| <div class="header"> | ||
| <div class="wh-lead"> | ||
| <div class="title-wrapper sl-flex"> | ||
| <SiteTitle /> | ||
| </div> | ||
| <nav | ||
| class="wh-header-nav sl-hidden md:sl-flex print:hidden" | ||
| aria-label="Primary" | ||
| > | ||
| { | ||
| headerNav.map(({ label, href }) => ( | ||
| <a | ||
| href={href} | ||
| class="wh-header-nav__link" | ||
| aria-current={ | ||
| currentPath === href || currentPath.startsWith(`${href}/`) | ||
| ? "page" | ||
| : undefined | ||
| } | ||
| > | ||
| {label} | ||
| </a> | ||
| )) | ||
| } | ||
| </nav> | ||
| </div> | ||
|
|
||
| <div class="wh-right"> | ||
| { | ||
| shouldRenderSearch && ( | ||
| <div class="wh-search sl-flex print:hidden"> | ||
| <Search /> | ||
| </div> | ||
| ) | ||
| } | ||
| <div class="wh-controls sl-hidden md:sl-flex print:hidden"> | ||
| <div class="sl-flex social-icons"> | ||
| <SocialIcons /> | ||
| </div> | ||
| <ThemeSelect /> | ||
| <LanguageSelect /> | ||
| <a class="wh-cta" href={ctaHref}>Get Started</a> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <style> | ||
| /* Our own layout, held in a centered column that matches the page content | ||
| (~68rem, like the splash hero) instead of Starlight's edge-to-edge row. | ||
| The outer PageFrame bar still spans full width; only this inner content is | ||
| capped + centered. Unlayered so it authoritatively styles this component's | ||
| inner .header row (Starlight's own rules are @layer'd and would otherwise | ||
| win). */ | ||
| .header { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: space-between; | ||
| gap: 1rem; | ||
| height: 100%; | ||
| /* Doc pages: full-bleed to the bar edges, like Supabase/ClickHouse docs. */ | ||
| } | ||
| /* Splash homepage (the only page with a hero): hold the header in a centered | ||
| content-width column instead. Keyed off the hero's presence in the body — | ||
| the same signal global.css uses — rather than an SSR class/attribute on the | ||
| header, because vtbot's <ReplacementSwap/> PRESERVES the header element | ||
| across view-transitions while swapping the body content: a baked-in | ||
| attribute would go stale, but this `:has()` selector re-evaluates live. */ | ||
| :global(body:has(.wh-hero)) .header { | ||
| max-width: 68rem; | ||
| margin-inline: auto; | ||
| } | ||
|
|
||
| .wh-lead { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 1.75rem; | ||
| min-width: 0; | ||
| } | ||
| .title-wrapper { | ||
| /* Avoid clipping the focus ring around the title link. */ | ||
| padding: 0.25rem; | ||
| margin: -0.25rem; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .wh-right { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 1rem; | ||
| } | ||
| /* No `display` here on purpose — let the `sl-hidden md:sl-flex` utilities | ||
| govern visibility so the controls collapse under 50rem (an unlayered | ||
| `display: flex` would override Starlight's layered `sl-hidden`). This only | ||
| styles the flex row they become at >=50rem. */ | ||
| .wh-controls { | ||
| align-items: center; | ||
| gap: 1rem; | ||
| } | ||
| .social-icons { | ||
| align-items: center; | ||
| gap: 1rem; | ||
| } | ||
| /* Hairline divider before the theme/lang controls, matching the default. */ | ||
| .social-icons::after { | ||
| content: ""; | ||
| height: 1.5rem; | ||
| border-inline-end: 1px solid var(--sl-color-gray-5); | ||
| } | ||
|
|
||
| /* Search: collapse Starlight's search box to a compact icon button (the | ||
| "Search" label + ⌘K hint are already `md:`-only, so hide them at every | ||
| width) that opens the same modal, ClickHouse-style. */ | ||
| .wh-search { | ||
| align-items: center; | ||
| } | ||
| /* Doc pages: keep Starlight's expanded search box, sized to a comfortable | ||
| width. */ | ||
| .wh-search :global(button[data-open-modal]) { | ||
| width: 22rem; | ||
| max-width: 100%; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||
| /* Splash: collapse to a compact icon button (its "Search" label + ⌘K hint | ||
| are already md-only) that opens the same modal, ClickHouse-style. */ | ||
| :global(body:has(.wh-hero)) .wh-search :global(button[data-open-modal] > span), | ||
| :global(body:has(.wh-hero)) .wh-search :global(button[data-open-modal] > kbd) { | ||
| display: none; | ||
| } | ||
| :global(body:has(.wh-hero)) .wh-search :global(button[data-open-modal]) { | ||
| width: auto; | ||
| min-width: 0; | ||
| padding: 0.5rem; | ||
| gap: 0; | ||
| } | ||
|
|
||
| /* Primary nav links — quiet by default, brand accent when current. */ | ||
| .wh-header-nav { | ||
| align-items: center; | ||
| gap: 1.5rem; | ||
| } | ||
| .wh-header-nav__link { | ||
| color: var(--wh-ink-muted); | ||
| /* Match the wordmark's font-size so, centered on the same header line, the | ||
| link's baseline lands exactly on the "WaveHouse" text baseline (the logo | ||
| itself is untouched — this only sizes the nav link). */ | ||
| font-size: 1.0625rem; | ||
| font-weight: 500; | ||
| line-height: 1; | ||
| text-decoration: none; | ||
| white-space: nowrap; | ||
| transition: color 0.15s ease; | ||
| } | ||
| .wh-header-nav__link:hover { | ||
| color: var(--wh-ink); | ||
| } | ||
| .wh-header-nav__link[aria-current="page"] { | ||
| color: var(--wh-accent-text); | ||
| font-weight: 600; | ||
| } | ||
|
|
||
| /* Get Started CTA — the filled accent button that anchors the right side, | ||
| the way ClickHouse/Supabase headers do. */ | ||
| .wh-cta { | ||
| align-items: center; | ||
| padding: 0.45rem 0.95rem; | ||
| border-radius: 0.5rem; | ||
| background: var(--wh-accent); | ||
| color: var(--wh-cta-fg, #fff); | ||
| font-size: 0.9375rem; | ||
| font-weight: 600; | ||
| line-height: 1; | ||
| text-decoration: none; | ||
| white-space: nowrap; | ||
| transition: transform 0.15s ease, box-shadow 0.15s ease; | ||
| } | ||
| /* Hover: lift + accent-tinted shadow, keeping the fill constant so the | ||
| text/background contrast never changes on interaction. */ | ||
| .wh-cta:hover { | ||
| transform: translateY(-1px); | ||
| box-shadow: 0 4px 14px -4px var(--wh-accent); | ||
| } | ||
| /* In dark theme --wh-accent resolves to a bright cyan; white text on it | ||
| fails contrast (~2.6:1), so switch to dark ink. Covers both explicit dark | ||
| (data-theme) and auto/OS dark (prefers-color-scheme), matching how | ||
| Starlight itself themes. */ | ||
| :global([data-theme="dark"]) .wh-cta { | ||
| --wh-cta-fg: #052a30; | ||
| } | ||
| @media (prefers-color-scheme: dark) { | ||
| :global(:root:not([data-theme="light"])) .wh-cta { | ||
| --wh-cta-fg: #052a30; | ||
| } | ||
| } | ||
| </style> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.