Zeta: Export remark-toc and remark-structure MDX plugins

This commit is contained in:
SonMooSans
2023-10-20 19:15:11 +08:00
parent df0a56aa36
commit 7a0690b8f5
28 changed files with 120 additions and 94 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'next-docs-zeta': minor
---
Export remark-toc and remark-structure MDX plugins
+2 -2
View File
@@ -7,7 +7,7 @@ import type { NextConfig } from 'next'
import {
rehypeNextDocs,
remarkGfm,
remarkStructurize,
remarkStructure,
remarkToc
} from 'next-docs-zeta/mdx-plugins'
import remarkFrontmatter, {
@@ -43,7 +43,7 @@ const createNextDocs =
remarkGfm,
[remarkFrontmatter, 'yaml' satisfies RemarkFrontmatterOptions],
remarkMdxFrontmatter,
remarkStructurize,
remarkStructure,
remarkToc,
[remarkMdxExport, { values: dataExports }],
...(pluginOptions.options?.remarkPlugins ?? [])
+18 -36
View File
@@ -11,28 +11,28 @@
],
"exports": {
"./sidebar": {
"import": "./dist/sidebar/index.mjs",
"types": "./dist/sidebar/index.d.ts"
"import": "./dist/sidebar.mjs",
"types": "./dist/sidebar.d.ts"
},
"./breadcrumb": {
"import": "./dist/breadcrumb/index.mjs",
"types": "./dist/breadcrumb/index.d.ts"
"import": "./dist/breadcrumb.mjs",
"types": "./dist/breadcrumb.d.ts"
},
"./toc": {
"import": "./dist/toc/index.mjs",
"types": "./dist/toc/index.d.ts"
"import": "./dist/toc.mjs",
"types": "./dist/toc.d.ts"
},
"./search/*": {
"import": "./dist/search/*.mjs",
"types": "./dist/search/*.d.ts"
},
"./server": {
"import": "./dist/server/index.mjs",
"types": "./dist/server/index.d.ts"
"import": "./dist/server.mjs",
"types": "./dist/server.d.ts"
},
"./link": {
"import": "./dist/link/index.mjs",
"types": "./dist/link/index.d.ts"
"import": "./dist/link.mjs",
"types": "./dist/link.d.ts"
},
"./contentlayer": {
"import": "./dist/contentlayer/index.mjs",
@@ -43,12 +43,12 @@
"types": "./dist/contentlayer/configuration.d.ts"
},
"./middleware": {
"import": "./dist/middleware/index.mjs",
"types": "./dist/middleware/index.d.ts"
"import": "./dist/middleware.mjs",
"types": "./dist/middleware.d.ts"
},
"./mdx-plugins": {
"import": "./dist/mdx-plugins/index.mjs",
"types": "./dist/mdx-plugins/index.d.ts"
"import": "./dist/mdx-plugins.mjs",
"types": "./dist/mdx-plugins.d.ts"
},
"./search-algolia/*": {
"import": "./dist/search-algolia/*.mjs",
@@ -57,23 +57,8 @@
},
"typesVersions": {
"*": {
"sidebar": [
"./dist/sidebar/index.d.ts"
],
"breadcrumb": [
"./dist/breadcrumb/index.d.ts"
],
"toc": [
"./dist/toc/index.d.ts"
],
"search/*": [
"./dist/search/*.d.ts"
],
"server": [
"./dist/server/index.d.ts"
],
"link": [
"./dist/link/index.d.ts"
"*": [
"./dist/*.d.ts"
],
"contentlayer": [
"./dist/contentlayer/index.d.ts"
@@ -81,11 +66,8 @@
"contentlayer/configuration": [
"./dist/contentlayer/configuration.d.ts"
],
"mdx-plugins": [
"./dist/mdx-plugins/index.d.ts"
],
"middleware": [
"./dist/middleware/index.d.ts"
"search/*": [
"./dist/search/*.d.ts"
],
"search-algolia/*": [
"./dist/search-algolia/*.d.ts"
@@ -6,7 +6,7 @@ type Context = PagesContext & {
lang?: string
}
type Options = {
export type Options = {
/**
* The root folder to scan files
* @default 'docs'
@@ -11,7 +11,7 @@ import type { Args, ComputedFields, FieldDef } from 'contentlayer/source-files'
import { defineDocumentType } from 'contentlayer/source-files'
import type { Options as ImgSizeOptions } from 'rehype-img-size'
function removeSlash(path: string) {
function removeSlash(path: string): string {
let start = 0,
end = path.length
while (path.charAt(start) == '/') start++
@@ -20,7 +20,7 @@ function removeSlash(path: string) {
return path.slice(start, end)
}
function removePattern(path: string, pattern: string) {
function removePattern(path: string, pattern: string): string {
if (path.endsWith('/index') || path === 'index') {
path = path.slice(0, path.length - 'index'.length)
}
@@ -148,8 +148,8 @@ export function createConfig(options: Partial<Options> = {}): Args {
rehypePlugins: [
rehypeNextDocs,
[
/* eslint-disable */
rehypeImgSize as any,
// @ts-ignore
rehypeImgSize,
{
dir: imgDirPath
} as ImgSizeOptions
@@ -1,7 +1,8 @@
import type { PageTree } from '@/server/types'
import { buildI18nPageTree, buildPageTree } from './build-tree'
import { loadContext, type ContextOptions } from './load-context'
import type { DocsPageBase, MetaPageBase, PagesContext } from './types'
import { createUtils } from './utils'
import { createUtils, type ContentlayerUtils } from './utils'
type Options<L extends string[] | undefined> = Omit<
Partial<ContextOptions>,
@@ -20,10 +21,8 @@ type CreateContentlayer = <
options?: Options<Langs>
) => {
__pageContext: PagesContext
tree: Langs extends string[]
? ReturnType<typeof buildI18nPageTree>
: ReturnType<typeof buildPageTree>
} & ReturnType<typeof createUtils<Docs>>
tree: Langs extends string[] ? Record<Langs[number], PageTree> : PageTree
} & ContentlayerUtils<Docs>
/**
* Create page tree and utilities for Contentlayer
+1 -1
View File
@@ -1,6 +1,6 @@
export * from './load-context'
export * from './build-tree'
export { createUtils } from './utils'
export { createUtils, ContentlayerUtils } from './utils'
export { createContentlayer } from './create-contentlayer'
export type * from './types'
@@ -54,7 +54,7 @@ export function loadContext<
function getI18nPages<Docs extends DocsPageBase>(
docsMap: Map<string, Docs>,
languages: string[]
) {
): Map<string, Docs[]> {
const pages = new Map<string, Docs[]>()
pages.set('', [])
+14 -10
View File
@@ -23,9 +23,7 @@ export function getPageUrl(slug: string[], baseUrl: string, locale?: string) {
return url
}
export function createUtils<Docs extends DocsPageBase>(
context: PagesContext<MetaPageBase, Docs>
): {
export type ContentlayerUtils<Docs extends DocsPageBase> = {
/**
* Get list of pages from language
*
@@ -36,22 +34,28 @@ export function createUtils<Docs extends DocsPageBase>(
/**
* @param language If empty, the default language will be used
*/
getPage: (slugs?: string[], language?: string) => Docs | undefined
getPage: (slugs: string[] | undefined, language?: string) => Docs | undefined
getPageUrl: (
slugs: string | string[] | undefined,
language?: string
) => string
} {
}
export function createUtils<Docs extends DocsPageBase>(
context: PagesContext<MetaPageBase, Docs>
): ContentlayerUtils<Docs> {
return {
getPages: (language = '') => context.pages.get(language),
getPage(slugs, language = '') {
const path = (slugs ?? []).join('/')
getPages(language = '') {
return context.pages.get(language)
},
getPage(slugs = [], language = '') {
const path = slugs.join('/')
return context.pages.get(language)?.find(page => page.slug === path)
},
getPageUrl(slug, language) {
const slugs = typeof slug === 'string' ? slug.split('/') : slug ?? []
getPageUrl(slug = [], language) {
const slugs = typeof slug === 'string' ? slug.split('/') : slug
return context.getUrl(slugs, language)
}
+12
View File
@@ -0,0 +1,12 @@
export {
default as rehypeImgSize,
Options as RehypeImgSizeOptions
} from 'rehype-img-size'
export { default as remarkGfm, Options as RemarkGfmOptions } from 'remark-gfm'
export { rehypeNextDocs } from './mdx-plugins/rehype-next-docs'
export {
remarkDynamicContent,
Options as RemarkDynamicContentOptions
} from './mdx-plugins/remark-dynamic-content'
export * from './mdx-plugins/remark-structure'
export { remarkToc } from './mdx-plugins/remark-toc'
@@ -1,6 +0,0 @@
export { default as rehypeImgSize } from 'rehype-img-size'
export { default as remarkGfm } from 'remark-gfm'
export { rehypeNextDocs } from './rehype-next-docs'
export { remarkDynamicContent } from './remark-dynamic-content'
export * from './remark-structure'
export * from './remark-toc'
@@ -7,7 +7,7 @@ import { visit } from 'unist-util-visit'
const regex = /^\|reference:(.+)\|/
type Options = {
export type Options = {
/** @default process.cwd() */
cwd?: string
/** @default true */
@@ -41,7 +41,7 @@ const textTypes = ['text', 'inlineCode']
/**
* Attach structured data to VFile, you can access via `vfile.data.structuredData`.
*/
export function remarkStructurize({
export function remarkStructure({
types = ['paragraph', 'blockquote', 'heading']
}: Options = {}): Transformer<Root, Root> {
return (node, file) => {
@@ -2,7 +2,7 @@ import type { SortedResult } from '@/search/shared'
import type { Hit, SearchOptions } from '@algolia/client-search'
import type { SearchIndex } from 'algoliasearch/lite'
import { useState } from 'react'
import useSWR from 'swr'
import useSWR, { type SWRResponse } from 'swr'
import type { BaseIndex } from './shared'
export function groupResults(hits: Hit<BaseIndex>[]): SortedResult[] {
@@ -46,7 +46,20 @@ export async function searchDocs(
return groupResults(result.hits)
}
export function useAlgoliaSearch(index: SearchIndex, options?: SearchOptions) {
type UseAlgoliaSearch = {
search: string
setSearch: (v: string) => void
query: SWRResponse<
SortedResult[] | 'empty',
Error,
{ keepPreviousData: true }
>
}
export function useAlgoliaSearch(
index: SearchIndex,
options?: SearchOptions
): UseAlgoliaSearch {
const [search, setSearch] = useState('')
const query = useSWR(
@@ -1,10 +1,15 @@
import { randomUUID } from 'crypto'
import type { DocsPageBase } from '@/contentlayer/types'
import type { StructuredData } from '@/mdx-plugins/remark-structure'
import type { SearchClient, SearchIndex } from 'algoliasearch'
import type { BaseIndex } from './shared'
type DocumentRecord = DocsPageBase & {
type DocumentRecord = {
/**
* The ID of document, must be unique
*/
_id: string
title: string
/**
* URL to the page
*/
@@ -17,12 +22,11 @@ type DocumentRecord = DocsPageBase & {
extra_data?: object
}
type SyncOptions = { document?: string; documents: DocumentRecord[] }
export async function sync(
client: SearchClient,
{
document = 'document',
documents
}: { document?: string; documents: DocumentRecord[] }
{ document = 'document', documents }: SyncOptions
) {
const index = client.initIndex(document)
await setIndexSettings(index)
+15 -3
View File
@@ -1,11 +1,23 @@
import { useEffect, useState } from 'react'
import useSWR from 'swr'
import useSWR, { type SWRResponse } from 'swr'
import type { SortedResult } from './shared'
type UseDocsSearch<Result> = {
search: string
setSearch: (v: string) => void
query: SWRResponse<
Result,
Error,
{
keepPreviousData: true
}
>
}
export function useDocsSearch<Result = SortedResult[]>(
locale?: string,
tag?: string
) {
): UseDocsSearch<Result | 'empty'> {
const [search, setSearch] = useState('')
const debouncedValue = useDebounce(search, 100)
@@ -32,7 +44,7 @@ export function useDocsSearch<Result = SortedResult[]>(
return { search, setSearch, query: searchQuery }
}
function useDebounce<T>(value: T, delayMs: number = 1000) {
function useDebounce<T>(value: T, delayMs: number = 1000): T {
const [debouncedValue, setDebouncedValue] = useState(value)
useEffect(() => {
+3 -3
View File
@@ -43,13 +43,13 @@ type ToI18n<T extends { indexes: unknown }> = Omit<
export function createSearchAPI<T extends 'simple' | 'advanced'>(
type: T,
_options: T extends 'simple' ? SimpleOptions : AdvancedOptions
options: T extends 'simple' ? SimpleOptions : AdvancedOptions
): SearchAPI {
if (type === 'simple') {
return initSearchAPI(_options as SimpleOptions)
return initSearchAPI(options as SimpleOptions)
}
return initSearchAPIAdvanced(_options as AdvancedOptions)
return initSearchAPIAdvanced(options as AdvancedOptions)
}
export function createI18nSearchAPI<T extends 'simple' | 'advanced'>(
+5
View File
@@ -0,0 +1,5 @@
export * from './server/get-toc'
export * from './server/types'
export { getTableOfContentsFromPortableText } from './server/get-toc-sanity'
export * from './server/tree-utils'
export * from './server/git-api'
+1 -1
View File
@@ -1,4 +1,4 @@
import { remarkToc } from '@/mdx-plugins'
import { remarkToc } from '@/mdx-plugins/remark-toc'
import { remark } from 'remark'
import type { TableOfContents } from './types'
-5
View File
@@ -1,5 +0,0 @@
export * from './get-toc'
export * from './types'
export * from './get-toc-sanity'
export * from './tree-utils'
export * from './git-api'
@@ -10,7 +10,7 @@ import {
useRef
} from 'react'
import scrollIntoView from 'scroll-into-view-if-needed'
import { useAnchorObserver } from './use-anchor-observer'
import { useAnchorObserver } from './utils/use-anchor-observer'
const ActiveAnchorContext = createContext<{
activeAnchor: string | undefined
+6 -5
View File
@@ -1,14 +1,15 @@
import { defineConfig } from 'tsup'
import packageJson from './package.json'
import tsconfig from './tsconfig.json'
export default defineConfig({
entry: [
'src/{server,breadcrumb,sidebar,toc,link,contentlayer,middleware,mdx-plugins}/index.{ts,tsx}',
'src/search/{client,server,shared}.ts',
'src/search-algolia/{client,server,shared}.ts',
'src/contentlayer/configuration.ts'
'src/{toc,link,breadcrumb,sidebar}.tsx',
'src/{middleware,server,mdx-plugins}.ts',
'src/{search,search-algolia}/{client,server,shared}.ts',
'src/contentlayer/{index,configuration}.ts'
],
external: ['@algolia/client-search', 'algoliasearch', 'contentlayer', 'next'],
external: [...Object.keys(packageJson.devDependencies)],
format: 'esm',
dts: true,
target: tsconfig.compilerOptions.target as 'es2016'