@opentf/afw-docs
v0.36.0
Published
Documentation and blog sites built as ordinary AFW apps.
Maintainers
Readme
@opentf/afw-docs
Documentation and blog sites built as ordinary AFW apps
Docs | API | Changelog | GitHub
An Open Tech Foundation project
Write pages as MDX in
app/. The theme supplies the navbar, sidebar, table of contents, breadcrumbs, search and prev/next links, and generates the navigation from your folders at build time. The AFW website is built with it.
// app/docs/layout.jsx
import { DocsLayout } from "@opentf/afw-docs";
import config from "../../afw.config.js";
export default function Layout(props) {
return <DocsLayout config={config.docs}>{props.children}</DocsLayout>;
}---
title: Reactivity
description: Signal-based state.
---
import { Callout } from "@opentf/afw-docs";
# Reactivity
<Callout type="tip">Mix components into Markdown freely.</Callout>Every folder under app/ with a layout like this becomes its own section with its
own sidebar: app/docs serves /docs and app/api serves /api.
[!NOTE] Alpha. Components, options and class names can change between minor versions; see the changelog.
Why afw-docs
| Need | How afw-docs meets it |
| --- | --- |
| 🧭 Navigation from folders | The sidebar, breadcrumbs and prev/next are generated from app/; _meta.js sets order and labels |
| 🔎 Search without a service | A static index built from the prerendered HTML by afwc, queried in the browser |
| ✍️ MDX with components | Callouts, tabs, steps, cards and code blocks with copy buttons, highlighted at build time |
| 📰 Blog included | Post lists, banners, reading time and RSS/Atom feeds |
| 🕒 Last updated and edit links | Dates from git history or frontmatter, linked to the source file |
| 🌗 Themeable | Light and dark modes driven by --afw-* CSS variables, in an overridable cascade layer |
| 🤖 LLM-ready | llms.txt and llms-full.txt generated at build |
Install
pnpm add @opentf/afw-docs @opentf/afw
pnpm add -D @opentf/esdev-plugin-afw @opentf/afw-cliesdev create my-docs --template=docs generates a complete site. To add the theme
to an existing project, import its stylesheet and register the build plugins:
/* app/global.css */
@import "@opentf/afw-docs/theme";{
"plugins": [
{ "module": "@opentf/esdev-plugin-afw", "options": { "mode": "ssg" } },
{ "module": "@opentf/afw-docs/build", "export": "afwDocsPlugin", "options": { "appDir": "app" } }
]
}afwDocsPlugin is the whole docs toolchain in one entry (esdev 0.27 or later). It reads
afw.config.js and enables what the config asks for:
docs→ the sidebar navigation (@opentf/afw-docs/nav).blog→ the post list (@opentf/afw-docs/posts), fromblog.dir.lastUpdated→ the per-page dates and edit links (@opentf/afw-docs/updated).- Always → code-fence highlighting with
@opentf/syntax-highlighter, at build time on each compiled.md/.mdxpage. Prerendered and client-rendered pages carry the same colors; nothing highlights in the browser. The theme colors tokens with GitHub Light and GitHub Dark, followingdata-theme.
Options:
appDir— the routes folder, resolved from the directory esdev runs in (default"app").exclude— folders under it that hold no pages.
The individual plugins (docsNavPlugin, blogPostsPlugin, lastUpdatedPlugin,
codeHighlightPlugin) are still exported for custom setups.
With Vite
In the Vite + Node workflow, add @opentf/afw-docs/vite next to the AFW Vite plugin.
It reads the same afw.config.js, serves the generated navigation, post list and
last-updated map, and after the prerender writes the search index, the blog's RSS and
Atom feeds, and llms.txt:
pnpm add @opentf/afw-docs @opentf/afw
pnpm add -D vite @opentf/vite-plugin-afw// vite.config.js
import afw from "@opentf/vite-plugin-afw";
import afwDocs from "@opentf/afw-docs/vite";
export default { plugins: [afw({ mode: "ssg" }), afwDocs()] };vite build writes the static site to dist/; vite preview serves it.
Configure
// afw.config.js
import { defineDocsConfig } from "@opentf/afw-docs/config";
export default defineDocsConfig({
site: { url: "https://docs.example.com" },
docs: {
title: "My Project",
github: "https://github.com/me/my-project",
repoUrl: "https://github.com/me/my-project",
nav: [
{ label: "Docs", href: "/docs" },
{ label: "Blog", href: "/blog" },
],
lastUpdated: true,
},
});Components
| Group | Components |
| --- | --- |
| Layouts | DocsLayout, BlogLayout |
| Shell | Navbar, NavbarLink, Sidebar, SidebarToggle, Toc, Breadcrumbs, Pagination, Footer, LastUpdated, ThemeToggle, Search, SearchTrigger |
| Content | Callout, Tabs, Steps, CodeBlock, Table, Cards, Card, Tooltip, NavIcon |
| Blog | PostList, PostCard, PostBanner, PostMeta, ReadingTime |
Entry points
| Import | Contents |
| --- | --- |
| @opentf/afw-docs | Every component above, plus createSearch |
| @opentf/afw-docs/theme | The default light/dark stylesheet |
| @opentf/afw-docs/config | defineDocsConfig and the config types |
| @opentf/afw-docs/build | afwDocsPlugin (all of the below as one entry), docsNavPlugin, blogPostsPlugin, lastUpdatedPlugin, codeHighlightPlugin, feed and llms.txt renderers (esdev) |
| @opentf/afw-docs/vite | afwDocs(): the same generators as one Vite plugin |
| @opentf/afw-docs/nav, /posts, /updated | Generated navigation, post list and last-updated map |
| @opentf/afw-docs/search | Browser search: createSearch, tokenize, excerptParts |
Styling
The theme's own elements use afwd-* classes (.afwd-sidebar, .afwd-callout-tip),
and its colours come from --afw-* variables that switch on [data-theme='dark'].
All theme rules sit in the afw-docs cascade layer, so any rule in your own
stylesheet overrides them without raising specificity.
License
MIT — see LICENSE.
