Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 Jul 3, 2026
7c86cc0
fix(docs): reduce header nav to a single Docs link and align the logo…
taitelee Jul 3, 2026
4b304fc
feat(docs): redesign header — centered splash / full-width docs, comp…
taitelee Jul 3, 2026
518e35e
fix(docs): gate expanded header search to >=50rem to avoid mobile ove…
taitelee Jul 3, 2026
35ee725
style(docs): size the header nav link smaller than the WaveHouse word…
taitelee Jul 3, 2026
30b2739
refactor(docs): remove the Get Started CTA from the site header
taitelee Jul 6, 2026
da82e98
Merge remote-tracking branch 'origin/main' into page-header
taitelee Jul 6, 2026
add31c3
fix(docs): expand splash search, align and restyle the header Docs link
taitelee Jul 6, 2026
c7a1371
Merge remote-tracking branch 'origin/main' into page-header
taitelee Jul 6, 2026
390859f
fix(docs): sit the header Docs link flush on the wordmark baseline
taitelee Jul 6, 2026
eb8bccb
Merge origin/main into page-header: changelog _in wording fix (#376)
taitelee Jul 6, 2026
58d7197
fix(docs): align header Docs link to wordmark baseline
taitelee Jul 7, 2026
d077ffd
fix(docs): use branding lockup image for the header logo, bottom-alig…
taitelee Jul 7, 2026
8029e3b
fix(docs): center the header lockup in the bar and enlarge the Docs link
taitelee Jul 7, 2026
1c7efd0
fix(docs): drop the header Docs link onto the logo wordmark baseline
taitelee Jul 7, 2026
d709f6f
fix(docs): align the header Docs link to the logo wordmark baseline
taitelee Jul 7, 2026
cd47715
fix(docs): center + underline the Docs link, drop the header width-swap
taitelee Jul 8, 2026
8d19c33
fix(docs): track header nav aria-current across view transitions
taitelee Jul 8, 2026
627444a
Merge remote-tracking branch 'origin/main' into page-header
taitelee Jul 8, 2026
8228864
fix(docs): center the splash header, drop the Docs link underline
taitelee Jul 8, 2026
65cf495
refactor(docs): inline-SVG Logo, robust Docs alignment, smooth width
taitelee Jul 8, 2026
4283201
refactor(docs): inline-SVG Logo component, magic-number-free Docs ali…
taitelee Jul 8, 2026
c120d60
refactor(docs): inline-SVG Logo, robust Docs alignment, smooth width
taitelee Jul 8, 2026
99737e3
fix(docs): reuse Logo in footer, hide lockup a11y dupe, harden aria-c…
taitelee Jul 9, 2026
bc7e15a
fixed footer misalignment
taitelee Jul 9, 2026
305951c
fix(docs): valid standalone lockup SVG, full lockup + Docs nav on mobile
taitelee Jul 9, 2026
fb4ba11
fix(docs): valid standalone lockup SVG, full lockup on mobile
taitelee Jul 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export default defineConfig({
},
},
components: {
Header: "./src/components/Header.astro",
Hero: "./src/components/Hero.astro",
SiteTitle: "./src/components/SiteTitle.astro",
Footer: "./src/components/Footer.astro",
Expand Down
246 changes: 246 additions & 0 deletions docs/src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
---
// 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;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
.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. Doc pages show Starlight's expanded "Search … ⌘K" box; the splash
homepage collapses it to a compact icon. Either way it opens the same
modal. */
.wh-search {
align-items: center;
}
/* Expand to the box only from 50rem up — the same breakpoint that reveals the
controls. Below it the label + ⌘K are already hidden (md:-only), so forcing
a width would leave a wide, near-empty button overflowing the narrow header
beside the logo; letting it size to its icon keeps it compact there.
min-width:0 + max-width let it shrink rather than overflow if the desktop
row gets tight. */
@media (min-width: 50rem) {
.wh-search {
min-width: 0;
}
.wh-search :global(button[data-open-modal]) {
width: 22rem;
max-width: 100%;
}
}
/* Splash homepage: collapse to a compact icon button at every width (label +
⌘K hidden), 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>
10 changes: 10 additions & 0 deletions docs/src/config/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,13 @@ export const sidebar: StarlightUserConfig["sidebar"] = [
],
},
];

// Top-level link(s) for the site header (src/components/Header.astro), colocated
// with the sidebar so header and sidebar share one file as the single source of
// truth for navigation. A single "Docs" entry into the doc tree: the splash
// homepage hides the sidebar, so this is the way in from there; every doc page
// already carries the full sidebar. Root-absolute href matches the internal link
// convention used across the docs (index.mdx hero, LinkCards).
export const headerNav: { label: string; href: string }[] = [
{ label: "Docs", href: "/getting-started" },
];
24 changes: 22 additions & 2 deletions docs/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// Starlight exposes its built-in components to overrides through these virtual
// modules (Vite resolves them at build time), but only ships their TYPES in an
// internal declaration file that isn't visible to user code — so `astro check`
// can't find them. Declare the ones the Footer override re-renders. See
// node_modules/@astrojs/starlight/virtual-internal.d.ts for the canonical list.
// can't find them. Declare the ones the Footer and Header overrides re-render.
// See node_modules/@astrojs/starlight/virtual-internal.d.ts for the canonical list.
declare module "virtual:starlight/components/EditLink" {
const Component: import("astro").AstroComponentFactory;
export default Component;
Expand All @@ -17,3 +17,23 @@ declare module "virtual:starlight/components/Pagination" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}
declare module "virtual:starlight/components/LanguageSelect" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}
declare module "virtual:starlight/components/Search" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}
declare module "virtual:starlight/components/SiteTitle" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}
declare module "virtual:starlight/components/SocialIcons" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}
declare module "virtual:starlight/components/ThemeSelect" {
const Component: import("astro").AstroComponentFactory;
export default Component;
}