mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
Zeta & MDX: Support custom build page tree options
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'next-docs-zeta': patch
|
||||
'next-docs-mdx': patch
|
||||
---
|
||||
|
||||
Support custom build page tree options
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PageTree } from 'next-docs-zeta/server'
|
||||
import type { BuildPageTreeOptions, PageTree } from 'next-docs-zeta/server'
|
||||
import { getPageTreeBuilder, type BuilderOptions } from './build-tree'
|
||||
import { createPageUtils, type PageUtils } from './page-utils'
|
||||
import {
|
||||
@@ -16,11 +16,6 @@ type UtilsOptions<Langs extends string[] | undefined> = {
|
||||
*/
|
||||
baseUrl: string
|
||||
|
||||
/**
|
||||
* @deprecated Use `rootDir` instead
|
||||
*/
|
||||
root: string
|
||||
|
||||
/**
|
||||
* Root directory, files outside of the root directory will be ignored
|
||||
*
|
||||
@@ -28,6 +23,8 @@ type UtilsOptions<Langs extends string[] | undefined> = {
|
||||
*/
|
||||
rootDir: string
|
||||
|
||||
pageTreeOptions: BuildPageTreeOptions
|
||||
|
||||
slugs: ResolveOptions['slugs']
|
||||
validate: ResolveOptions['validate']
|
||||
} & BuilderOptions
|
||||
@@ -50,6 +47,7 @@ function fromMap<Langs extends string[] | undefined = undefined>(
|
||||
slugs,
|
||||
getUrl,
|
||||
resolveIcon,
|
||||
pageTreeOptions = { root: rootDir },
|
||||
languages,
|
||||
validate
|
||||
}: Partial<UtilsOptions<Langs>> = {}
|
||||
@@ -73,9 +71,12 @@ function fromMap<Langs extends string[] | undefined = undefined>(
|
||||
...resolved,
|
||||
...pageUtils,
|
||||
tree: (languages == null
|
||||
? builder.build({ root: rootDir })
|
||||
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
builder.buildI18n({ languages, root: rootDir })) as any
|
||||
? builder.build(pageTreeOptions)
|
||||
: builder.buildI18n({
|
||||
...pageTreeOptions,
|
||||
languages
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
})) as any
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,7 @@ export function createPageUtils(
|
||||
}
|
||||
|
||||
/**
|
||||
* @example
|
||||
* ```
|
||||
* ['a','b','c'] // '/a/b/c'
|
||||
* ['/a'] // '/a'
|
||||
* ```
|
||||
* Join paths with leading slash
|
||||
*/
|
||||
function joinPaths(...paths: (string | null)[]): string {
|
||||
const relative = paths
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { BuildPageTreeOptions } from '@/server'
|
||||
import type { PageTree } from '@/server/types'
|
||||
import { loadContext, type ContextOptions } from './load-context'
|
||||
import type { DocsPageBase, MetaPageBase, PagesContext } from './types'
|
||||
@@ -5,6 +6,10 @@ import { createUtils, type ContentlayerUtils } from './utils'
|
||||
|
||||
type Options<L extends string[] | undefined> = Partial<
|
||||
Omit<ContextOptions, 'languages'> & {
|
||||
/**
|
||||
* @default { root: 'docs' }
|
||||
*/
|
||||
pageTreeOptions: BuildPageTreeOptions
|
||||
languages: L
|
||||
}
|
||||
>
|
||||
@@ -31,13 +36,17 @@ export const createContentlayer: CreateContentlayer = (
|
||||
options = {}
|
||||
) => {
|
||||
const ctx = loadContext(metaPages, docsPages, options)
|
||||
const pageTreeOptions = options.pageTreeOptions ?? { root: 'docs' }
|
||||
|
||||
return {
|
||||
__pageContext: ctx,
|
||||
tree: (options.languages != null
|
||||
? ctx.builder.buildI18n({ languages: options.languages })
|
||||
? ctx.builder.buildI18n({
|
||||
...pageTreeOptions,
|
||||
languages: options.languages
|
||||
})
|
||||
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
ctx.builder.build()) as any,
|
||||
ctx.builder.build(pageTreeOptions)) as any,
|
||||
...createUtils(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,7 @@ export function loadContext<Docs extends DocsPageBase>(
|
||||
icon: meta.icon,
|
||||
title: meta.title
|
||||
})),
|
||||
resolveIcon(icon) {
|
||||
if (icon == null) return
|
||||
return resolveIcon(icon)
|
||||
}
|
||||
resolveIcon
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -53,7 +53,7 @@ type PageTreeBuilderContext = {
|
||||
export type BuildPageTreeOptions = {
|
||||
/**
|
||||
* The root folder to scan files
|
||||
* @default 'docs'
|
||||
* @default ''
|
||||
*/
|
||||
root: string
|
||||
}
|
||||
@@ -87,7 +87,6 @@ function buildMeta(
|
||||
meta: AbstractMeta,
|
||||
ctx: PageTreeBuilderContext
|
||||
): FolderNode {
|
||||
const segments = meta.file.dirname.split('/')
|
||||
let index: FileNode | undefined = undefined
|
||||
const filtered = new Set<string>()
|
||||
|
||||
@@ -109,7 +108,7 @@ function buildMeta(
|
||||
item = extract_result[1]
|
||||
}
|
||||
|
||||
const path = meta.file.dirname + '/' + item
|
||||
const path = joinPaths([meta.file.dirname, item])
|
||||
const page = ctx.getPageByPath(path)
|
||||
|
||||
if (page != null) {
|
||||
@@ -151,14 +150,14 @@ function buildMeta(
|
||||
})
|
||||
|
||||
if (index == null) {
|
||||
const page = ctx.getPageByPath(meta.file.dirname + '/index')
|
||||
const page = ctx.getPageByPath(joinPaths([meta.file.dirname, 'index']))
|
||||
|
||||
if (page != null) index = buildFileNode(page, ctx)
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'folder',
|
||||
name: meta.title ?? index?.name ?? pathToName(segments),
|
||||
name: meta.title ?? index?.name ?? pathToName(splitPath(meta.file.dirname)),
|
||||
icon: ctx.resolveIcon(meta.icon),
|
||||
index,
|
||||
children
|
||||
@@ -193,15 +192,15 @@ function getFolderNodes(
|
||||
children.push(node)
|
||||
}
|
||||
|
||||
const segments = path.split('/')
|
||||
const segments = splitPath(path)
|
||||
const folders = new Set<string>(
|
||||
ctx.basePages.flatMap(page => {
|
||||
const dirnameSegments = page.file.dirname.split('/')
|
||||
const dirnameSegments = splitPath(page.file.dirname)
|
||||
|
||||
if (path.length === 0 && path !== page.file.dirname)
|
||||
return dirnameSegments[0]
|
||||
if (page.file.dirname.startsWith(path + '/'))
|
||||
return path + '/' + dirnameSegments[segments.length]
|
||||
return joinPaths([path, dirnameSegments[segments.length]])
|
||||
|
||||
return []
|
||||
})
|
||||
@@ -241,8 +240,9 @@ function buildFolderNode(
|
||||
keepIndex: boolean = false
|
||||
): FolderNode {
|
||||
let meta: AbstractMeta | undefined
|
||||
if (ctx.lang) meta = ctx.getMetaByPath(path + `/meta-${ctx.lang}`)
|
||||
meta ??= ctx.getMetaByPath(path + '/meta')
|
||||
|
||||
if (ctx.lang) meta = ctx.getMetaByPath(joinPaths([path, `meta-${ctx.lang}`]))
|
||||
meta ??= ctx.getMetaByPath(joinPaths([path, 'meta']))
|
||||
|
||||
if (meta != null) {
|
||||
return buildMeta(meta, ctx)
|
||||
@@ -252,7 +252,7 @@ function buildFolderNode(
|
||||
|
||||
return {
|
||||
type: 'folder',
|
||||
name: index?.name ?? pathToName(path.split('/')),
|
||||
name: index?.name ?? pathToName(splitPath(path)),
|
||||
index,
|
||||
children
|
||||
}
|
||||
@@ -296,10 +296,10 @@ export function createPageTreeBuilder({
|
||||
}
|
||||
|
||||
return {
|
||||
build({ root = 'docs' } = {}) {
|
||||
build({ root = '' } = {}) {
|
||||
return build(root, context)
|
||||
},
|
||||
buildI18n({ root = 'docs', languages = [] } = {}) {
|
||||
buildI18n({ root = '', languages = [] } = {}) {
|
||||
const entries = languages.map(lang => {
|
||||
const tree = build(root, {
|
||||
...context,
|
||||
@@ -318,3 +318,41 @@ function pathToName(path: string[]): string {
|
||||
const name = path[path.length - 1] ?? 'docs'
|
||||
return name.slice(0, 1).toUpperCase() + name.slice(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Split path into segments, trailing/leading slashes are removed
|
||||
*/
|
||||
export function splitPath(path: string): string[] {
|
||||
return path.split('/').filter(p => p.length > 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert paths to an array, slashes within the path will be ignored
|
||||
* @param paths
|
||||
* @param slash Add a trailing/leading slash to path
|
||||
* @example
|
||||
* ```
|
||||
* ['a','b','c'] // 'a/b/c'
|
||||
* ['/a'] // 'a'
|
||||
* ['a', '/b'] // 'a/b'
|
||||
* ['a', 'b/c'] // 'a/b/c'
|
||||
* ```
|
||||
*/
|
||||
export function joinPaths(
|
||||
paths: string[],
|
||||
slash: 'leading' | 'trailing' | 'none' = 'none'
|
||||
): string {
|
||||
const joined = paths
|
||||
// avoid slashes in path and filter empty
|
||||
.flatMap(path => splitPath(path))
|
||||
.join('/')
|
||||
|
||||
switch (slash) {
|
||||
case 'leading':
|
||||
return '/' + joined
|
||||
case 'trailing':
|
||||
return joined + '/'
|
||||
default:
|
||||
return joined
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user