kohaku-docs

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.
1,955
Install
npm install kohaku-docs
Latest Version:0.3.0
Vue:3
License:Apache-2.0
Last Updated:Jun 12, 2026
Links: npm
Maintainer: kblueleaf

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, and markdown-it-attrs.
  • Syntax highlighting via highlight.js with 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-scheme on 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 _redirects file for SPA fallback is emitted into dist/ automatically.
  • Multi-language support: ships dictionaries for en, zh-TW, zh-CN, ja, de, ko and 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-docs

Or one-shot via npx:

npx kohaku-docs gen ./docs

Quick 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 ./dist

The 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 server

Configuration

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

  1. Push the repo to GitHub / GitLab.
  2. Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect Git.
  3. Build command: npm install && npm run build
  4. Output directory: dist
  5. NODE_VERSION=20 environment 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 ./dist

Tech 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

Related Packages

@docsector/docsector-reader

A documentation rendering engine built with Vue 3, Quasar v2 and Vite. Transform...

29,198 21
kawapress

A Vue-centric static site generator

712 8
mdnook

Browse a local Markdown folder in an explorer-style web reader.

468 0
create-vue-docs-ui

Scaffolding tool for Vue Docs UI projects - Create beautiful documentation websi...

794 0
@bindr/bindr

(WIP) Convention-based Markdown documentation generator.

366 0

Version History

Version Released Vue License
0.3.0 ^3.5.13 Apache-2.0
0.2.7 ^3.5.13 Apache-2.0
0.2.6 ^3.5.13 Apache-2.0
0.2.5 ^3.5.13 Apache-2.0
0.2.4 ^3.5.13 Apache-2.0