mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
MDX: Support intelligent schema types
This commit is contained in:
@@ -10,11 +10,11 @@ You can now generate slugs automatically depending on the root directory you hav
|
||||
|
||||
```ts
|
||||
const utils = fromMap(map, {
|
||||
rootDir: 'ui',
|
||||
validate: {
|
||||
frontmatter: frontmatterSchema
|
||||
}
|
||||
})
|
||||
rootDir: 'ui',
|
||||
schema: {
|
||||
frontmatter: frontmatterSchema
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The configuration above will generate `/hello` slugs for a file named `/content/ui/hello.mdx`, while the previous one generates `/ui/hello`.
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
'next-docs-mdx': major
|
||||
---
|
||||
|
||||
**Support intelligent schema types**
|
||||
|
||||
The `validate` options is now renamed to `schema`.
|
||||
|
||||
```ts
|
||||
import { defaultSchemas, fromMap } from 'next-docs-mdx/map';
|
||||
|
||||
const utils = fromMap(map, {
|
||||
rootDir: 'docs/ui',
|
||||
baseUrl: '/docs/ui',
|
||||
schema: {
|
||||
frontmatter: defaultSchemas.frontmatter.extend({
|
||||
preview: z.string().optional(),
|
||||
}),
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
The `frontmatter` field on pages should be automatically inferred to your Zod schema type.
|
||||
@@ -7,5 +7,6 @@
|
||||
"access": "restricted",
|
||||
"baseBranch": "dev",
|
||||
"updateInternalDependencies": "patch",
|
||||
"privatePackages": { "version": false },
|
||||
"ignore": ["simple-app", "docs", "advanced-app", "simple-app-mdx"]
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { resolve } from 'node:url';
|
||||
import { ExternalLinkIcon } from 'lucide-react';
|
||||
import type { Metadata } from 'next';
|
||||
import type { Utils } from 'next-docs-mdx/map';
|
||||
import type { Page } from 'next-docs-mdx/types';
|
||||
import { Card, Cards, MDXContent } from 'next-docs-ui/mdx';
|
||||
import { DocsPage } from 'next-docs-ui/page';
|
||||
import { getGithubLastEdit } from 'next-docs-zeta/server';
|
||||
import { notFound } from 'next/navigation';
|
||||
import type { DocsUtils } from '@/utils/source';
|
||||
import { getUtils, tabs } from '@/utils/source';
|
||||
import { createMetadata } from '@/utils/metadata';
|
||||
import Preview from '@/components/preview';
|
||||
@@ -60,7 +60,7 @@ export default async function Page({
|
||||
>
|
||||
<MDXContent>
|
||||
<div className="not-prose mb-12">
|
||||
<h1 className="mb-4 text-3xl font-semibold text-foreground sm:text-4xl">
|
||||
<h1 className="mb-4 text-3xl font-bold text-foreground sm:text-4xl">
|
||||
{page.matter.title}
|
||||
</h1>
|
||||
<p className="text-lg text-muted-foreground">
|
||||
@@ -78,7 +78,7 @@ export default async function Page({
|
||||
);
|
||||
}
|
||||
|
||||
function Category({ page, tab }: { page: Page; tab: Utils }): JSX.Element {
|
||||
function Category({ page, tab }: { page: Page; tab: DocsUtils }): JSX.Element {
|
||||
const filtered = tab.pages.filter(
|
||||
(docs) =>
|
||||
docs.file.dirname === page.file.dirname && docs.file.name !== 'index',
|
||||
|
||||
+23
-17
@@ -1,55 +1,61 @@
|
||||
import { map } from '@/_map';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { defaultValidators, fromMap, type Utils } from 'next-docs-mdx/map';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import type { Utils } from 'next-docs-mdx/map';
|
||||
import { defaultSchemas, fromMap } from 'next-docs-mdx/map';
|
||||
import type { StructuredData } from 'next-docs-zeta/mdx-plugins';
|
||||
import { PHASE_PRODUCTION_BUILD } from 'next/constants';
|
||||
import path from 'path';
|
||||
import { z } from 'zod';
|
||||
import type { DefaultMetaData } from 'next-docs-mdx/types';
|
||||
import { map } from '@/_map';
|
||||
|
||||
const frontmatterSchema = defaultValidators.frontmatter.extend({
|
||||
const frontmatterSchema = defaultSchemas.frontmatter.extend({
|
||||
preview: z.string().optional(),
|
||||
index: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export const tabs: Record<string, Utils> = {
|
||||
export type DocsUtils = Utils<{
|
||||
languages: undefined;
|
||||
schema: {
|
||||
frontmatter: z.infer<typeof frontmatterSchema>;
|
||||
meta: DefaultMetaData;
|
||||
};
|
||||
}>;
|
||||
|
||||
export const tabs: Record<string, DocsUtils> = {
|
||||
ui: fromMap(map, {
|
||||
rootDir: 'docs/ui',
|
||||
baseUrl: '/docs/ui',
|
||||
validate: {
|
||||
schema: {
|
||||
frontmatter: frontmatterSchema,
|
||||
},
|
||||
}),
|
||||
headless: fromMap(map, {
|
||||
rootDir: 'docs/headless',
|
||||
baseUrl: '/docs/headless',
|
||||
validate: {
|
||||
schema: {
|
||||
frontmatter: frontmatterSchema,
|
||||
},
|
||||
}),
|
||||
mdx: fromMap(map, {
|
||||
rootDir: 'docs/mdx',
|
||||
baseUrl: '/docs/mdx',
|
||||
validate: {
|
||||
schema: {
|
||||
frontmatter: frontmatterSchema,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export function getUtils(mode: 'ui' | 'headless' | 'mdx' | string): Utils {
|
||||
return tabs[mode] ?? tabs['headless'];
|
||||
export function getUtils(mode: string): DocsUtils {
|
||||
return mode in tabs ? tabs[mode] : tabs.headless;
|
||||
}
|
||||
|
||||
declare module 'next-docs-mdx/types' {
|
||||
interface Frontmatter extends z.infer<typeof frontmatterSchema> {}
|
||||
}
|
||||
|
||||
export type Index = {
|
||||
export interface Index {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
url: string;
|
||||
structuredData: StructuredData;
|
||||
};
|
||||
}
|
||||
|
||||
// Access and export MDX pages data to json file
|
||||
// So that we can update search indexes after the build
|
||||
|
||||
@@ -4,13 +4,14 @@ import {
|
||||
} from 'next-docs-zeta/server';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { ResolvedFiles } from './resolve-files';
|
||||
import type { DefaultFrontmatter, DefaultMetaData } from './types';
|
||||
|
||||
export interface BuilderOptions {
|
||||
resolveIcon?: (icon: string) => ReactElement | undefined;
|
||||
}
|
||||
|
||||
export function getPageTreeBuilder(
|
||||
{ metas, pages }: ResolvedFiles,
|
||||
{ metas, pages }: ResolvedFiles<DefaultFrontmatter, DefaultMetaData>,
|
||||
{ resolveIcon = () => undefined }: BuilderOptions,
|
||||
): PageTreeBuilder {
|
||||
return createPageTreeBuilder({
|
||||
|
||||
@@ -86,6 +86,7 @@ const createNextDocs =
|
||||
const valueToExport = [
|
||||
'structuredData',
|
||||
'toc',
|
||||
'frontmatter',
|
||||
...(mdxOptions.valueToExport ?? []),
|
||||
];
|
||||
const _mapPath = path.resolve(cwd, rootMapPath);
|
||||
|
||||
@@ -18,6 +18,11 @@ export interface NextDocsBuildInfo {
|
||||
|
||||
const cache = new Map<string, Processor>();
|
||||
|
||||
/**
|
||||
* Load MDX/markdown files
|
||||
*
|
||||
* it supports frontmatter by parsing and injecting the data in `vfile.data.frontmatter`
|
||||
*/
|
||||
export default function loader(
|
||||
this: LoaderContext<Options>,
|
||||
source: string,
|
||||
@@ -27,7 +32,7 @@ export default function loader(
|
||||
const context = this.context;
|
||||
const filePath = this.resourcePath;
|
||||
const options = this.getOptions();
|
||||
const { content, data } = grayMatter(source);
|
||||
const { content, data: frontmatter } = grayMatter(source);
|
||||
const config = {
|
||||
development: this.mode === 'development',
|
||||
...options,
|
||||
@@ -41,25 +46,29 @@ export default function loader(
|
||||
cache.set(format, processor);
|
||||
}
|
||||
|
||||
processor.process({ value: content, path: filePath }).then(
|
||||
(file) => {
|
||||
const result = String(file.value);
|
||||
const info = this._module?.buildInfo as NextDocsBuildInfo;
|
||||
processor
|
||||
.process({
|
||||
value: content,
|
||||
path: filePath,
|
||||
data: {
|
||||
frontmatter,
|
||||
},
|
||||
})
|
||||
.then(
|
||||
(file) => {
|
||||
const info = this._module?.buildInfo as NextDocsBuildInfo;
|
||||
|
||||
info.__next_docs = {
|
||||
path: this.resourcePath,
|
||||
data: file.data,
|
||||
};
|
||||
info.__next_docs = {
|
||||
path: filePath,
|
||||
data: file.data,
|
||||
};
|
||||
|
||||
const final = `export const frontmatter = ${JSON.stringify(
|
||||
data,
|
||||
)};\n${result}`;
|
||||
callback(undefined, final, file.map || undefined);
|
||||
},
|
||||
(error: Error) => {
|
||||
const fpath = path.relative(context, filePath);
|
||||
error.message = `${fpath}:${error.name}: ${error.message}`;
|
||||
callback(error);
|
||||
},
|
||||
);
|
||||
callback(undefined, String(file.value), file.map || undefined);
|
||||
},
|
||||
(error: Error) => {
|
||||
const fpath = path.relative(context, filePath);
|
||||
error.message = `${fpath}:${error.name}: ${error.message}`;
|
||||
callback(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+74
-26
@@ -3,40 +3,85 @@ import {
|
||||
type BuildPageTreeOptions,
|
||||
type PageTree,
|
||||
} from 'next-docs-zeta/server';
|
||||
import type { AnyZodObject, z } from 'zod';
|
||||
import { getPageTreeBuilder, type BuilderOptions } from './build-tree';
|
||||
import { createPageUtils, type PageUtils } from './page-utils';
|
||||
import {
|
||||
defaultValidators,
|
||||
resolveFiles,
|
||||
type ResolvedFiles,
|
||||
type SchemaOptions,
|
||||
type ResolveOptions,
|
||||
} from './resolve-files';
|
||||
import type { Meta, Page } from './types';
|
||||
import type { DefaultFrontmatter, DefaultMetaData, Meta, Page } from './types';
|
||||
import { defaultSchemas } from './validate/schema';
|
||||
|
||||
type UtilsOptions<Langs extends string[] | undefined> = {
|
||||
languages: Langs;
|
||||
interface UtilsOptions extends BuilderOptions {
|
||||
languages: string[] | undefined;
|
||||
|
||||
/**
|
||||
* @defaultValue `'/'`
|
||||
*/
|
||||
baseUrl: string;
|
||||
|
||||
schema: Partial<SchemaOptions>;
|
||||
|
||||
getUrl: ResolveOptions['getUrl'];
|
||||
getSlugs: ResolveOptions['getSlugs'];
|
||||
rootDir: ResolveOptions['rootDir'];
|
||||
pageTreeOptions: BuildPageTreeOptions;
|
||||
} & BuilderOptions &
|
||||
Pick<ResolveOptions, 'getSlugs' | 'getUrl' | 'validate' | 'rootDir'>;
|
||||
}
|
||||
|
||||
export type Utils = PageUtils & {
|
||||
tree: PageTree;
|
||||
pages: Page[];
|
||||
metas: Meta[];
|
||||
interface RootConfig {
|
||||
languages: string[] | undefined;
|
||||
schema: {
|
||||
frontmatter: unknown;
|
||||
meta: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export type Utils<TTypes extends RootConfig> = PageUtils<
|
||||
TTypes['schema']['frontmatter']
|
||||
> & {
|
||||
tree: TTypes['languages'] extends string[]
|
||||
? Record<string, PageTree>
|
||||
: PageTree;
|
||||
pages: Page<TTypes['schema']['frontmatter']>[];
|
||||
metas: Meta<TTypes['schema']['meta']>[];
|
||||
};
|
||||
|
||||
type I18nUtils = Omit<Utils, 'tree'> & {
|
||||
tree: Record<string, PageTree>;
|
||||
};
|
||||
type GetSchemaType<Schema, DefaultValue> = Schema extends AnyZodObject
|
||||
? z.infer<Schema>
|
||||
: DefaultValue;
|
||||
|
||||
function fromMap<Langs extends string[] | undefined = undefined>(
|
||||
/**
|
||||
* Get accurate options type from partial options
|
||||
*/
|
||||
interface TransformPartialOptions<TOptions extends Partial<UtilsOptions>> {
|
||||
languages: TOptions['languages'] extends string[] ? string[] : undefined;
|
||||
schema: TOptions['schema'] extends Partial<SchemaOptions>
|
||||
? {
|
||||
frontmatter: GetSchemaType<
|
||||
TOptions['schema']['frontmatter'],
|
||||
DefaultFrontmatter
|
||||
>;
|
||||
meta: GetSchemaType<TOptions['schema']['meta'], DefaultMetaData>;
|
||||
}
|
||||
: {
|
||||
frontmatter: DefaultFrontmatter;
|
||||
meta: DefaultMetaData;
|
||||
};
|
||||
}
|
||||
|
||||
function fromMap<TOptions extends Partial<UtilsOptions>>(
|
||||
map: Record<string, unknown>,
|
||||
{
|
||||
options?: TOptions,
|
||||
): Utils<TransformPartialOptions<TOptions>> {
|
||||
type $Options = TransformPartialOptions<TOptions>;
|
||||
type $Frontmatter = $Options['schema']['frontmatter'];
|
||||
type $MetaData = $Options['schema']['meta'];
|
||||
type $Utils = Utils<$Options>;
|
||||
|
||||
const {
|
||||
baseUrl = '/',
|
||||
rootDir = '',
|
||||
getSlugs,
|
||||
@@ -44,22 +89,25 @@ function fromMap<Langs extends string[] | undefined = undefined>(
|
||||
resolveIcon,
|
||||
pageTreeOptions = { root: '' },
|
||||
languages,
|
||||
validate,
|
||||
}: Partial<UtilsOptions<Langs>> = {},
|
||||
): Langs extends string[] ? I18nUtils : Utils {
|
||||
const resolved = resolveFiles({
|
||||
schema,
|
||||
} = options ?? {};
|
||||
|
||||
const resolved = resolveFiles<$Frontmatter, $MetaData>({
|
||||
map,
|
||||
rootDir,
|
||||
getSlugs,
|
||||
getUrl,
|
||||
validate,
|
||||
schema,
|
||||
});
|
||||
|
||||
const pageUtils = createPageUtils(resolved, languages ?? []);
|
||||
|
||||
const builder = getPageTreeBuilder(resolved, {
|
||||
resolveIcon,
|
||||
});
|
||||
const builder = getPageTreeBuilder(
|
||||
resolved as ResolvedFiles<DefaultFrontmatter, DefaultMetaData>,
|
||||
{
|
||||
resolveIcon,
|
||||
},
|
||||
);
|
||||
|
||||
const tree =
|
||||
languages === undefined
|
||||
@@ -71,9 +119,9 @@ function fromMap<Langs extends string[] | undefined = undefined>(
|
||||
|
||||
return {
|
||||
...resolved,
|
||||
tree: tree as $Utils['tree'],
|
||||
...pageUtils,
|
||||
tree,
|
||||
} as Langs extends string[] ? I18nUtils : Utils;
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
@@ -81,5 +129,5 @@ export {
|
||||
resolveFiles,
|
||||
createPageUtils,
|
||||
getPageTreeBuilder,
|
||||
defaultValidators,
|
||||
defaultSchemas,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { valueToEstree } from 'estree-util-value-to-estree';
|
||||
|
||||
/**
|
||||
* MDX.js first converts javascript (with esm support) into mdast nodes with remark-mdx, then handle the other remark plugins
|
||||
*
|
||||
* Therefore, if we want to inject an export, we must convert the object into AST, then add the mdast node
|
||||
*/
|
||||
export function getMdastExport(name: string, value: unknown): object {
|
||||
return {
|
||||
type: 'mdxjsEsm',
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import type { ResolvedFiles } from './resolve-files';
|
||||
import type { Page } from './types';
|
||||
|
||||
export interface PageUtils {
|
||||
getPages: (locale?: string) => Page[];
|
||||
getPage: (slugs: string[] | undefined, locale?: string) => Page | null;
|
||||
export interface PageUtils<Frontmatter> {
|
||||
getPages: (locale?: string) => Page<Frontmatter>[];
|
||||
getPage: (
|
||||
slugs: string[] | undefined,
|
||||
locale?: string,
|
||||
) => Page<Frontmatter> | null;
|
||||
}
|
||||
|
||||
export function createPageUtils(
|
||||
{ pages }: ResolvedFiles,
|
||||
export function createPageUtils<Frontmatter>(
|
||||
{ pages }: ResolvedFiles<Frontmatter, unknown>,
|
||||
languages: string[],
|
||||
): PageUtils {
|
||||
const pageMap = new Map<string, Page>();
|
||||
): PageUtils<Frontmatter> {
|
||||
type $Page = Page<Frontmatter>;
|
||||
const pageMap = new Map<string, $Page>();
|
||||
|
||||
for (const page of pages) {
|
||||
pageMap.set(page.file.flattenedPath, page);
|
||||
}
|
||||
|
||||
const i18nMap = new Map<string, Page[]>();
|
||||
const i18nMap = new Map<string, $Page[]>();
|
||||
|
||||
i18nMap.set('', []);
|
||||
|
||||
@@ -41,25 +45,17 @@ export function createPageUtils(
|
||||
return i18nMap.get(locale) ?? [];
|
||||
},
|
||||
getPage(slugs, locale) {
|
||||
return getPage(pages, slugs, locale);
|
||||
const path = (slugs ?? []).join('/');
|
||||
let def: $Page | null = null;
|
||||
|
||||
for (const page of pages) {
|
||||
if (page.slugs.join('/') === path) {
|
||||
if (!page.file.locale) def = page;
|
||||
if (page.file.locale === locale) return page;
|
||||
}
|
||||
}
|
||||
|
||||
return def;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getPage(
|
||||
pages: Page[],
|
||||
slugs: string[] | undefined = [],
|
||||
locale?: string,
|
||||
): Page | null {
|
||||
const path = slugs.join('/');
|
||||
let def: Page | null = null;
|
||||
|
||||
for (const page of pages) {
|
||||
if (page.slugs.join('/') === path) {
|
||||
if (!page.file.locale) def = page;
|
||||
if (page.file.locale === locale) return page;
|
||||
}
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
@@ -2,19 +2,14 @@ import path from 'node:path';
|
||||
import { joinPaths, splitPath } from 'next-docs-zeta/server';
|
||||
import type { AnyZodObject } from 'zod';
|
||||
import type { FileInfo, MDXExport, Meta, Page } from './types';
|
||||
import {
|
||||
frontmatterSchema,
|
||||
metaSchema,
|
||||
type Frontmatter,
|
||||
type MetaExport,
|
||||
} from './validate/schema';
|
||||
import { defaultSchemas } from './validate/schema';
|
||||
|
||||
const pageTypes = ['.md', '.mdx'];
|
||||
const metaTypes = ['.json'];
|
||||
|
||||
export interface ResolvedFiles {
|
||||
pages: Page[];
|
||||
metas: Meta[];
|
||||
export interface ResolvedFiles<Frontmatter, MetaData> {
|
||||
pages: Page<Frontmatter>[];
|
||||
metas: Meta<MetaData>[];
|
||||
}
|
||||
|
||||
export interface ResolveOptions {
|
||||
@@ -33,9 +28,9 @@ export interface ResolveOptions {
|
||||
getSlugs?: (file: FileInfo) => string[];
|
||||
|
||||
/**
|
||||
* Check frontmatter/meta objects, transform allowed
|
||||
* Zod schema for frontmatter/meta objects, transform allowed
|
||||
*/
|
||||
validate?: ValidateOptions;
|
||||
schema?: Partial<SchemaOptions>;
|
||||
|
||||
/**
|
||||
* Get url from slugs and locale, override the default getUrl function
|
||||
@@ -43,15 +38,10 @@ export interface ResolveOptions {
|
||||
getUrl: (slugs: string[], locale?: string) => string;
|
||||
}
|
||||
|
||||
type ValidateOptions = Partial<{
|
||||
export interface SchemaOptions {
|
||||
frontmatter: AnyZodObject;
|
||||
meta: AnyZodObject;
|
||||
}>;
|
||||
|
||||
export const defaultValidators = {
|
||||
frontmatter: frontmatterSchema,
|
||||
meta: metaSchema,
|
||||
};
|
||||
}
|
||||
|
||||
function parsePath(p: string, root = ''): FileInfo | false {
|
||||
if (!p.startsWith(root)) return false;
|
||||
@@ -90,28 +80,27 @@ function parse<T>(schema: AnyZodObject, object: unknown, errorName: string): T {
|
||||
return result.data as T;
|
||||
}
|
||||
|
||||
export function resolveFiles({
|
||||
export function resolveFiles<Frontmatter, MetaData>({
|
||||
map,
|
||||
getSlugs = pathToSlugs,
|
||||
getUrl,
|
||||
rootDir = '',
|
||||
validate = defaultValidators,
|
||||
}: ResolveOptions): ResolvedFiles {
|
||||
const metas: Meta[] = [];
|
||||
const pages: Page[] = [];
|
||||
schema = defaultSchemas,
|
||||
}: ResolveOptions): ResolvedFiles<Frontmatter, MetaData> {
|
||||
type $Meta = Meta<MetaData>;
|
||||
type $Page = Page<Frontmatter>;
|
||||
|
||||
const metas: $Meta[] = [];
|
||||
const pages: $Page[] = [];
|
||||
|
||||
for (const [key, value] of Object.entries(map)) {
|
||||
const file = parsePath(key, rootDir);
|
||||
if (file === false) continue;
|
||||
|
||||
if (metaTypes.includes(file.type)) {
|
||||
const meta: Meta = {
|
||||
const meta: $Meta = {
|
||||
file,
|
||||
data: parse<MetaExport>(
|
||||
validate.meta ?? defaultValidators.meta,
|
||||
value,
|
||||
file.path,
|
||||
),
|
||||
data: parse(schema.meta ?? defaultSchemas.meta, value, file.path),
|
||||
};
|
||||
|
||||
metas.push(meta);
|
||||
@@ -120,15 +109,15 @@ export function resolveFiles({
|
||||
}
|
||||
|
||||
if (pageTypes.includes(file.type)) {
|
||||
const data = value as MDXExport;
|
||||
const data = value as MDXExport<Frontmatter>;
|
||||
const slugs = getSlugs(file);
|
||||
|
||||
const page: Page = {
|
||||
const page: $Page = {
|
||||
file,
|
||||
slugs,
|
||||
url: getUrl(slugs, file.locale),
|
||||
matter: parse<Frontmatter>(
|
||||
validate.frontmatter ?? defaultValidators.frontmatter,
|
||||
matter: parse(
|
||||
schema.frontmatter ?? defaultSchemas.frontmatter,
|
||||
data.frontmatter,
|
||||
file.path,
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { MDXProps } from 'mdx/types';
|
||||
import type { StructuredData } from 'next-docs-zeta/mdx-plugins';
|
||||
import type { TableOfContents } from 'next-docs-zeta/server';
|
||||
import type { z } from 'zod';
|
||||
import type * as Default from './validate/schema';
|
||||
|
||||
export interface FileInfo {
|
||||
@@ -47,26 +48,26 @@ export interface FileInfo {
|
||||
/**
|
||||
* Defalt MDX properties, feel free to extend
|
||||
*/
|
||||
export interface MDXExport {
|
||||
export interface MDXExport<Frontmatter = unknown> {
|
||||
default: (props: MDXProps) => JSX.Element;
|
||||
frontmatter: Frontmatter;
|
||||
toc: TableOfContents;
|
||||
structuredData: StructuredData;
|
||||
}
|
||||
|
||||
export type Frontmatter = Default.Frontmatter;
|
||||
export type DefaultFrontmatter = z.infer<typeof Default.frontmatterSchema>;
|
||||
|
||||
export type JsonExport = Default.MetaExport;
|
||||
export type DefaultMetaData = z.infer<typeof Default.metaSchema>;
|
||||
|
||||
export interface Meta {
|
||||
export interface Meta<Data = unknown> {
|
||||
file: FileInfo;
|
||||
data: JsonExport;
|
||||
data: Data;
|
||||
}
|
||||
|
||||
export interface Page {
|
||||
export interface Page<Frontmatter = unknown> {
|
||||
file: FileInfo;
|
||||
url: string;
|
||||
slugs: string[];
|
||||
data: MDXExport;
|
||||
data: MDXExport<Frontmatter>;
|
||||
matter: Frontmatter;
|
||||
}
|
||||
|
||||
@@ -12,5 +12,7 @@ export const frontmatterSchema = z.object({
|
||||
icon: z.string().optional(),
|
||||
});
|
||||
|
||||
export type MetaExport = z.infer<typeof metaSchema>;
|
||||
export type Frontmatter = z.infer<typeof frontmatterSchema>;
|
||||
export const defaultSchemas = {
|
||||
frontmatter: frontmatterSchema,
|
||||
meta: metaSchema,
|
||||
};
|
||||
|
||||
@@ -91,14 +91,11 @@ export const docsUi = plugin.withOptions<NextDocsUIOptions>(
|
||||
'& [data-line]': {
|
||||
'padding-left': `theme('spacing.4')`,
|
||||
'padding-right': `theme('spacing.4')`,
|
||||
'border-left-width': `theme('borderWidth.2')`,
|
||||
'border-color': 'transparent',
|
||||
'& span': {
|
||||
color: 'var(--shiki-light)',
|
||||
},
|
||||
},
|
||||
'& [data-highlighted-line]': {
|
||||
'border-color': `theme('colors.primary.DEFAULT')`,
|
||||
'background-color': `theme('colors.primary.DEFAULT / 10%')`,
|
||||
},
|
||||
'& [data-highlighted-chars]': {
|
||||
|
||||
Reference in New Issue
Block a user