refactor(docs) parse and render docs mdx files by fumadocs
This commit is contained in:
parent
3b741b3b98
commit
f4d8a09ab6
3
.gitignore
vendored
3
.gitignore
vendored
@ -43,6 +43,9 @@ next-env.d.ts
|
||||
# content collections
|
||||
.content-collections
|
||||
|
||||
# fumadocs
|
||||
.source
|
||||
|
||||
# OpenNext build output
|
||||
.open-next
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
import path from 'path';
|
||||
import { DEFAULT_LOCALE, LOCALES } from '@/i18n/routing';
|
||||
import { defineCollection, defineConfig } from '@content-collections/core';
|
||||
import {
|
||||
createDocSchema,
|
||||
createMetaSchema,
|
||||
transformMDX,
|
||||
} from '@fumadocs/content-collections/configuration';
|
||||
import { transformMDX } from '@fumadocs/content-collections/configuration';
|
||||
|
||||
/**
|
||||
* 1. Content Collections documentation
|
||||
@ -16,25 +12,25 @@ import {
|
||||
* 2. Use Content Collections for Fumadocs
|
||||
* https://fumadocs.dev/docs/headless/content-collections
|
||||
*/
|
||||
const docs = defineCollection({
|
||||
name: 'docs',
|
||||
directory: 'content/docs',
|
||||
include: '**/*.mdx',
|
||||
schema: (z) => ({
|
||||
...createDocSchema(z),
|
||||
preview: z.string().optional(),
|
||||
index: z.boolean().default(false),
|
||||
}),
|
||||
transform: transformMDX,
|
||||
});
|
||||
// const docs = defineCollection({
|
||||
// name: 'docs',
|
||||
// directory: 'content/docs',
|
||||
// include: '**/*.mdx',
|
||||
// schema: (z) => ({
|
||||
// ...createDocSchema(z),
|
||||
// preview: z.string().optional(),
|
||||
// index: z.boolean().default(false),
|
||||
// }),
|
||||
// transform: transformMDX,
|
||||
// });
|
||||
|
||||
const metas = defineCollection({
|
||||
name: 'meta',
|
||||
directory: 'content/docs',
|
||||
include: '**/meta**.json',
|
||||
parser: 'json',
|
||||
schema: createMetaSchema,
|
||||
});
|
||||
// const metas = defineCollection({
|
||||
// name: 'meta',
|
||||
// directory: 'content/docs',
|
||||
// include: '**/meta**.json',
|
||||
// parser: 'json',
|
||||
// schema: createMetaSchema,
|
||||
// });
|
||||
|
||||
/**
|
||||
* Blog Author collection
|
||||
@ -324,5 +320,5 @@ function extractLocaleAndBase(fileName: string): {
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
collections: [docs, metas, authors, categories, posts, pages, releases],
|
||||
collections: [authors, categories, posts, pages, releases],
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { withContentCollections } from '@content-collections/next';
|
||||
import { createMDX } from 'fumadocs-mdx/next';
|
||||
import type { NextConfig } from 'next';
|
||||
import createNextIntlPlugin from 'next-intl/plugin';
|
||||
|
||||
@ -69,8 +69,9 @@ const nextConfig: NextConfig = {
|
||||
const withNextIntl = createNextIntlPlugin();
|
||||
|
||||
/**
|
||||
* withContentCollections must be the outermost plugin
|
||||
*
|
||||
* https://www.content-collections.dev/docs/quickstart/next
|
||||
* https://fumadocs.dev/docs/ui/manual-installation
|
||||
* https://fumadocs.dev/docs/mdx/plugin
|
||||
*/
|
||||
export default withContentCollections(withNextIntl(nextConfig));
|
||||
const withMDX = createMDX();
|
||||
|
||||
export default withMDX(withNextIntl(nextConfig));
|
||||
|
@ -6,6 +6,7 @@
|
||||
"dev": "concurrently \"content-collections watch\" \"next dev\"",
|
||||
"build": "content-collections build && next build",
|
||||
"start": "next start",
|
||||
"postinstall": "fumadocs-mdx",
|
||||
"lint": "biome check --write .",
|
||||
"lint:fix": "biome check --fix --unsafe .",
|
||||
"format": "biome format --write .",
|
||||
|
510
pnpm-lock.yaml
generated
510
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
27
source.config.ts
Normal file
27
source.config.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { defineDocs, frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
const customDocsSchema = frontmatterSchema.extend({
|
||||
preview: z.string().optional(),
|
||||
index: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const customMetaSchema = metaSchema.extend({
|
||||
description: z.string().optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* frontmatterSchema.extend causes error: Type instantiation is excessively deep,
|
||||
* so we define the schema manually.
|
||||
*
|
||||
* https://fumadocs.dev/docs/mdx/collections#schema-1
|
||||
*/
|
||||
export const docs = defineDocs({
|
||||
dir: 'content/docs',
|
||||
docs: {
|
||||
schema: customDocsSchema,
|
||||
},
|
||||
meta: {
|
||||
schema: customMetaSchema,
|
||||
},
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import { getMDXComponents } from '@/components/custom/mdx-components';
|
||||
import * as Preview from '@/components/docs';
|
||||
import { CustomMDXContent } from '@/components/shared/custom-mdx-content';
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
@ -87,6 +87,8 @@ export default async function DocPage({ params }: DocPageProps) {
|
||||
|
||||
const preview = page.data.preview;
|
||||
|
||||
const MDX = page.data.body;
|
||||
|
||||
return (
|
||||
<DocsPage
|
||||
toc={page.data.toc}
|
||||
@ -102,9 +104,8 @@ export default async function DocPage({ params }: DocPageProps) {
|
||||
{preview ? <PreviewRenderer preview={preview} /> : null}
|
||||
|
||||
{/* MDX Content */}
|
||||
<CustomMDXContent
|
||||
code={page.data.body}
|
||||
customComponents={{
|
||||
<MDX
|
||||
components={getMDXComponents({
|
||||
a: ({ href, ...props }: { href?: string; [key: string]: any }) => {
|
||||
const found = source.getPageByHref(href ?? '', {
|
||||
dir: page.file.dirname,
|
||||
@ -133,7 +134,7 @@ export default async function DocPage({ params }: DocPageProps) {
|
||||
</HoverCard>
|
||||
);
|
||||
},
|
||||
}}
|
||||
})}
|
||||
/>
|
||||
</DocsBody>
|
||||
</DocsPage>
|
||||
|
45
src/components/custom/mdx-components.tsx
Normal file
45
src/components/custom/mdx-components.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { ImageWrapper } from '@/components/docs/image-wrapper';
|
||||
import { Wrapper } from '@/components/docs/wrapper';
|
||||
import { YoutubeVideo } from '@/components/docs/youtube-video';
|
||||
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
|
||||
import { Callout } from 'fumadocs-ui/components/callout';
|
||||
import { File, Files, Folder } from 'fumadocs-ui/components/files';
|
||||
import { Step, Steps } from 'fumadocs-ui/components/steps';
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
import { TypeTable } from 'fumadocs-ui/components/type-table';
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
import * as LucideIcons from 'lucide-react';
|
||||
import type { MDXComponents } from 'mdx/types';
|
||||
import type { ComponentProps, FC } from 'react';
|
||||
|
||||
/**
|
||||
* Enhanced MDX Content component that includes commonly used MDX components
|
||||
* It can be used for blog posts, documentation, and custom pages
|
||||
*/
|
||||
export function getMDXComponents(components?: MDXComponents): MDXComponents {
|
||||
// Start with default components
|
||||
const baseComponents: Record<string, any> = {
|
||||
...defaultMdxComponents,
|
||||
...LucideIcons,
|
||||
// ...((await import('lucide-react')) as unknown as MDXComponents),
|
||||
YoutubeVideo,
|
||||
Tabs,
|
||||
Tab,
|
||||
TypeTable,
|
||||
Accordion,
|
||||
Accordions,
|
||||
Steps,
|
||||
Step,
|
||||
Wrapper,
|
||||
File,
|
||||
Folder,
|
||||
Files,
|
||||
blockquote: Callout as unknown as FC<ComponentProps<'blockquote'>>,
|
||||
img: ImageWrapper,
|
||||
};
|
||||
|
||||
return {
|
||||
...baseComponents,
|
||||
...components,
|
||||
};
|
||||
}
|
@ -28,7 +28,7 @@ export default function Example() {
|
||||
className="bg-transparent px-4 py-2 text-sm focus-visible:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<DynamicCodeBlock lang={lang} code={code} options={{}} />
|
||||
<DynamicCodeBlock lang={lang} code={code} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { createMDXSource } from '@fumadocs/content-collections';
|
||||
import { allDocs, allMetas } from 'content-collections';
|
||||
import { loader } from 'fumadocs-core/source';
|
||||
import * as LucideIcons from 'lucide-react';
|
||||
import { createElement } from 'react';
|
||||
import { docs } from '../../../.source';
|
||||
import { docsI18nConfig } from './i18n';
|
||||
|
||||
/**
|
||||
* Turn a content source into a unified interface
|
||||
* .source folder is generated by `fumadocs-mdx`
|
||||
*
|
||||
* https://fumadocs.dev/docs/headless/source-api
|
||||
* https://fumadocs.dev/docs/headless/content-collections
|
||||
@ -14,7 +14,7 @@ import { docsI18nConfig } from './i18n';
|
||||
export const source = loader({
|
||||
baseUrl: '/docs',
|
||||
i18n: docsI18nConfig,
|
||||
source: createMDXSource(allDocs, allMetas),
|
||||
source: docs.toFumadocsSource(),
|
||||
icon(iconName) {
|
||||
if (!iconName) {
|
||||
return undefined;
|
||||
|
Loading…
Reference in New Issue
Block a user