White Papers

Configuration

Site title, navigation, theme colors, and search behavior — everything that customizes how the docs feel.

Most of the site's behavior is controlled by three files. Once you know what each one owns, customization is straightforward.

Where things live

layout.tsx
globals.css
source.ts
layout.shared.ts
meta.json
index.mdx
source.config.ts

Site title and navigation

Edit lib/layout.shared.ts — this is the single source of truth for the brand title, nav links, and footer.

lib/layout.shared.ts
export const baseOptions = {
  nav: {
    title: "nxt-whitepapers",
  },
  links: [
    { text: "GitHub", url: "https://github.com/your-org/nxt-whitepapers" },
  ],
};

The nav.title shows in the top-left of both the docs sidebar and any home pages you add.

Theme colors

Fumadocs uses CSS variables for color — primary, background, foreground, muted, and so on. To match the brand, override them in app/globals.css:

app/globals.css
:root {
  --brand-blue-300: #93c5fd;
  --brand-sky-500: #0ea5e9;
  --gradient-primary: linear-gradient(
    to bottom,
    var(--brand-blue-300),
    var(--brand-sky-500)
  );
  --color-fd-primary: var(--brand-sky-500);
}

Why OKLCH?

OKLCH is perceptually uniform — same lightness value reads as the same brightness across hues. HSL fakes this and tends to produce muddier mid-tones. If you prefer HSL, both formats work; just be consistent across light and dark variants.

The order of pages in the sidebar comes from meta.json files. Each folder can have one:

content/docs/meta.json
{
  "pages": [
    "index",
    "ai-machine-learning",
    "coding-tutorials",
    "security",
    "ui-ux",
    "performances"
  ]
}
  • "index" and "ai-machine-learning" are file/folder names (no extension)
  • "---Label---" becomes a section divider with the given text

Pages not listed in meta.json are appended to the end in alphabetical order. To hide a page, prefix the filename with _ — Fumadocs ignores those.

Search is configured in app/api/search/route.ts. It uses Fumadocs' advanced mode, which indexes headings and body text:

app/api/search/route.ts
import { source } from "@/lib/source";
import { createSearchAPI } from "fumadocs-core/search/server";

export const { GET } = createSearchAPI("advanced", {
  indexes: source.getPages().map((page) => ({
    title: page.data.title,
    structuredData: page.data.structuredData,
    id: page.url,
    url: page.url,
  })),
});

Switch to "simple" if you only want to match titles — faster, less useful.

Feedback collector

The thumbs-up/thumbs-down widget at the bottom of every page is wired in app/docs/[[...slug]]/page.tsx. Right now it console.logs the response; replace the server action body with a fetch to your analytics endpoint.

{async (feedback) => {
  "use server";
  console.log("[feedback]", feedback);
  return {};
}}
{async (feedback) => {
  "use server";
  await posthog.capture("docs_feedback", feedback);
  return {};
}}
{async (feedback) => {
  "use server";
  await fetch("https://api.example.com/feedback", {
    method: "POST",
    body: JSON.stringify(feedback),
  });
  return {};
}}

How is this guide?

On this page