Visitar URL original
Fumapress

Turn your Markdown into a documentation site.

Fumapress is a site generator for docs, blogs and API references, offering a polished theme, search and other features with zero configuration.

原稿The manuscript

Only the writing is left to you.

Each file you write becomes a page, and each folder a chapter in the sidebar. There are no routes to wire and no layouts to keep in step.

When words alone fall short, MDX lets you set a React component between the lines.

content/deploy.mdx---title: Deploy---Push to main, and the site goes live.<Callout>Every pull request gets a preview.</Callout>
丁合Gathering

Publish content from any source as one site.

Keep pages as files in your repository, or fetch them from Notion, Obsidian, Sanity or a source of your own. Fumapress serves each source under its own path.

export default createPress({
  docs: docs.toFumadocsSource({ baseDir: "docs" }),
  guides: notion.dynamicSource({ baseDir: "guides" }),
  // a vault and a Sanity dataset join the same way
}).plugins(notionPlugin({ notion }));
装丁Binding

It looks finished on day one, and stays yours to change.

Every page is built on Fumadocs UI, a design already refined on many documentation sites, with dark mode and phone layouts included. Pick a layout and a color theme, and there is nothing left to design.

When you want your own design, the Fumadocs CLI installs any component or layout into your project, where its source is yours to edit.

付録Appendix

When your docs grow, the site grows with them.

A blog for your news, a changelog for your releases, an AI that answers from your pages, a reference drawn from your API spec. Each is one plugin away.

No. 01Blog

Turn a content collection into blog posts, an index and tag pages.

press.config.tsx

import { createPress } from "fumapress";
import { blogPlugin } from "@fumapress/blog";
import { defineDocs } from "fumadocs-mdx/macro";

const docs = defineDocs({
  dir: "content/docs",
  docs: { async: true },
});
const blog = defineDocs({
  dir: "content/blog",
  docs: { async: true },
});

export default createPress({
  docs: docs.toFumadocsSource(),
  blog: blog.toFumadocsSource({ baseDir: "blog" }),
}).plugins(blogPlugin({ source: "blog" }));
試し刷りTest print

Try it here before you install anything.

Settings

Appearance

Layout
Theme
Neutral

Features

Details

Tabs
Folders
On this page
import { createPress } from "fumapress";import { defineDocs } from "fumadocs-mdx/macro";import { createOpenAPI } from "fumadocs-openapi/server";import openapiPlugin from "fumadocs-openapi/press";import { DocsLayout } from "fumadocs-ui/layouts/docs";import {  DocsBody,  DocsDescription,  DocsPage,  DocsTitle,} from "fumadocs-ui/layouts/docs/page"; const docs = defineDocs({ dir: "content/docs" });const openapi = createOpenAPI({ input: ["./openapi.json"] }); export default createPress({  docs: docs.toFumadocsSource(),  openapi: await openapi.staticSource(),})  .plugins(    openapiPlugin({ server: openapi }),  )  .config({    site: { name: "Acme Docs" },    ui: {      renderPage(props) {        const { renderDefault } = props;        if (props.type !== "docs" && props.type !== "openapi") return renderDefault();        const { layoutProps, pageData, toc, body, slots } = props;         return (          <DocsLayout {...layoutProps}>            <DocsPage toc={toc} full={pageData.full}>              <DocsTitle>{pageData.title}</DocsTitle>              <DocsDescription>{pageData.description}</DocsDescription>              <div className="flex gap-2">                {slots["core:markdown"]?.element}                {slots["core:view-options"]?.element}              </div>              <DocsBody>{body}</DocsBody>            </DocsPage>          </DocsLayout>        );      },    },  });
奥付Colophon

Your first page is one command away.

Custom pages are React Server Components.

Custom pages are .astro files with React islands.

Welcome to Fumapress

FumapressA press for your wordsWritten byFuma NamaBuilt onFumadocsLicenseMIT検印文

A star helps Fumapress reach the next writer.

Star on GitHub