From c3370be64dfce2d165243e39698743289ab0db04 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 23 Feb 2022 22:12:04 +0800 Subject: [PATCH] refactor: make MDX export a flat TOC list instead of tree (#6729) --- .../__snapshots__/index.test.ts.snap | 32 +-- .../src/remark/toc/__tests__/index.test.ts | 58 ++---- .../src/remark/toc/__tests__/search.test.ts | 182 ------------------ .../src/remark/toc/index.ts | 27 ++- .../src/remark/toc/search.ts | 80 -------- .../src/theme/TOCItems/index.tsx | 14 +- packages/docusaurus-theme-common/src/index.ts | 6 +- .../src/utils/__tests__/tocUtils.test.ts | 170 ++++++++++------ .../src/utils/tocUtils.ts | 76 ++++++-- packages/docusaurus-types/src/index.d.ts | 5 +- project-words.txt | 2 + website/docs/cli.md | 6 - website/docs/configuration.md | 2 +- .../markdown-features-inline-toc.mdx | 67 ++++++- .../version-2.0.0-beta.14/cli.md | 6 - .../version-2.0.0-beta.14/configuration.md | 2 +- .../markdown-features-inline-toc.mdx | 8 - .../version-2.0.0-beta.15/cli.md | 6 - .../version-2.0.0-beta.15/configuration.md | 2 +- .../markdown-features-inline-toc.mdx | 6 - 20 files changed, 312 insertions(+), 445 deletions(-) delete mode 100644 packages/docusaurus-mdx-loader/src/remark/toc/__tests__/search.test.ts delete mode 100644 packages/docusaurus-mdx-loader/src/remark/toc/search.ts diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap index f3d93c0585..bca8c59199 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap @@ -5,32 +5,26 @@ exports[`inline code should be escaped 1`] = ` { value: '<Head />', id: 'head-', - children: [ - { - value: '<Head>Test</Head>', - id: 'headtesthead', - children: [], - level: 3 - } - ], level: 2 }, + { + value: '<Head>Test</Head>', + id: 'headtesthead', + level: 3 + }, { value: '<div />', id: 'div-', - children: [], level: 2 }, { value: '<div> Test </div>', id: 'div-test-div', - children: [], level: 2 }, { value: '<div><i>Test</i></div>', id: 'divitestidiv', - children: [], level: 2 } ]; @@ -52,32 +46,26 @@ exports[`non text phrasing content 1`] = ` { value: 'Emphasis', id: 'emphasis', - children: [ - { - value: 'Importance', - id: 'importance', - children: [], - level: 3 - } - ], level: 2 }, + { + value: 'Importance', + id: 'importance', + level: 3 + }, { value: 'Strikethrough', id: 'strikethrough', - children: [], level: 2 }, { value: 'HTML', id: 'html', - children: [], level: 2 }, { value: 'inline.code()', id: 'inlinecode', - children: [], level: 2 } ]; diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts index f3134ef5d4..daf2488705 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts @@ -41,26 +41,21 @@ test('text content', async () => { { value: 'Endi', id: 'endi', - children: [], level: 3 }, { value: 'Endi', id: 'endi-1', - children: [ - { - value: 'Yangshun', - id: 'yangshun', - children: [], - level: 3 - } - ], level: 2 }, + { + value: 'Yangshun', + id: 'yangshun', + level: 3 + }, { value: 'I ♥ unicode.', id: 'i--unicode', - children: [], level: 2 } ]; @@ -91,21 +86,17 @@ test('should export even with existing name', async () => { { value: 'Thanos', id: 'thanos', - children: [], level: 2 }, { value: 'Tony Stark', id: 'tony-stark', - children: [ - { - value: 'Avengers', - id: 'avengers', - children: [], - level: 3 - } - ], level: 2 + }, + { + value: 'Avengers', + id: 'avengers', + level: 3 } ]; @@ -128,26 +119,21 @@ test('should export with custom name', async () => { { value: 'Endi', id: 'endi', - children: [], level: 3 }, { value: 'Endi', id: 'endi-1', - children: [ - { - value: 'Yangshun', - id: 'yangshun', - children: [], - level: 3 - } - ], level: 2 }, + { + value: 'Yangshun', + id: 'yangshun', + level: 3 + }, { value: 'I ♥ unicode.', id: 'i--unicode', - children: [], level: 2 } ]; @@ -182,21 +168,17 @@ test('should insert below imports', async () => { { value: 'Title', id: 'title', - children: [], level: 2 }, { value: 'Test', id: 'test', - children: [ - { - value: 'Again', - id: 'again', - children: [], - level: 3 - } - ], level: 2 + }, + { + value: 'Again', + id: 'again', + level: 3 } ]; diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/search.test.ts b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/search.test.ts deleted file mode 100644 index 900fbfad3f..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/search.test.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import remark from 'remark'; -import mdx from 'remark-mdx'; -import search from '../search'; -import headings from '../../headings/index'; - -const getHeadings = async (mdText: string) => { - const node = remark().parse(mdText); - const result = await remark().use(headings).use(mdx).run(node); - return search(result); -}; - -test('should process all heading levels', async () => { - const md = ` -# Alpha - -## Bravo - -### Charlie - -#### Delta - -##### Echo - -###### Foxtrot - - `; - - await expect(getHeadings(md)).resolves.toEqual([ - { - children: [ - { - children: [ - { - children: [ - { - children: [ - { - children: [], - id: 'foxtrot', - level: 6, - value: 'Foxtrot', - }, - ], - id: 'echo', - level: 5, - value: 'Echo', - }, - ], - id: 'delta', - level: 4, - value: 'Delta', - }, - ], - id: 'charlie', - level: 3, - value: 'Charlie', - }, - ], - id: 'bravo', - level: 2, - value: 'Bravo', - }, - ]); -}); - -test('should process real-world well-formatted md', async () => { - const md = ` -# title - -some text - -## section 1 - -some text - -### subsection 1-1 - -some text - -#### subsection 1-1-1 - -some text - -#### subsection 1-1-2 - -some text - -### subsection 1-2 - -some text - -### subsection 1-3 - -some text - -## section 2 - -some text - -### subsection 2-1 - -some text - -### subsection 2-1 - -some text - -## section 3 - -some text - -### subsection 3-1 - -some text - -### subsection 3-2 - -some text - - `; - - await expect(getHeadings(md)).resolves.toEqual([ - { - children: [ - { - children: [ - { - children: [], - id: 'subsection-1-1-1', - level: 4, - value: 'subsection 1-1-1', - }, - { - children: [], - id: 'subsection-1-1-2', - level: 4, - value: 'subsection 1-1-2', - }, - ], - id: 'subsection-1-1', - level: 3, - value: 'subsection 1-1', - }, - {children: [], id: 'subsection-1-2', level: 3, value: 'subsection 1-2'}, - {children: [], id: 'subsection-1-3', level: 3, value: 'subsection 1-3'}, - ], - id: 'section-1', - level: 2, - value: 'section 1', - }, - { - children: [ - {children: [], id: 'subsection-2-1', level: 3, value: 'subsection 2-1'}, - { - children: [], - id: 'subsection-2-1-1', - level: 3, - value: 'subsection 2-1', - }, - ], - id: 'section-2', - level: 2, - value: 'section 2', - }, - { - children: [ - {children: [], id: 'subsection-3-1', level: 3, value: 'subsection 3-1'}, - {children: [], id: 'subsection-3-2', level: 3, value: 'subsection 3-2'}, - ], - id: 'section-3', - level: 2, - value: 'section 3', - }, - ]); -}); diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts index c5630b796b..80e92b4a6b 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts @@ -9,10 +9,14 @@ import {parse, type ParserOptions} from '@babel/parser'; import type {Identifier} from '@babel/types'; import traverse from '@babel/traverse'; import stringifyObject from 'stringify-object'; -import search from './search'; -import type {Plugin, Transformer} from 'unified'; +import toString from 'mdast-util-to-string'; +import visit from 'unist-util-visit'; +import {toValue} from '../utils'; + +import type {TOCItem} from '@docusaurus/types'; import type {Node, Parent} from 'unist'; -import type {Literal} from 'mdast'; +import type {Heading, Literal} from 'mdast'; +import type {Plugin, Transformer} from 'unified'; const parseOptions: ParserOptions = { plugins: ['jsx'], @@ -70,7 +74,22 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => { const name = options.name || 'toc'; const transformer: Transformer = (node) => { - const headings = search(node); + const headings: TOCItem[] = []; + + visit(node, 'heading', (child: Heading, _index, parent) => { + const value = toString(child); + + // depth:1 headings are titles and not included in the TOC + if (parent !== node || !value || child.depth < 2) { + return; + } + + headings.push({ + value: toValue(child), + id: child.data!.id as string, + level: child.depth, + }); + }); const {children} = node as Parent; const targetIndex = getOrCreateExistingTargetIndex(children, name); diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/search.ts b/packages/docusaurus-mdx-loader/src/remark/toc/search.ts deleted file mode 100644 index ea8fc8b704..0000000000 --- a/packages/docusaurus-mdx-loader/src/remark/toc/search.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import toString from 'mdast-util-to-string'; -import visit from 'unist-util-visit'; -import {toValue} from '../utils'; -import type {TOCItem} from '@docusaurus/types'; -import type {Node} from 'unist'; -import type {Heading} from 'mdast'; - -// Intermediate interface for TOC algorithm -interface SearchItem { - node: TOCItem; - level: number; - parentIndex: number; -} - -/** - * - * Generate a TOC AST from the raw Markdown contents - */ -export default function search(node: Node): TOCItem[] { - const headings: SearchItem[] = []; - - visit(node, 'heading', (child: Heading, _index, parent) => { - const value = toString(child); - - // depth:1 headings are titles and not included in the TOC - if (parent !== node || !value || child.depth < 2) { - return; - } - - headings.push({ - node: { - value: toValue(child), - id: child.data!.id as string, - children: [], - level: child.depth, - }, - level: child.depth, - parentIndex: -1, - }); - }); - - // Keep track of which previous index would be the current heading's direct - // parent. Each entry is the last index of the `headings` array at heading - // level . We will modify these indices as we iterate through all headings. - // e.g. if an ### H3 was last seen at index 2, then prevIndexForLevel[3] === 2 - // indices 0 and 1 will remain unused. - const prevIndexForLevel = Array(7).fill(-1); - - headings.forEach((curr, currIndex) => { - // take the last seen index for each ancestor level. the highest - // index will be the direct ancestor of the current heading. - const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level); - curr.parentIndex = Math.max(...ancestorLevelIndexes); - // mark that curr.level was last seen at the current index - prevIndexForLevel[curr.level] = currIndex; - }); - - const rootNodeIndexes: number[] = []; - - // For a given parentIndex, add each Node into that parent's `children` array - headings.forEach((heading, i) => { - if (heading.parentIndex >= 0) { - headings[heading.parentIndex].node.children.push(heading.node); - } else { - rootNodeIndexes.push(i); - } - }); - - const toc = headings - .filter((_, k) => rootNodeIndexes.includes(k)) // only return root nodes - .map((heading) => heading.node); // only return Node, no metadata - return toc; -} diff --git a/packages/docusaurus-theme-classic/src/theme/TOCItems/index.tsx b/packages/docusaurus-theme-classic/src/theme/TOCItems/index.tsx index 18715350f3..b0bed7c2bd 100644 --- a/packages/docusaurus-theme-classic/src/theme/TOCItems/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/TOCItems/index.tsx @@ -7,12 +7,12 @@ import React, {useMemo} from 'react'; import type {Props} from '@theme/TOCItems'; -import type {TOCItem} from '@docusaurus/types'; import { type TOCHighlightConfig, + type TOCTreeNode, useThemeConfig, - useTOCFilter, useTOCHighlight, + useFilteredAndTreeifiedTOC, } from '@docusaurus/theme-common'; // Recursive component rendering the toc tree @@ -23,7 +23,7 @@ function TOCItemList({ linkClassName, isChild, }: { - readonly toc: readonly TOCItem[]; + readonly toc: readonly TOCTreeNode[]; readonly className: string; readonly linkClassName: string | null; readonly isChild?: boolean; @@ -70,7 +70,11 @@ export default function TOCItems({ const maxHeadingLevel = maxHeadingLevelOption ?? themeConfig.tableOfContents.maxHeadingLevel; - const tocFiltered = useTOCFilter({toc, minHeadingLevel, maxHeadingLevel}); + const tocTree = useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel, + maxHeadingLevel, + }); const tocHighlightConfig: TOCHighlightConfig | undefined = useMemo(() => { if (linkClassName && linkActiveClassName) { @@ -87,7 +91,7 @@ export default function TOCItems({ return ( { +describe('useFilteredAndTreeifiedTOC', () => { test('filter a toc with all heading levels', () => { const toc: TOCItem[] = [ { id: 'alpha', level: 1, value: 'alpha', - children: [ - { - id: 'bravo', - level: 2, - value: 'Bravo', - children: [ - { - id: 'charlie', - level: 3, - value: 'Charlie', - children: [ - { - id: 'delta', - level: 4, - value: 'Delta', - children: [ - { - id: 'echo', - level: 5, - value: 'Echo', - children: [ - { - id: 'foxtrot', - level: 6, - value: 'Foxtrot', - children: [], - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + }, + { + id: 'bravo', + level: 2, + value: 'Bravo', + }, + { + id: 'charlie', + level: 3, + value: 'Charlie', + }, + { + id: 'delta', + level: 4, + value: 'Delta', + }, + { + id: 'echo', + level: 5, + value: 'Echo', + }, + { + id: 'foxtrot', + level: 6, + value: 'Foxtrot', }, ]; - expect(filterTOC({toc, minHeadingLevel: 2, maxHeadingLevel: 2})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 2, + maxHeadingLevel: 2, + }), + ).result.current, + ).toEqual([ { id: 'bravo', level: 2, @@ -63,7 +61,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 3, maxHeadingLevel: 3})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 3, + maxHeadingLevel: 3, + }), + ).result.current, + ).toEqual([ { id: 'charlie', level: 3, @@ -72,7 +78,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 2, maxHeadingLevel: 3})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 2, + maxHeadingLevel: 3, + }), + ).result.current, + ).toEqual([ { id: 'bravo', level: 2, @@ -88,7 +102,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 2, maxHeadingLevel: 4})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 2, + maxHeadingLevel: 4, + }), + ).result.current, + ).toEqual([ { id: 'bravo', level: 2, @@ -121,24 +143,28 @@ describe('filterTOC', () => { id: 'charlie', level: 3, value: 'Charlie', - children: [], }, { id: 'bravo', level: 2, value: 'Bravo', - children: [ - { - id: 'delta', - level: 4, - value: 'Delta', - children: [], - }, - ], + }, + { + id: 'delta', + level: 4, + value: 'Delta', }, ]; - expect(filterTOC({toc, minHeadingLevel: 2, maxHeadingLevel: 2})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 2, + maxHeadingLevel: 2, + }), + ).result.current, + ).toEqual([ { id: 'bravo', level: 2, @@ -147,7 +173,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 3, maxHeadingLevel: 3})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 3, + maxHeadingLevel: 3, + }), + ).result.current, + ).toEqual([ { id: 'charlie', level: 3, @@ -156,7 +190,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 4, maxHeadingLevel: 4})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 4, + maxHeadingLevel: 4, + }), + ).result.current, + ).toEqual([ { id: 'delta', level: 4, @@ -165,7 +207,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 2, maxHeadingLevel: 3})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 2, + maxHeadingLevel: 3, + }), + ).result.current, + ).toEqual([ { id: 'charlie', level: 3, @@ -180,7 +230,15 @@ describe('filterTOC', () => { }, ]); - expect(filterTOC({toc, minHeadingLevel: 3, maxHeadingLevel: 4})).toEqual([ + expect( + renderHook(() => + useFilteredAndTreeifiedTOC({ + toc, + minHeadingLevel: 3, + maxHeadingLevel: 4, + }), + ).result.current, + ).toEqual([ { id: 'charlie', level: 3, diff --git a/packages/docusaurus-theme-common/src/utils/tocUtils.ts b/packages/docusaurus-theme-common/src/utils/tocUtils.ts index 0e88c9fb4f..6f00ebc3db 100644 --- a/packages/docusaurus-theme-common/src/utils/tocUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tocUtils.ts @@ -8,18 +8,64 @@ import {useMemo} from 'react'; import type {TOCItem} from '@docusaurus/types'; -type FilterTOCParam = { - toc: readonly TOCItem[]; - minHeadingLevel: number; - maxHeadingLevel: number; +export type TOCTreeNode = { + readonly value: string; + readonly id: string; + readonly level: number; + readonly children: readonly TOCTreeNode[]; }; -export function filterTOC({ +function treeifyTOC(flatTOC: readonly TOCItem[]): TOCTreeNode[] { + const headings = flatTOC.map((heading) => ({ + ...heading, + parentIndex: -1, + children: [] as TOCTreeNode[], + })); + + // Keep track of which previous index would be the current heading's direct + // parent. Each entry is the last index of the `headings` array at heading + // level . We will modify these indices as we iterate through all headings. + // e.g. if an ### H3 was last seen at index 2, then prevIndexForLevel[3] === 2 + // indices 0 and 1 will remain unused. + const prevIndexForLevel = Array(7).fill(-1); + + headings.forEach((curr, currIndex) => { + // take the last seen index for each ancestor level. the highest + // index will be the direct ancestor of the current heading. + const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level); + curr.parentIndex = Math.max(...ancestorLevelIndexes); + // mark that curr.level was last seen at the current index + prevIndexForLevel[curr.level] = currIndex; + }); + + const rootNodes: TOCTreeNode[] = []; + + // For a given parentIndex, add each Node into that parent's `children` array + headings.forEach((heading) => { + const {parentIndex, ...rest} = heading; + if (parentIndex >= 0) { + headings[parentIndex].children.push(rest); + } else { + rootNodes.push(rest); + } + }); + return rootNodes; +} + +export function useTreeifiedTOC(toc: TOCItem[]): readonly TOCTreeNode[] { + return useMemo(() => treeifyTOC(toc), [toc]); +} + +function filterTOC({ toc, minHeadingLevel, maxHeadingLevel, -}: FilterTOCParam): TOCItem[] { - function isValid(item: TOCItem) { +}: { + toc: readonly TOCTreeNode[]; + minHeadingLevel: number; + maxHeadingLevel: number; +}): TOCTreeNode[] { + function isValid(item: TOCTreeNode) { return item.level >= minHeadingLevel && item.level <= maxHeadingLevel; } @@ -41,14 +87,22 @@ export function filterTOC({ }); } -// Memoize potentially expensive filtering logic -export function useTOCFilter({ +export function useFilteredAndTreeifiedTOC({ toc, minHeadingLevel, maxHeadingLevel, -}: FilterTOCParam): readonly TOCItem[] { +}: { + toc: readonly TOCItem[]; + minHeadingLevel: number; + maxHeadingLevel: number; +}): readonly TOCTreeNode[] { return useMemo( - () => filterTOC({toc, minHeadingLevel, maxHeadingLevel}), + () => + // Note: we have to filter the TOC after it has been treeified. This is + // mostly to ensure that weird TOC structures preserve their semantics. + // For example, an h3-h2-h4 sequence should not be treeified as an h3 > h4 + // hierarchy with min=3, max=4, but should rather be [h3, h4] + filterTOC({toc: treeifyTOC(toc), minHeadingLevel, maxHeadingLevel}), [toc, minHeadingLevel, maxHeadingLevel], ); } diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index a33d8c5e81..f664c66c69 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -429,12 +429,11 @@ export interface ThemeConfigValidationContext { themeConfig: Partial; } -export interface TOCItem { +export type TOCItem = { readonly value: string; readonly id: string; - readonly children: TOCItem[]; readonly level: number; -} +}; export type RouteChunksTree = {[x: string | number]: string | RouteChunksTree}; diff --git a/project-words.txt b/project-words.txt index e3fa93bff9..940a50943f 100644 --- a/project-words.txt +++ b/project-words.txt @@ -246,6 +246,7 @@ stylelintrc sublabel sublicensable sublist +subsubsection subpage subroute subroutes @@ -260,6 +261,7 @@ toolset toplevel transifex transpiles +treeified treeify treosh triaging diff --git a/website/docs/cli.md b/website/docs/cli.md index 5955f30f78..44980ef6c4 100644 --- a/website/docs/cli.md +++ b/website/docs/cli.md @@ -25,12 +25,6 @@ Once your website is bootstrapped, the website source will contain the Docusauru } ``` -## Index {#index} - -import TOCInline from "@theme/TOCInline" - - - ## Docusaurus CLI commands {#docusaurus-cli-commands} Below is a list of Docusaurus CLI commands and their usages: diff --git a/website/docs/configuration.md b/website/docs/configuration.md index c91354a6e6..161882929c 100644 --- a/website/docs/configuration.md +++ b/website/docs/configuration.md @@ -17,7 +17,7 @@ However, it can be helpful if you have a high-level understanding of how the con The high-level overview of Docusaurus configuration can be categorized into: - + For exact reference to each of the configurable fields, you may refer to [**`docusaurus.config.js` API reference**](api/docusaurus.config.js.md). diff --git a/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx b/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx index c8a8eaf567..4a48251ac4 100644 --- a/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx +++ b/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx @@ -35,33 +35,30 @@ import TOCInline from '@theme/TOCInline'; ## Custom table of contents {#custom-table-of-contents} -The `toc` props is just a list of table of contents items: +The `toc` prop is just a list of heading items: ```ts type TOCItem = { value: string; id: string; - children: TOCItem[]; level: number; }; ``` -You can create this TOC tree manually, or derive a new TOC tree from the `toc` variable: +Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. ```jsx import TOCInline from '@theme/TOCInline'; node.level === 2 || node.level === 4)} />; ``` ```mdx-code-block - + node.level === 2 || node.level === 4)} /> ``` @@ -81,14 +78,32 @@ Lorem ipsum Lorem ipsum +#### Example subsubsection 1 a I + +#### Example subsubsection 1 a II + +#### Example subsubsection 1 a III + ### Example Subsection 1 b {#example-subsection-1-b} Lorem ipsum +#### Example subsubsection 1 b I + +#### Example subsubsection 1 b II + +#### Example subsubsection 1 b III + ### Example Subsection 1 c {#example-subsection-1-c} Lorem ipsum +#### Example subsubsection 1 c I + +#### Example subsubsection 1 c II + +#### Example subsubsection 1 c III + ## Example Section 2 {#example-section-2} Lorem ipsum @@ -97,14 +112,32 @@ Lorem ipsum Lorem ipsum +#### Example subsubsection 2 a I + +#### Example subsubsection 2 a II + +#### Example subsubsection 2 a III + ### Example Subsection 2 b {#example-subsection-2-b} Lorem ipsum +#### Example subsubsection 2 b I + +#### Example subsubsection 2 b II + +#### Example subsubsection 2 b III + ### Example Subsection 2 c {#example-subsection-2-c} Lorem ipsum +#### Example subsubsection 2 c I + +#### Example subsubsection 2 c II + +#### Example subsubsection 2 c III + ## Example Section 3 {#example-section-3} Lorem ipsum @@ -113,10 +146,28 @@ Lorem ipsum Lorem ipsum +#### Example subsubsection 3 a I + +#### Example subsubsection 3 a II + +#### Example subsubsection 3 a III + ### Example Subsection 3 b {#example-subsection-3-b} Lorem ipsum +#### Example subsubsection 3 b I + +#### Example subsubsection 3 b II + +#### Example subsubsection 3 b III + ### Example Subsection 3 c {#example-subsection-3-c} Lorem ipsum + +#### Example subsubsection 3 c I + +#### Example subsubsection 3 c II + +#### Example subsubsection 3 c III diff --git a/website/versioned_docs/version-2.0.0-beta.14/cli.md b/website/versioned_docs/version-2.0.0-beta.14/cli.md index 9ea0d48af1..a88cb82b04 100644 --- a/website/versioned_docs/version-2.0.0-beta.14/cli.md +++ b/website/versioned_docs/version-2.0.0-beta.14/cli.md @@ -25,12 +25,6 @@ Once your website is bootstrapped, the website source will contain the Docusauru } ``` -## Index {#index} - -import TOCInline from "@theme/TOCInline" - - - ## Docusaurus CLI commands {#docusaurus-cli-commands} Below is a list of Docusaurus CLI commands and their usages: diff --git a/website/versioned_docs/version-2.0.0-beta.14/configuration.md b/website/versioned_docs/version-2.0.0-beta.14/configuration.md index c10a1692c9..00b42d0172 100644 --- a/website/versioned_docs/version-2.0.0-beta.14/configuration.md +++ b/website/versioned_docs/version-2.0.0-beta.14/configuration.md @@ -17,7 +17,7 @@ However, it can be helpful if you have a high-level understanding of how the con The high-level overview of Docusaurus configuration can be categorized into: - + For exact reference to each of the configurable fields, you may refer to [**`docusaurus.config.js` API reference**](api/docusaurus.config.js.md). diff --git a/website/versioned_docs/version-2.0.0-beta.14/guides/markdown-features/markdown-features-inline-toc.mdx b/website/versioned_docs/version-2.0.0-beta.14/guides/markdown-features/markdown-features-inline-toc.mdx index 3726f04842..d3ad685831 100644 --- a/website/versioned_docs/version-2.0.0-beta.14/guides/markdown-features/markdown-features-inline-toc.mdx +++ b/website/versioned_docs/version-2.0.0-beta.14/guides/markdown-features/markdown-features-inline-toc.mdx @@ -59,14 +59,6 @@ import TOCInline from '@theme/TOCInline'; />; ``` -```mdx-code-block - - - - - -``` - --- :::caution diff --git a/website/versioned_docs/version-2.0.0-beta.15/cli.md b/website/versioned_docs/version-2.0.0-beta.15/cli.md index a491f7f618..b2593ca4b0 100644 --- a/website/versioned_docs/version-2.0.0-beta.15/cli.md +++ b/website/versioned_docs/version-2.0.0-beta.15/cli.md @@ -25,12 +25,6 @@ Once your website is bootstrapped, the website source will contain the Docusauru } ``` -## Index {#index} - -import TOCInline from "@theme/TOCInline" - - - ## Docusaurus CLI commands {#docusaurus-cli-commands} Below is a list of Docusaurus CLI commands and their usages: diff --git a/website/versioned_docs/version-2.0.0-beta.15/configuration.md b/website/versioned_docs/version-2.0.0-beta.15/configuration.md index c91354a6e6..161882929c 100644 --- a/website/versioned_docs/version-2.0.0-beta.15/configuration.md +++ b/website/versioned_docs/version-2.0.0-beta.15/configuration.md @@ -17,7 +17,7 @@ However, it can be helpful if you have a high-level understanding of how the con The high-level overview of Docusaurus configuration can be categorized into: - + For exact reference to each of the configurable fields, you may refer to [**`docusaurus.config.js` API reference**](api/docusaurus.config.js.md). diff --git a/website/versioned_docs/version-2.0.0-beta.15/guides/markdown-features/markdown-features-inline-toc.mdx b/website/versioned_docs/version-2.0.0-beta.15/guides/markdown-features/markdown-features-inline-toc.mdx index c8a8eaf567..bfdc6c1a6d 100644 --- a/website/versioned_docs/version-2.0.0-beta.15/guides/markdown-features/markdown-features-inline-toc.mdx +++ b/website/versioned_docs/version-2.0.0-beta.15/guides/markdown-features/markdown-features-inline-toc.mdx @@ -59,12 +59,6 @@ import TOCInline from '@theme/TOCInline'; />; ``` -```mdx-code-block - - - -``` - --- :::caution