Skip to content

Latest commit

 

History

240 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

duxt

Versioned, multi-repo documentation for Nuxt — one line to extend, no collection boilerplate

npm Version Downloads Tests Node Version License: MIT


export default defineNuxtConfig({
  extends: ['@kirchdev/duxt'],
})

That's it. Put your Markdown in docs/ and you have a themed documentation site — search, navigation, table of contents, dark mode, llms.txt and an MCP server — with no collection, no layout and no config written by hand.

🤔 Why

Nuxt Content v3 already downloads and caches a git repository, at a branch or at a tag, private ones included — so nothing here rebuilds that. What it does not give you is the part that gets retyped in every documentation repo: one collection per version × repository, a URL scheme that carries them, a version switcher that knows which page exists where, and a theme on top.

duxt turns all of it into one list. Sources are declared once, and the collections, the prefixes, the switcher, the redirects and the sitemap are generated from that declaration.

📦 Install & run

pnpm add -D @kirchdev/duxt

The extends line above is the whole of the single-folder case. Everything beyond it is one file — app/app.config.ts, which both halves of the layer read:

export default defineAppConfig({
  duxt: {
    title: 'Acme',
    sources: [
      { path: 'docs', slug: 'acme' },                          // this repository
      { repo: 'acme/api', path: 'docs', refs: ['main', 'v2.0.0', 'v1.4.0'] },
    ],
    sourceOptions: { defaultRef: 'v2.0.0' },
  },
})

Two repositories and three refs become five collections, the URL prefixes that serve them, and a version switcher — none of which you write.

✨ Features

  • 📦 Extend, don't scaffold — a Nuxt layer: theme, pages, components and app.config defaults arrive with extends and are overridden file by file where you disagree.
  • 🗂️ Sources as a list — one compact entry per source instead of one Content collection per version × repository.
  • 🧭 Version switcher and URL scheme/[repo]/[version]/[...slug], collapsing cleanly when there is one source and no versions, with a lifecycle per version that decides the banner a reader gets.
  • 🌿 Git-native sourcing — branches, tags, private repositories and hash-based caching come straight from Content v3's own repository support; 'latest' resolves to the newest semver tag at build time.
  • 🤖 Machine-readable by defaultllms.txt, llms-full.txt and a real MCP server at /mcp, generated from the same collections the pages render from.
  • 🎨 shadcn-vue theme, owned not vendored — Tailwind 4 with the components in app/components/ui/, MDC components in app/components/content/.
  • 🔍 Search, TOC, breadcrumb, prev/next — ⌘K fuzzy search across every source, active-heading tracking, section landing pages, feedback and "Edit this page" links.
  • 🧯 A build that fails loudly — a validator walks the parse cache for URL collisions, empty collections, broken links and missing titles, because every bug this layer actually had was a silent one.
Full feature list

Sources & versions

  • 🗂️ Sources as a list — one compact entry per source instead of one Content collection per version × repository. The single unversioned folder is the default and needs no config at all.
  • 🧭 Version switcher and URL scheme/[repo]/[version]/[...slug], collapsing cleanly when there is one source and no versions, with a lifecycle per version (upcoming, current, maintained, deprecated, eol) that decides the banner a reader gets.
  • 🌿 Git-native sourcing — branches, tags, private repositories and hash-based caching come straight from Content v3's own repository support; 'latest' resolves to the newest semver tag at build time.
  • 🔁 Redirects from frontmatterredirectFrom on a moved page becomes route rules under every repository, version and locale prefix it is served at.

Theme & reading experience

  • 🎨 shadcn-vue theme, owned not vendored — Tailwind 4 with the components in app/components/ui/, MDC components (::callout, ::steps, ::code-group, file trees, Mermaid) in app/components/content/.
  • 🔍 Search, TOC, breadcrumb, prev/next — ⌘K fuzzy search across every source, active-heading tracking, section landing pages, feedback and "Edit this page" links.
  • 🌍 Seven locales out of the boxen-GB, en-US, de-DE, es-ES, fr-FR, pt-PT and pt-BR; a site picks which of them it serves, and its own strings take a literal, a key or a per-locale record.

Machine-readable & SEO

  • 🤖 Machine-readable by defaultllms.txt, llms-full.txt and a real MCP server at /mcp (list pages, read a page, search), generated from the same collections the pages render from.
  • 📈 SEO and feeds included — sitemap, robots, generated OG images, and an optional /rss.xml over a section you nominate.

Layer & build

  • 📦 Extend, don't scaffold — a Nuxt layer: theme, pages, components and app.config defaults arrive with extends and are overridden file by file where you disagree.
  • 🧯 A build that fails loudly — a validator walks the parse cache for URL collisions, empty collections, broken links and missing titles, because every bug this layer actually had was a silent one.
  • 🔎 DevTools tab — the resolved sources, collections, prefixes, message catalogues and download cache, in dev, where guessing used to be the only option.

⚙️ Configuration

Everything lives under the duxt key of app.config.ts. The keys most sites touch:

Key What it controls
sources The documentation sources — folder, repository, refs, lifecycle, history.
sourceOptions How those become URL prefixes (defaultRef, showRepo, showVersion).
title The site name, in the navbar and every generated document.
locales Which of the layer's locales this site serves. Read at build time.

Every text field takes a literal, an i18n key, or a per-locale record — a single-language site never sees the other two.

Tip

The full surface — navigation, sections, landing, feed, footer and the rest — is typed, and the types are the documentation: app/types/duxt.d.ts carries a comment per key explaining what it costs and when it is read.

🧪 Development

git clone https://github.com/kirchDev/duxt.git
cd duxt
pnpm install   # wires the husky hooks
pnpm check     # lint + format + typecheck + tests + policy parity + build + a11y

The repo root is the layer — nuxt.config.ts, content.config.ts, app/, modules/ and server/ live there, and package.json points at them. www/ beside it is the site that consumes the layer, and the development target: it deliberately carries the awkward cases — two repositories, four refs, one version of each lifecycle. It is not a template; the exemplary starting point lives in kirchDev/duxt-starter.

🎨 Assets & branding

The mark is the package name with its first letter bracketed — [d]uxt — because that is how the package is written where it is used: extends: ['@kirchdev/duxt'], an array with one entry. It is set in IBM Plex Mono SemiBold and converted to outlines, so no asset depends on the font being installed anywhere.

Note

The wordmark is AI-assisted placeholder artwork — a stand-in to be replaced at some point, with no fixed timeline. No image generator was involved: it is typeset, not drawn.

Every asset, the colour values, why the icon's brackets are redrawn and the font licensing are in Conventions → Branding.

Important

The layer ships no branding. duxt.logo is unset by default, so DuxtBrand falls back to the consumer's own duxt.title beside a generic icon: a site extending duxt shows its own name in the header and footer and its own icon in the tab, never this one. These assets belong to this repository and to www/, not to the published package.

🤝 Contributing

PRs welcome. Conventional Commits are enforced via commitlint, and husky runs the linters on git commit. Branch off dev.

Tip

Run pnpm check:fix before pushing — CI will catch what husky missed.

See CONTRIBUTING.md for the full workflow.

🛣️ Versioning

Semantic Versioning via release-please — see the releases.

📄 License

MIT © Titus Kirch / IT-Dienstleistungen Titus Kirch

About

Nuxt documentation layer on Content v3 — multi-repo, versioned docs from one compact source list.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

Generated from TitusKirch/scaffold