Shared Astro + Starlight documentation theme and tooling for @onury
projects. One source of truth for the look (fonts, colors, header, code blocks,
feature cards), the markdown-sync engine, the scaffolder, and the GitHub Pages
deploy. Each project's site/ is a thin, generated shell.
Consumed as a git dependency (no npm publish):
@astrojs/starlight, starlight-typedoc, TypeDoc and the fonts are pulled in by
the kit and hoisted into the project — you don't list them per project.
| Export | Purpose |
|---|---|
@onury/docs-kit/styles/custom.css, …/theme.css |
The shared visual theme — referenced as customCss string paths in the project's astro.config.mjs. |
@onury/docs-kit/sync → syncDocs(opts) |
Pulls repo-root markdown (CHANGELOG) into the Starlight content collection at build time. All other pages are authored directly in site/src/content/docs/. |
bin/init.mjs (docs-kit init) |
Scaffolds a project's site/ + a self-contained Pages workflow (.github/workflows/docs.yml). |
The hero background and the home page are intentionally per-project (each
project owns src/styles/hero.css + src/content/docs/index.mdx); the shared
theme covers everything else.
The shared theme reads the accent from an overridable variable, so each docs site
can have its own color without forking the theme. In a project's
src/styles/overrides.css (generated by the scaffolder, loaded after the shared
theme):
:root {
--oy-accent: #3b82f6; /* this site's accent; defaults to brand yellow */
/* --oy-accent-high: var(--oy-accent); */
}--sl-color-accent and --sl-color-accent-high derive from --oy-accent. Any
other Starlight --sl-color-* token can be overridden in the same file for
finer per-site control.
Why no
defineConfighelper?astro.config.mjsmust notimportfrom this package. The kit is ESM-only, and importing it into the Astro config makes Vite externalize@astrojs/starlightand load its TypeScript entry under Node, which fails on Node ≥22.18. So the theme is wired via CSS string paths (resolved at app build, not config load), and the small config plumbing (the constructor-heading remark fix + TypeDoc wiring) is generated inline by the scaffolder. Thesyncengine is safe toimport— it runs under plain Node, not the Astro config loader.
From the target project root (a sibling of this repo under ~/Developer/@onury/):
# local development (uses a file: dependency on this repo)
node ../docs-kit/bin/init.mjs --local --base /myproject --title MyProject
# or, once published as a git dep
npx @onury/docs-kit init --base /myprojectIt reads the project's package.json, picks up CHANGELOG.md (synced),
detects whether there's a public TS API (src/index.ts + tsconfig.build.json)
to document, and writes site/ (including a site/README.md that explains
how to customize that site) plus .github/workflows/docs.yml. Then:
# --local installs use --install-links (see "Local development" below)
npm --prefix site install --install-links
npm --prefix site run dev # preview
npm --prefix site run build # → site/dist--base must match the GitHub repo name (the Pages project path): a repo
onury/myproject serves at onury.io/myproject and needs base: /myproject.
Thin and self-contained — the only shared piece is the theme (CSS string paths):
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import { createStarlightTypeDocPlugin } from 'starlight-typedoc';
const [starlightTypeDoc, typeDocSidebarGroup] = createStarlightTypeDocPlugin();
// + inline remarkDropConstructorsHeading()
export default defineConfig({
site: 'https://onury.io',
base: '/myproject',
markdown: { remarkPlugins: [remarkDropConstructorsHeading] },
integrations: [
starlight({
title: 'MyProject',
customCss: [
'@onury/docs-kit/styles/custom.css', // shared theme
'@onury/docs-kit/styles/theme.css', // shared theme
'./src/styles/overrides.css', // per-project tokens (accent…)
'./src/styles/hero.css' // project-owned hero
],
plugins: [ starlightTypeDoc({ entryPoints: ['../src/index.ts'], /* … */ }) ],
sidebar: [ /* … */, typeDocSidebarGroup ]
})
]
});Edit it freely — it's the project's own config. Re-running docs-kit init --force
regenerates it.
import { syncDocs } from '@onury/docs-kit/sync';
syncDocs({
root: resolve(here, '../..'),
outDir: resolve(here, '../src/content/docs'),
base: '/myproject',
files: [{ src: 'CHANGELOG.md', out: 'changelog.md', title: 'Changelog' }, /* … */]
});A file: dependency on this repo is a symlink, which sits outside the
project's node_modules; npm can't then resolve the kit's own dependencies for
it. Use --install-links, which packs the kit like a real tarball and hoists its
deps into the project — exactly how the git dependency behaves in CI:
npm --prefix site install --install-linksRe-run it after changing kit JS/CSS. (For the published git dep, plain
npm install / npm ci is correct — no flag needed.)
# in this repo, after committing changes
git tag -f v1 && git push -f origin v1 # move v1, or cut v2 for breaking changes
# in each consuming project
npm --prefix site update @onury/docs-kitProjects pin #v1; moving the tag + npm update rolls the theme forward. Cut a
new major tag (v2) for breaking syncDocs/scaffolder changes.