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
|
||||||
.content-collections
|
.content-collections
|
||||||
|
|
||||||
|
# fumadocs
|
||||||
|
.source
|
||||||
|
|
||||||
# OpenNext build output
|
# OpenNext build output
|
||||||
.open-next
|
.open-next
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { DEFAULT_LOCALE, LOCALES } from '@/i18n/routing';
|
import { DEFAULT_LOCALE, LOCALES } from '@/i18n/routing';
|
||||||
import { defineCollection, defineConfig } from '@content-collections/core';
|
import { defineCollection, defineConfig } from '@content-collections/core';
|
||||||
import {
|
import { transformMDX } from '@fumadocs/content-collections/configuration';
|
||||||
createDocSchema,
|
|
||||||
createMetaSchema,
|
|
||||||
transformMDX,
|
|
||||||
} from '@fumadocs/content-collections/configuration';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Content Collections documentation
|
* 1. Content Collections documentation
|
||||||
@ -16,25 +12,25 @@ import {
|
|||||||
* 2. Use Content Collections for Fumadocs
|
* 2. Use Content Collections for Fumadocs
|
||||||
* https://fumadocs.dev/docs/headless/content-collections
|
* https://fumadocs.dev/docs/headless/content-collections
|
||||||
*/
|
*/
|
||||||
const docs = defineCollection({
|
// const docs = defineCollection({
|
||||||
name: 'docs',
|
// name: 'docs',
|
||||||
directory: 'content/docs',
|
// directory: 'content/docs',
|
||||||
include: '**/*.mdx',
|
// include: '**/*.mdx',
|
||||||
schema: (z) => ({
|
// schema: (z) => ({
|
||||||
...createDocSchema(z),
|
// ...createDocSchema(z),
|
||||||
preview: z.string().optional(),
|
// preview: z.string().optional(),
|
||||||
index: z.boolean().default(false),
|
// index: z.boolean().default(false),
|
||||||
}),
|
// }),
|
||||||
transform: transformMDX,
|
// transform: transformMDX,
|
||||||
});
|
// });
|
||||||
|
|
||||||
const metas = defineCollection({
|
// const metas = defineCollection({
|
||||||
name: 'meta',
|
// name: 'meta',
|
||||||
directory: 'content/docs',
|
// directory: 'content/docs',
|
||||||
include: '**/meta**.json',
|
// include: '**/meta**.json',
|
||||||
parser: 'json',
|
// parser: 'json',
|
||||||
schema: createMetaSchema,
|
// schema: createMetaSchema,
|
||||||
});
|
// });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blog Author collection
|
* Blog Author collection
|
||||||
@ -324,5 +320,5 @@ function extractLocaleAndBase(fileName: string): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
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 type { NextConfig } from 'next';
|
||||||
import createNextIntlPlugin from 'next-intl/plugin';
|
import createNextIntlPlugin from 'next-intl/plugin';
|
||||||
|
|
||||||
@ -69,8 +69,9 @@ const nextConfig: NextConfig = {
|
|||||||
const withNextIntl = createNextIntlPlugin();
|
const withNextIntl = createNextIntlPlugin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* withContentCollections must be the outermost plugin
|
* https://fumadocs.dev/docs/ui/manual-installation
|
||||||
*
|
* https://fumadocs.dev/docs/mdx/plugin
|
||||||
* https://www.content-collections.dev/docs/quickstart/next
|
|
||||||
*/
|
*/
|
||||||
export default withContentCollections(withNextIntl(nextConfig));
|
const withMDX = createMDX();
|
||||||
|
|
||||||
|
export default withMDX(withNextIntl(nextConfig));
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"dev": "concurrently \"content-collections watch\" \"next dev\"",
|
"dev": "concurrently \"content-collections watch\" \"next dev\"",
|
||||||
"build": "content-collections build && next build",
|
"build": "content-collections build && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
|
"postinstall": "fumadocs-mdx",
|
||||||
"lint": "biome check --write .",
|
"lint": "biome check --write .",
|
||||||
"lint:fix": "biome check --fix --unsafe .",
|
"lint:fix": "biome check --fix --unsafe .",
|
||||||
"format": "biome format --write .",
|
"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 * as Preview from '@/components/docs';
|
||||||
import { CustomMDXContent } from '@/components/shared/custom-mdx-content';
|
|
||||||
import {
|
import {
|
||||||
HoverCard,
|
HoverCard,
|
||||||
HoverCardContent,
|
HoverCardContent,
|
||||||
@ -87,6 +87,8 @@ export default async function DocPage({ params }: DocPageProps) {
|
|||||||
|
|
||||||
const preview = page.data.preview;
|
const preview = page.data.preview;
|
||||||
|
|
||||||
|
const MDX = page.data.body;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DocsPage
|
<DocsPage
|
||||||
toc={page.data.toc}
|
toc={page.data.toc}
|
||||||
@ -102,9 +104,8 @@ export default async function DocPage({ params }: DocPageProps) {
|
|||||||
{preview ? <PreviewRenderer preview={preview} /> : null}
|
{preview ? <PreviewRenderer preview={preview} /> : null}
|
||||||
|
|
||||||
{/* MDX Content */}
|
{/* MDX Content */}
|
||||||
<CustomMDXContent
|
<MDX
|
||||||
code={page.data.body}
|
components={getMDXComponents({
|
||||||
customComponents={{
|
|
||||||
a: ({ href, ...props }: { href?: string; [key: string]: any }) => {
|
a: ({ href, ...props }: { href?: string; [key: string]: any }) => {
|
||||||
const found = source.getPageByHref(href ?? '', {
|
const found = source.getPageByHref(href ?? '', {
|
||||||
dir: page.file.dirname,
|
dir: page.file.dirname,
|
||||||
@ -133,7 +134,7 @@ export default async function DocPage({ params }: DocPageProps) {
|
|||||||
</HoverCard>
|
</HoverCard>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</DocsBody>
|
</DocsBody>
|
||||||
</DocsPage>
|
</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"
|
className="bg-transparent px-4 py-2 text-sm focus-visible:outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<DynamicCodeBlock lang={lang} code={code} options={{}} />
|
<DynamicCodeBlock lang={lang} code={code} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { createMDXSource } from '@fumadocs/content-collections';
|
|
||||||
import { allDocs, allMetas } from 'content-collections';
|
|
||||||
import { loader } from 'fumadocs-core/source';
|
import { loader } from 'fumadocs-core/source';
|
||||||
import * as LucideIcons from 'lucide-react';
|
import * as LucideIcons from 'lucide-react';
|
||||||
import { createElement } from 'react';
|
import { createElement } from 'react';
|
||||||
|
import { docs } from '../../../.source';
|
||||||
import { docsI18nConfig } from './i18n';
|
import { docsI18nConfig } from './i18n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn a content source into a unified interface
|
* 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/source-api
|
||||||
* https://fumadocs.dev/docs/headless/content-collections
|
* https://fumadocs.dev/docs/headless/content-collections
|
||||||
@ -14,7 +14,7 @@ import { docsI18nConfig } from './i18n';
|
|||||||
export const source = loader({
|
export const source = loader({
|
||||||
baseUrl: '/docs',
|
baseUrl: '/docs',
|
||||||
i18n: docsI18nConfig,
|
i18n: docsI18nConfig,
|
||||||
source: createMDXSource(allDocs, allMetas),
|
source: docs.toFumadocsSource(),
|
||||||
icon(iconName) {
|
icon(iconName) {
|
||||||
if (!iconName) {
|
if (!iconName) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
Loading…
Reference in New Issue
Block a user