npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@opentf/afw-docs

v0.36.0

Published

Documentation and blog sites built as ordinary AFW apps.

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-cli

esdev 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), from blog.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/.mdx page. Prerendered and client-rendered pages carry the same colors; nothing highlights in the browser. The theme colors tokens with GitHub Light and GitHub Dark, following data-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.