A Starlight theme with a left rail instead of a top bar. Built for vdbx.io and shared across sites; the layout lives here, each site keeps only its tokens, logo, and pages.
What it does
- Rail — logo, section nav that scrolls on its own (logo and footer stay put), footer lines, then Search, theme toggle, and your Starlight
sociallinks as icon buttons. The current page is bold in the accent and stays in view between pages. - Phones (under 50rem) — a header row (logo · icons · action button), then two horizontally scrolling rows: sections, and the selected section's pages. Native touch and trackpad scrolling; chevrons and click-drag for mouse users.
- Table of contents — the right column stays until 64rem; below that it becomes one horizontal row of headings with the active one in the accent.
- Product headers — pages with a product block in frontmatter get an id / status / price line, lede, link and file buttons, and a hero image in a tinted well.
- Link buttons — bare URLs are classified by host (Amazon, Crowd Supply, Tindie, Etsy → shop; GitHub →
owner/repo; OSHWLab, Onshape, Printables, YouTube, Discord…) and files by extension (pdf, step/stl/3mf, epro/kicad, zip, bin…), each with an icon and color. - Solid-tint callouts, icon-only search trigger, mono page names in prev/next links, dark-mode inversion for
img.invert-dark.
Every site tracks this repo's main, so a change here reaches all of them on their next build.
"dependencies": {
"starlight-theme-luna": "git+https://github.com/vdbxio/starlight-theme-luna.git"
}Lockfiles freeze a git dependency to a commit. To pick up the latest theme on every deploy, refresh it in CI after npm ci:
- run: npm ci
- run: npm install starlight-theme-luna@git+https://github.com/vdbxio/starlight-theme-luna.git --no-saveIf you use a remark plugin (this package's remark-base included), Astro 7 also needs @astrojs/markdown-remark in your dependencies.
// astro.config.mjs
import starlight from '@astrojs/starlight';
import luna from 'starlight-theme-luna';
export default defineConfig({
integrations: [
starlight({
title: 'Example',
customCss: ['./src/styles/theme.css'], // your tokens; loaded after the theme's stylesheet
plugins: [
luna({
logo: './src/logo.svg', // inlined, filled with the text color
footer: ['example.com', 'CC-BY-SA 4.0'],
action: { label: 'Connect', title: 'Flash a board', dialog: './src/components/Connect.astro' }, // optional
frontmatterKey: 'product', // where the product block lives (default)
statusLabels: { preorder: 'Pre-order' },
}),
],
social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/example' }],
}),
],
});| option | ||
|---|---|---|
logo |
required | path to an SVG, relative to the project root |
footer |
[] |
short lines under the nav on desktop |
action |
off | pill button in the rail's top-right corner; dialog is an Astro component rendered once per page, and the button carries data-luna-action for its script to hook |
frontmatterKey |
product |
frontmatter key the page header reads |
tocTopLabel |
Intro |
label of the table of contents' first entry (the link to the page title); Starlight's default "Overview" doubles up with a page whose first heading is Overview |
statusLabels |
{} |
labels for product status values, merged over the built-in set (idea, prototype, validation, preorder, production, shipping, released, out_of_stock, retired) |
Your site's own components overrides still win over the theme's, so any part can be replaced per site.
Set these in your own stylesheet; the theme's styles/base.css gives every one a default derived from Starlight's variables. Starlight's --sl-color-* and --sl-font* tokens work as usual.
:root {
--luna-display: "League Spartan", var(--sl-font); /* headings */
--luna-section-size: 1.8rem; /* section names in the rail */
--luna-rail-width: 16.5rem;
--luna-rail-pad-top: 2.5rem;
--luna-logo: 8.5rem; /* logo width; every H1 centers on it */
--luna-tint: linear-gradient(135deg, #abc2ff, #ff00ff); /* image wells */
--luna-render-shadow: drop-shadow(0 14px 22px rgba(0 0 0 / .45));
--luna-btn-shop: …; --luna-btn-source: …; --luna-btn-cad: …; --luna-btn-doc: …; --luna-btn-media: …; --luna-btn-plain: …;
--luna-note-bg: …; --luna-note-edge: …; --luna-note-text: …; /* also tip, caution, danger */
}Breakpoints are fixed: the rail collapses under 50rem, the TOC column under 64rem.
// src/content.config.ts
import { productSchema } from 'starlight-theme-luna/schema';
docsSchema({ extend: z.object({ product: productSchema.optional() }) })product:
type: product # anything else renders a plain title
id: VBX2360
status: shipping
status_note: Batch 3
msrp: 19.95
hero: /attachments/flip_c3.png
works_with: [PwrTool 500]
links: [{ url: https://www.amazon.com/dp/… }, { url: https://github.com/vdbxio/esphome-configs }]
files: [{ url: /attachments/flip_c3.epro, name: flip_c3.epro }]starlight-theme-luna/components/LinkButton.astroandstarlight-theme-luna/links(classifyLink,classifyFile) for landing pages and custom components.starlight-theme-luna/remark-base— prefixes root-relative Markdown URLs with the site base, so one build works atuser.github.io/repo/and at a custom domain:markdown: { remarkPlugins: [[remarkBase, { base: '/repo' }]] }.
MIT