Skip to content

Commit c4540c7

Browse files
authored
feat: mdx fumadocs docs migration
- Set up Next.js + Fumadocs site in apps/docs - Migrate all documentation to .mdx format - Fix CI test hangs and documentation routing 404s
2 parents bc920c2 + c5ab617 commit c4540c7

File tree

28 files changed

+6527
-6
lines changed

28 files changed

+6527
-6
lines changed

apps/docs/.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# deps
2+
/node_modules
3+
4+
# generated content
5+
.source
6+
7+
# test & build
8+
/coverage
9+
/.next/
10+
/out/
11+
/build
12+
*.tsbuildinfo
13+
14+
# misc
15+
.DS_Store
16+
*.pem
17+
/.pnp
18+
.pnp.js
19+
npm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*
22+
23+
# others
24+
.env*.local
25+
.vercel
26+
next-env.d.ts

apps/docs/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Multi-PB Documentation Site
2+
3+
This is the Next.js documentation site for Multi-PB, built using [Fumadocs](https://fumadocs.dev).
4+
5+
Run development server:
6+
7+
```bash
8+
npm run dev
9+
```
10+
11+
Open http://localhost:3000 with your browser to see the result.
12+
13+
## Explore
14+
15+
In the project, you can see:
16+
17+
- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content.
18+
- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep.
19+
20+
| Route | Description |
21+
| ------------------------- | ------------------------------------------------------ |
22+
| `app/(home)` | The route group for your landing page and other pages. |
23+
| `app/docs` | The documentation layout and pages. |
24+
| `app/api/search/route.ts` | The Route Handler for search. |
25+
26+
### Fumadocs MDX
27+
28+
A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
29+
30+
Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details.
31+
32+
## Learn More
33+
34+
To learn more about Next.js and Fumadocs, take a look at the following
35+
resources:
36+
37+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
38+
features and API.
39+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
40+
- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs

apps/docs/app/api/search/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { source } from '@/lib/source';
2+
import { createFromSource } from 'fumadocs-core/search/server';
3+
4+
export const { GET } = createFromSource(source, {
5+
// https://docs.orama.com/docs/orama-js/supported-languages
6+
language: 'english',
7+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { getPageImage, source } from '@/lib/source';
2+
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
3+
import { notFound } from 'next/navigation';
4+
import { getMDXComponents } from '@/mdx-components';
5+
import type { Metadata } from 'next';
6+
import { createRelativeLink } from 'fumadocs-ui/mdx';
7+
import { LLMCopyButton, ViewOptions } from '@/components/ai/page-actions';
8+
9+
export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
10+
const params = await props.params;
11+
const page = source.getPage(params.slug);
12+
if (!page) notFound();
13+
14+
const MDX = page.data.body;
15+
const gitConfig = {
16+
user: 'username',
17+
repo: 'repo',
18+
branch: 'main',
19+
};
20+
21+
return (
22+
<DocsPage toc={page.data.toc} full={page.data.full}>
23+
<DocsTitle>{page.data.title}</DocsTitle>
24+
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
25+
<div className="flex flex-row gap-2 items-center border-b pb-6">
26+
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
27+
<ViewOptions
28+
markdownUrl={`${page.url}.mdx`}
29+
// update it to match your repo
30+
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/docs/content/docs/${page.path}`}
31+
/>
32+
</div>
33+
<DocsBody>
34+
<MDX
35+
components={getMDXComponents({
36+
// this allows you to link to other pages with relative file paths
37+
a: createRelativeLink(source, page),
38+
})}
39+
/>
40+
</DocsBody>
41+
</DocsPage>
42+
);
43+
}
44+
45+
export async function generateStaticParams() {
46+
return source.generateParams();
47+
}
48+
49+
export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise<Metadata> {
50+
const params = await props.params;
51+
const page = source.getPage(params.slug);
52+
if (!page) notFound();
53+
54+
return {
55+
title: page.data.title,
56+
description: page.data.description,
57+
openGraph: {
58+
images: getPageImage(page).url,
59+
},
60+
};
61+
}

apps/docs/app/docs/layout.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { source } from "@/lib/source";
2+
import { DocsLayout } from "fumadocs-ui/layouts/docs";
3+
import { baseOptions } from "@/lib/layout.shared";
4+
5+
export default function Layout({ children }: LayoutProps<"/">) {
6+
return (
7+
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
8+
{children}
9+
</DocsLayout>
10+
);
11+
}

apps/docs/app/global.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@import 'tailwindcss';
2+
@import 'fumadocs-ui/css/neutral.css';
3+
@import 'fumadocs-ui/css/preset.css';

apps/docs/app/layout.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { RootProvider } from 'fumadocs-ui/provider/next';
2+
import './global.css';
3+
import { Inter } from 'next/font/google';
4+
5+
const inter = Inter({
6+
subsets: ['latin'],
7+
});
8+
9+
export default function Layout({ children }: LayoutProps<'/'>) {
10+
return (
11+
<html lang="en" className={inter.className} suppressHydrationWarning>
12+
<body className="flex flex-col min-h-screen">
13+
<RootProvider>{children}</RootProvider>
14+
</body>
15+
</html>
16+
);
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getLLMText, source } from '@/lib/source';
2+
3+
export const revalidate = false;
4+
5+
export async function GET() {
6+
const scan = source.getPages().map(getLLMText);
7+
const scanned = await Promise.all(scan);
8+
9+
return new Response(scanned.join('\n\n'));
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { getLLMText, source } from '@/lib/source';
2+
import { notFound } from 'next/navigation';
3+
4+
export const revalidate = false;
5+
6+
export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) {
7+
const { slug } = await params;
8+
const page = source.getPage(slug);
9+
if (!page) notFound();
10+
11+
return new Response(await getLLMText(page), {
12+
headers: {
13+
'Content-Type': 'text/markdown',
14+
},
15+
});
16+
}
17+
18+
export function generateStaticParams() {
19+
return source.generateParams();
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { getPageImage, source } from "@/lib/source";
2+
import { notFound } from "next/navigation";
3+
import { ImageResponse } from "next/og";
4+
import { generate as DefaultImage } from "fumadocs-ui/og";
5+
6+
export const revalidate = false;
7+
8+
export async function GET(
9+
_req: Request,
10+
{ params }: RouteContext<"/og/docs/[...slug]">,
11+
) {
12+
const { slug } = await params;
13+
const page = source.getPage(slug.slice(0, -1));
14+
if (!page) notFound();
15+
16+
return new ImageResponse(
17+
<DefaultImage
18+
title={page.data.title}
19+
description={page.data.description}
20+
site="Multi PB Docs"
21+
/>,
22+
{
23+
width: 1200,
24+
height: 630,
25+
},
26+
);
27+
}
28+
29+
export function generateStaticParams() {
30+
return source.getPages().map((page) => ({
31+
lang: page.locale,
32+
slug: getPageImage(page).segments,
33+
}));
34+
}

0 commit comments

Comments
 (0)