kohaku-docs
v0.2.7
Published
Static documentation site generator for Markdown docs, powered by Vue and Vite. Ships a CLI (build/dev/preview/gen) and a warm, gem-accented default theme.
Downloads
1,084
Maintainers
Readme
kohaku-docs
Static documentation site generator for Markdown docs. Ships a CLI and a warm neutral + gem-accent theme. Build output is a single-page app that deploys to any static host.
Features
- Markdown with frontmatter, containers (
:::tip,:::warning,:::details), footnotes, task lists, KaTeX math, andmarkdown-it-attrs. - Syntax highlighting via
highlight.jswith gem-tinted tokens. - Client-side full-text search (
minisearch) over titles, summaries, and body. - Auto sidebar from your directory or an explicit tree in config. Breadcrumbs + prev/next nav.
- Right-column TOC extracted from headings.
- Light / dark theme toggle, respects
prefers-color-schemeon first load. - Three-column layout: left sidebar, article, right TOC — each an independent scroll region.
- File-based routing (
unplugin-vue-router) with clean HTML5-history URLs. A_redirectsfile for SPA fallback is emitted intodist/automatically. - Multi-language support: ships dictionaries for
en,zh-TW,zh-CN,ja,de,koand lets authors add any locale with an inline UI dictionary. Per-locale docs tree, sidebar, home, and editBaseUrl. Configurable missing-translation policy.
Install
npm install -D kohaku-docsOr one-shot via npx:
npx kohaku-docs gen ./docsQuick start
# 1. scaffold config + starter sidebar based on your ./docs folder
npx kohaku-docs gen ./docs
# 2. dev server with live reload
npx kohaku-docs dev ./docs
# 3. build static site
npx kohaku-docs build ./docs --out-dir ./dist
# 4. preview the built site
npx kohaku-docs preview ./docs --out-dir ./distThe gen command scans your ./docs folder, picks a home page (README.md or index.md), and writes a docs.config.js with a starter sidebar.
CLI
kohaku-docs <command> <docsDir> [options]
Commands
build <docsDir> Build a static docs site
dev <docsDir> Run a dev server
preview <docsDir> Preview a built site
gen <docsDir> Generate a starter docs.config.js
Options
-c, --config <path> Config file (default: <cwd>/docs.config.js)
-o, --out-dir <path> Output directory (default: <docsDir>/dist)
--base <path> Vite base path (default: ./)
--cwd <path> Working directory for config resolution
--host <host> Host for dev/preview server (default: 0.0.0.0)
--port <port> Port for dev/preview serverConfiguration
Minimal docs.config.js:
export default {
docsDir: './docs',
homePage: 'README.md',
site: {
title: 'My Docs',
description: 'Short tagline.',
editBaseUrl: 'https://github.com/your-org/your-repo/edit/main/',
},
home: {
kicker: 'Documentation',
title: 'My Docs',
description: 'Landing copy.',
actions: [{ text: 'Read docs', to: '/docs' }],
cards: [
{ title: 'Getting started', description: '...', to: '/docs/getting-started' },
],
},
sidebar: [
{
text: 'Guide',
items: [
'getting-started.md',
{ text: 'Custom label', file: 'architecture.md' },
{ text: 'Reference', autoDir: 'reference', recursive: true },
],
},
],
}Sidebar item forms: a string path, { text, file, slug }, or { text, autoDir, recursive, sort } to auto-expand a directory.
Multi-language
Opt in by adding a locales block to docs.config.js. Every field that was at the top level (homePage, site, home, sidebar) is nested per locale, and the docsDir gains a docsSubdir pointing at the locale-specific folder. URLs become prefixed (e.g., /en/docs/foo, /zh-TW/docs/foo); without locales, URLs stay flat (/docs/foo).
export default {
docsDir: './docs',
defaultLocale: 'en',
missingTranslation: 'fallback', // 'fallback' | 'banner' | 'home'
locales: {
en: {
label: 'English',
docsSubdir: 'en',
homePage: 'README.md',
site: { title: 'My Docs', editBaseUrl: '.../edit/main/docs/en/' },
home: { kicker: 'Documentation', title: 'My Docs', actions: [...] },
sidebar: [...],
ui: 'en', // borrow built-in dict (default: same code)
},
'zh-TW': {
label: '繁體中文',
docsSubdir: 'zh-TW',
homePage: 'README.md',
site: { title: '我的文件', editBaseUrl: '.../edit/main/docs/zh-TW/' },
home: { kicker: '文件', title: '我的文件', actions: [...] },
sidebar: [...],
ui: 'zh-TW',
},
fr: { // locale we don't ship a dict for
label: 'Français',
docsSubdir: 'fr',
homePage: 'README.md',
site: { title: 'Ma Documentation' },
home: { kicker: 'Documentation', title: 'Ma Documentation' },
sidebar: [...],
ui: { // inline UI overrides; missing keys fall back to en
'ui.browseDocs': 'Parcourir',
'ui.onThisPage': 'Sur cette page',
'ui.searchPlaceholder': 'Rechercher',
'ui.navPrevious': 'Précédent',
'ui.navNext': 'Suivant',
},
},
},
}Shipped UI locales: en, zh-TW, zh-CN, ja, de, ko (see src/locales/). Any UI key not provided by a custom ui object falls back to en.
missingTranslation chooses what happens when a page exists in the default locale but not the current one:
'fallback'(default) — render the default-locale page with a "Translation not available" banner.'banner'— render the default-locale page with a "Still translating" banner.'home'— redirect to the current locale's home.
Search searches the active locale first; if there are no results, it falls back to the default locale and tags the results with the default-locale label.
Deploying
The build output (./dist) is a fully static SPA using HTML5 history URLs. npm run build emits a _redirects file (/* /index.html 200) that Cloudflare Pages and Netlify pick up automatically for the SPA fallback. Other hosts need a one-line equivalent — see below.
Cloudflare Pages
- Push the repo to GitHub / GitLab.
- Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect Git.
- Build command:
npm install && npm run build - Output directory:
dist NODE_VERSION=20environment variable.
GitHub Pages
Push dist/ to a gh-pages branch, or use actions/deploy-pages. GitHub Pages ignores _redirects; add a dist/404.html copy of index.html for SPA fallback, or use hash routing by overriding main.js (not recommended).
Vercel
Build command npm run build, publish directory dist. Add vercel.json with { "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] } if the auto-detect doesn't handle SPA fallback.
Netlify
Auto-detects the _redirects file that npm run build already emits. No extra config.
Self-hosted nginx / caddy
scp dist/ user@host:/var/www/docs and point the webroot at it. In nginx: try_files $uri $uri/ /index.html; inside the location / block. In caddy: try_files {path} /index.html.
Theme
The default palette is a warm neutral scale (warm-50..warm-950) plus seven jewel accents (iolite, sapphire, aquamarine, taaffeite, amber, coral, sage), each with -light and -shadow variants. The primary accent is iolite. Callouts map: tip → sage, warning → amber, details → iolite, danger → coral.
All tokens live in src/styles/main.css (CSS variables) and uno.config.js (UnoCSS shortcuts). Dark mode toggles the dark class on <html>.
Development
git clone https://github.com/Kohaku-Lab/Kohaku-Docs.git
cd Kohaku-Docs
npm install
npm run dev # runs against the included ./docs folder
npm run build # builds ./distTech stack: Vue 3 + Vite (rolldown-vite) + UnoCSS + Element Plus + Pinia + unplugin-vue-router (file-based routes under src/pages/) + unplugin-auto-import + unplugin-vue-components. No TypeScript. Lint with ESLint flat config, format with Prettier (no semicolons, double quotes, 100-col).
CLI entry: scripts/cli.mjs. The build pipeline at scripts/lib/build-docs-site.mjs reads Markdown, extracts frontmatter / TOC, rewrites internal links (with locale prefix in multi-locale mode), copies referenced assets, and emits .docs/site.json + .docs/search.json per locale (plus .docs/manifest.json in multi-locale mode). The Vue frontend fetches the active locale's bundle at runtime.
Useful scripts: npm run dev, npm run build, npm run preview, npm run lint, npm run lint:fix, npm run format, npm run format:check.
License
Apache2 © Kohaku
