import type { ReactNode } from "react"; import type { Metadata } from "next"; import type { MDXComponents } from "mdx/types"; import { notFound } from "next/navigation"; import { Banner } from "fumadocs-ui/components/banner"; import { DocsLayout } from "fumadocs-ui/layouts/notebook"; import { DocsBody, DocsDescription, DocsPage, DocsTitle, MarkdownCopyButton, ViewOptionsPopover, } from "fumadocs-ui/layouts/notebook/page"; import { createRelativeLink } from "fumadocs-ui/mdx"; import { baseOptions } from "@/lib/layout.shared"; import { getMDXComponents } from "@/components/mdx"; import { gitConfig } from "@/lib/shared"; import { getPageContributors } from "@/lib/contributors"; import { getPageDescription } from "@/lib/source"; import Footer from "@/src/layouts/Footer"; import NavHeader from "@/src/layouts/NavHeader"; import TocFooter from "@/src/components/TocFooter"; import SidebarSearch from "@/src/layouts/SidebarSearch"; import LanguageSelector from "@/components/language-selector/language-selector"; import Link from "next/link"; // Each section's fumadocs-mdx collection resolves to a differently-typed // `LoaderOutput` (docs vs guides vs integrations all have their own // schema generics). The cross-section factory here is intentionally // agnostic to that shape, so the source is typed loosely. Using a // stricter shared type (`ReturnType`) doesn't unify // across collections and would require each caller to cast. // eslint-disable-next-line @typescript-eslint/no-explicit-any type Source = any; type SectionPageProps = { params: Promise<{ slug?: string[] }>; }; // Pages produced by our fumadocs-mdx collections carry the standard MDX frontmatter // (title, description) plus body/toc/full injected by fumadocs-mdx. The core loader // type is generic over this, so cast to a minimal shape we rely on here. // eslint-disable-next-line @typescript-eslint/no-explicit-any type Page = any; export type SectionConfig = { /** Fumadocs loader for this section. */ source: Source; /** Relative path inside the repo where the MDX files live, used to build the "Edit on GitHub" URL. */ contentDir: string; /** Optional helper returning the public raw-markdown URL for a page (enables the copy-markdown / view-options buttons). */ getMarkdownUrl?: (page: Page) => string; /** Optional helper returning an OG image URL for a page. */ getImageUrl?: (page: Page) => string; /** * Optional custom content rendered between the page description/copy-markdown * header and the main MDX body. Used by the blog section to surface author * avatars + date; other sections leave this undefined and get the default * layout. */ renderBeforeBody?: (page: Page) => ReactNode; /** * Show the build-time git-derived contributor strip below the * "last updated" line. Opt-in per section — docs has it, blog * already surfaces authors in the byline so it skips this. */ showContributors?: boolean; /** * Optional per-section metadata extension. Return value is shallow-merged * over the base metadata produced by `generateMetadata` (title, * description, canonical, optional OG image) — with `openGraph` and * `alternates` deep-merged so a section that sets * `openGraph.type = 'article'` doesn't clobber the per-page OG image. * * Used by the blog section to set `openGraph.type`, `publishedTime`, * `modifiedTime`, and the author list on individual posts. */ extendMetadata?: (page: Page) => Promise | Metadata; /** * Section-scoped MDX components, merged on top of the global map from * `getMDXComponents`. Lets a section register components globally for * its own content (so authors don't `import` them per file) without * leaking them into other sections. Used by the blog to expose * `ClaudeCodeTerminal` and friends. */ mdxComponents?: MDXComponents; }; /** * Build the layout + page handlers for a docs section. * * Usage in `app/
/layout.tsx`: * export default sectionDocs.Layout; * * Usage in `app/
/[[...slug]]/page.tsx`: * export default sectionDocs.Page; * export const generateStaticParams = sectionDocs.generateStaticParams; * export const generateMetadata = sectionDocs.generateMetadata; */ export function createSection(config: SectionConfig) { const { source, contentDir, getMarkdownUrl, getImageUrl, renderBeforeBody, showContributors, extendMetadata, mdxComponents, } = config; function Layout({ children }: { children: ReactNode }) { const { nav, ...rest } = baseOptions(); return ( <> 🔥 DeepEval 4.0 just got released.{" "} Read the announcement. ), }} > {children}