From 827924f12747e3aef6583cde3fc943828b5bcf67 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 17 Aug 2022 17:35:45 +0200 Subject: [PATCH 01/15] stable iso refactor of docs routes --- .../src/index.ts | 110 ++---------- .../src/routes.ts | 158 ++++++++++++------ .../src/versions/index.ts | 19 ++- 3 files changed, 139 insertions(+), 148 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 0b03d48a0542..ce25a87f0ea3 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -27,22 +27,18 @@ import { addDocNavigation, type DocEnv, } from './docs'; -import {readVersionsMetadata} from './versions'; +import {readVersionsMetadata, toFullVersion} from './versions'; import {cliDocsVersionCommand} from './cli'; import {VERSIONS_JSON_FILE} from './constants'; import {toGlobalDataVersion} from './globalData'; -import {toTagDocListProp} from './props'; -import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex'; import { translateLoadedContent, getLoadedContentTranslationFiles, } from './translations'; -import {getVersionTags} from './tags'; -import {createVersionRoutes} from './routes'; +import {createAllRoutes} from './routes'; import {createSidebarsUtils} from './sidebars/utils'; import type { - PropTagsListPage, PluginOptions, DocMetadataBase, VersionMetadata, @@ -55,7 +51,6 @@ import type { SourceToPermalink, DocFile, DocsMarkdownOption, - VersionTag, FullVersion, } from './types'; import type {RuleSetRule} from 'webpack'; @@ -209,102 +204,19 @@ export default async function pluginContentDocs( }, async contentLoaded({content, actions}) { - const {loadedVersions} = content; - const { - docLayoutComponent, - docItemComponent, - docCategoryGeneratedIndexComponent, - breadcrumbs, - } = options; - const {addRoute, createData, setGlobalData} = actions; - const versions: FullVersion[] = loadedVersions.map((version) => { - const sidebarsUtils = createSidebarsUtils(version.sidebars); - return { - ...version, - sidebarsUtils, - categoryGeneratedIndices: getCategoryGeneratedIndexMetadataList({ - docs: version.docs, - sidebarsUtils, - }), - }; - }); - - async function createVersionTagsRoutes(version: FullVersion) { - const versionTags = getVersionTags(version.docs); - - // TODO tags should be a sub route of the version route - async function createTagsListPage() { - const tagsProp: PropTagsListPage['tags'] = Object.values( - versionTags, - ).map((tagValue) => ({ - label: tagValue.label, - permalink: tagValue.permalink, - count: tagValue.docIds.length, - })); - - // Only create /tags page if there are tags. - if (tagsProp.length > 0) { - const tagsPropPath = await createData( - `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, - JSON.stringify(tagsProp, null, 2), - ); - addRoute({ - path: version.tagsPath, - exact: true, - component: options.docTagsListComponent, - modules: { - tags: aliasedSource(tagsPropPath), - }, - }); - } - } + const versions: FullVersion[] = content.loadedVersions.map(toFullVersion); - // TODO tags should be a sub route of the version route - async function createTagDocListPage(tag: VersionTag) { - const tagProps = toTagDocListProp({ - allTagsPath: version.tagsPath, - tag, - docs: version.docs, - }); - const tagPropPath = await createData( - `${docuHash(`tag-${tag.permalink}`)}.json`, - JSON.stringify(tagProps, null, 2), - ); - addRoute({ - path: tag.permalink, - component: options.docTagDocListComponent, - exact: true, - modules: { - tag: aliasedSource(tagPropPath), - }, - }); - } - - await createTagsListPage(); - await Promise.all(Object.values(versionTags).map(createTagDocListPage)); - } - - await Promise.all( - versions.map((version) => - createVersionRoutes({ - version, - docItemComponent, - docLayoutComponent, - docCategoryGeneratedIndexComponent, - pluginId, - aliasedSource, - actions, - }), - ), - ); - - // TODO tags should be a sub route of the version route - await Promise.all(versions.map(createVersionTagsRoutes)); + await createAllRoutes({ + versions, + options, + actions, + aliasedSource, + }); - setGlobalData({ + actions.setGlobalData({ path: normalizeUrl([baseUrl, options.routeBasePath]), versions: versions.map(toGlobalDataVersion), - breadcrumbs, + breadcrumbs: options.breadcrumbs, }); }, diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index 9a9205bee1c5..7a4f589c869a 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -7,25 +7,22 @@ import logger from '@docusaurus/logger'; import {docuHash, createSlugger} from '@docusaurus/utils'; -import {toVersionMetadataProp} from './props'; +import {toTagDocListProp, toVersionMetadataProp} from './props'; +import {getVersionTags} from './tags'; import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types'; -import type {FullVersion} from './types'; +import type {FullVersion, VersionTag} from './types'; import type { CategoryGeneratedIndexMetadata, - DocMetadata, + PluginOptions, + PropTagsListPage, } from '@docusaurus/plugin-content-docs'; -export async function createCategoryGeneratedIndexRoutes({ +async function createVersionCategoryGeneratedIndexRoutes({ version, actions, - docCategoryGeneratedIndexComponent, + options, aliasedSource, -}: { - version: FullVersion; - actions: PluginContentLoadedActions; - docCategoryGeneratedIndexComponent: string; - aliasedSource: (str: string) => string; -}): Promise { +}: CreateVersionRoutesParam): Promise { const slugs = createSlugger(); async function createCategoryGeneratedIndexRoute( @@ -44,7 +41,7 @@ export async function createCategoryGeneratedIndexRoutes({ return { path: categoryGeneratedIndex.permalink, - component: docCategoryGeneratedIndexComponent, + component: options.docCategoryGeneratedIndexComponent, exact: true, modules: { categoryGeneratedIndex: aliasedSource(propData), @@ -60,17 +57,13 @@ export async function createCategoryGeneratedIndexRoutes({ ); } -export async function createDocRoutes({ - docs, +async function createVersionDocRoutes({ + version, actions, - docItemComponent, -}: { - docs: DocMetadata[]; - actions: PluginContentLoadedActions; - docItemComponent: string; -}): Promise { + options, +}: CreateVersionRoutesParam): Promise { return Promise.all( - docs.map(async (metadataItem) => { + version.docs.map(async (metadataItem) => { await actions.createData( // Note that this created data path must be in sync with // metadataPath provided to mdx-loader. @@ -80,7 +73,7 @@ export async function createDocRoutes({ const docRoute: RouteConfig = { path: metadataItem.permalink, - component: docItemComponent, + component: options.docItemComponent, exact: true, modules: { content: metadataItem.source, @@ -98,25 +91,16 @@ export async function createDocRoutes({ ); } -export async function createVersionRoutes({ - version, - actions, - docItemComponent, - docLayoutComponent, - docCategoryGeneratedIndexComponent, - pluginId, - aliasedSource, -}: { +type CreateVersionRoutesParam = Omit & { version: FullVersion; - actions: PluginContentLoadedActions; - docLayoutComponent: string; - docItemComponent: string; - docCategoryGeneratedIndexComponent: string; - pluginId: string; - aliasedSource: (str: string) => string; -}): Promise { +}; + +async function createVersionRoutes( + param: CreateVersionRoutesParam, +): Promise { + const {version, actions, options, aliasedSource} = param; async function doCreateVersionRoutes(): Promise { - const versionMetadata = toVersionMetadataProp(pluginId, version); + const versionMetadata = toVersionMetadataProp(options.id, version); const versionMetadataPropPath = await actions.createData( `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`, JSON.stringify(versionMetadata, null, 2), @@ -124,13 +108,8 @@ export async function createVersionRoutes({ async function createVersionSubRoutes() { const [docRoutes, sidebarsRoutes] = await Promise.all([ - createDocRoutes({docs: version.docs, actions, docItemComponent}), - createCategoryGeneratedIndexRoutes({ - version, - actions, - docCategoryGeneratedIndexComponent, - aliasedSource, - }), + createVersionDocRoutes(param), + createVersionCategoryGeneratedIndexRoutes(param), ]); const routes = [...docRoutes, ...sidebarsRoutes]; @@ -141,7 +120,7 @@ export async function createVersionRoutes({ path: version.path, // Allow matching /docs/* since this is the wrapping route exact: false, - component: docLayoutComponent, + component: options.docLayoutComponent, routes: await createVersionSubRoutes(), modules: { versionMetadata: aliasedSource(versionMetadataPropPath), @@ -157,3 +136,88 @@ export async function createVersionRoutes({ throw err; } } + +async function createVersionsRoutes(param: CreateAllRoutesParam) { + await Promise.all( + param.versions.map((version) => + createVersionRoutes({ + ...param, + version, + }), + ), + ); +} + +type CreateAllRoutesParam = { + versions: FullVersion[]; + options: PluginOptions; + actions: PluginContentLoadedActions; + aliasedSource: (str: string) => string; +}; + +export async function createAllRoutes( + param: CreateAllRoutesParam, +): Promise { + const {versions, options, actions, aliasedSource} = param; + const {addRoute, createData} = actions; + + async function createVersionTagsRoutes(version: FullVersion) { + const versionTags = getVersionTags(version.docs); + + // TODO tags should be a sub route of the version route + async function createTagsListPage() { + const tagsProp: PropTagsListPage['tags'] = Object.values(versionTags).map( + (tagValue) => ({ + label: tagValue.label, + permalink: tagValue.permalink, + count: tagValue.docIds.length, + }), + ); + + // Only create /tags page if there are tags. + if (tagsProp.length > 0) { + const tagsPropPath = await createData( + `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, + JSON.stringify(tagsProp, null, 2), + ); + addRoute({ + path: version.tagsPath, + exact: true, + component: options.docTagsListComponent, + modules: { + tags: aliasedSource(tagsPropPath), + }, + }); + } + } + + // TODO tags should be a sub route of the version route + async function createTagDocListPage(tag: VersionTag) { + const tagProps = toTagDocListProp({ + allTagsPath: version.tagsPath, + tag, + docs: version.docs, + }); + const tagPropPath = await createData( + `${docuHash(`tag-${tag.permalink}`)}.json`, + JSON.stringify(tagProps, null, 2), + ); + addRoute({ + path: tag.permalink, + component: options.docTagDocListComponent, + exact: true, + modules: { + tag: aliasedSource(tagPropPath), + }, + }); + } + + await createTagsListPage(); + await Promise.all(Object.values(versionTags).map(createTagDocListPage)); + } + + await createVersionsRoutes(param); + + // TODO tags should be a sub route of the version route + await Promise.all(versions.map(createVersionTagsRoutes)); +} diff --git a/packages/docusaurus-plugin-content-docs/src/versions/index.ts b/packages/docusaurus-plugin-content-docs/src/versions/index.ts index 39edeba0e092..473cbc8e3cba 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions/index.ts @@ -14,12 +14,15 @@ import { getVersionMetadataPaths, readVersionNames, } from './files'; -import type { +import {createSidebarsUtils} from '../sidebars/utils'; +import {getCategoryGeneratedIndexMetadataList} from '../categoryGeneratedIndex'; +import type {FullVersion} from '../types'; +import type {LoadContext} from '@docusaurus/types'; +import type {LoadedVersion, PluginOptions, VersionBanner, VersionMetadata, } from '@docusaurus/plugin-content-docs'; -import type {LoadContext} from '@docusaurus/types'; export type VersionContext = { /** The version name to get banner of. */ @@ -252,3 +255,15 @@ export async function readVersionsMetadata({ ); return versionsMetadata; } + +export function toFullVersion(version: LoadedVersion): FullVersion { + const sidebarsUtils = createSidebarsUtils(version.sidebars); + return { + ...version, + sidebarsUtils, + categoryGeneratedIndices: getCategoryGeneratedIndexMetadataList({ + docs: version.docs, + sidebarsUtils, + }), + }; +} From da3cbe966a261e70e7fdcf3152c8674e2c0f1b5b Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 17 Aug 2022 18:19:37 +0200 Subject: [PATCH 02/15] move tags under version route --- .../__snapshots__/index.test.ts.snap | 128 +++++------ .../src/props.ts | 13 +- .../src/routes.ts | 215 ++++++++++-------- 3 files changed, 201 insertions(+), 155 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 3072419e03ef..a047b9eac4df 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1242,38 +1242,6 @@ exports[`simple website content: global data 1`] = ` exports[`simple website content: route config 1`] = ` [ - { - "component": "@theme/DocTagsListPage", - "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, - "path": "/docs/tags", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-1-b3f.json", - }, - "path": "/docs/tags/tag-1", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-3-ab5.json", - }, - "path": "/docs/tags/tag-3", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", - }, - "path": "/docs/tags/tag2-custom-permalink", - }, { "component": "@theme/DocPage", "exact": false, @@ -1444,6 +1412,38 @@ exports[`simple website content: route config 1`] = ` }, "path": "/docs/slugs/relativeSlug", }, + { + "component": "@theme/DocTagsListPage", + "exact": true, + "modules": { + "tags": "~docs/tags-list-current-prop-15a.json", + }, + "path": "/docs/tags", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-tags-tag-1-b3f.json", + }, + "path": "/docs/tags/tag-1", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-tags-tag-3-ab5.json", + }, + "path": "/docs/tags/tag-3", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", + }, + "path": "/docs/tags/tag2-custom-permalink", + }, { "component": "@theme/DocItem", "exact": true, @@ -3930,38 +3930,6 @@ exports[`versioned website content: global data 1`] = ` exports[`versioned website content: route config 1`] = ` [ - { - "component": "@theme/DocTagsListPage", - "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, - "path": "/docs/next/tags", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", - }, - "path": "/docs/next/tags/bar-tag-1", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", - }, - "path": "/docs/next/tags/bar-tag-2", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", - }, - "path": "/docs/next/tags/barTag-3-permalink", - }, { "component": "@theme/DocPage", "exact": false, @@ -4051,6 +4019,38 @@ exports[`versioned website content: route config 1`] = ` }, "path": "/docs/next/slugs/relativeSlug", }, + { + "component": "@theme/DocTagsListPage", + "exact": true, + "modules": { + "tags": "~docs/tags-list-current-prop-15a.json", + }, + "path": "/docs/next/tags", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", + }, + "path": "/docs/next/tags/bar-tag-1", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", + }, + "path": "/docs/next/tags/bar-tag-2", + }, + { + "component": "@theme/DocTagDocListPage", + "exact": true, + "modules": { + "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", + }, + "path": "/docs/next/tags/barTag-3-permalink", + }, { "component": "@theme/DocItem", "exact": true, diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index e8f05ba4ebe4..c9f58096ac50 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import {createDocsByIdIndex} from './docs'; -import type {VersionTag} from './types'; +import type {VersionTag, VersionTags} from './types'; import type { SidebarItemDoc, SidebarItem, @@ -21,6 +21,7 @@ import type { PropSidebarItemCategory, PropTagDocList, PropTagDocListDoc, + PropTagsListPage, PropSidebarItemLink, PropVersionDocs, DocMetadata, @@ -181,3 +182,13 @@ export function toTagDocListProp({ items: toDocListProp(), }; } + +export function toTagsListTagsProp( + versionTags: VersionTags, +): PropTagsListPage['tags'] { + return Object.values(versionTags).map((tagValue) => ({ + label: tagValue.label, + permalink: tagValue.permalink, + count: tagValue.docIds.length, + })); +} diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index 7a4f589c869a..0d083bae002e 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -5,9 +5,14 @@ * LICENSE file in the root directory of this source tree. */ +import _ from 'lodash'; import logger from '@docusaurus/logger'; import {docuHash, createSlugger} from '@docusaurus/utils'; -import {toTagDocListProp, toVersionMetadataProp} from './props'; +import { + toTagDocListProp, + toTagsListTagsProp, + toVersionMetadataProp, +} from './props'; import {getVersionTags} from './tags'; import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types'; import type {FullVersion, VersionTag} from './types'; @@ -17,15 +22,15 @@ import type { PropTagsListPage, } from '@docusaurus/plugin-content-docs'; -async function createVersionCategoryGeneratedIndexRoutes({ +async function buildVersionCategoryGeneratedIndexRoutes({ version, actions, options, aliasedSource, -}: CreateVersionRoutesParam): Promise { +}: BuildVersionRoutesParam): Promise { const slugs = createSlugger(); - async function createCategoryGeneratedIndexRoute( + async function buildCategoryGeneratedIndexRoute( categoryGeneratedIndex: CategoryGeneratedIndexMetadata, ): Promise { const {sidebar, ...prop} = categoryGeneratedIndex; @@ -53,7 +58,7 @@ async function createVersionCategoryGeneratedIndexRoutes({ } return Promise.all( - version.categoryGeneratedIndices.map(createCategoryGeneratedIndexRoute), + version.categoryGeneratedIndices.map(buildCategoryGeneratedIndexRoute), ); } @@ -61,7 +66,7 @@ async function createVersionDocRoutes({ version, actions, options, -}: CreateVersionRoutesParam): Promise { +}: BuildVersionRoutesParam): Promise { return Promise.all( version.docs.map(async (metadataItem) => { await actions.createData( @@ -91,32 +96,92 @@ async function createVersionDocRoutes({ ); } -type CreateVersionRoutesParam = Omit & { +async function buildVersionTagsRoutes( + param: BuildVersionRoutesParam, +): Promise { + const {version, options, actions, aliasedSource} = param; + const versionTags = getVersionTags(version.docs); + + async function buildTagsListRoute(): Promise { + // Don't create a tags list page if there's no tag + if (Object.keys(versionTags).length === 0) { + return null; + } + const tagsProp: PropTagsListPage['tags'] = toTagsListTagsProp(versionTags); + const tagsPropPath = await actions.createData( + `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, + JSON.stringify(tagsProp, null, 2), + ); + return { + path: version.tagsPath, + exact: true, + component: options.docTagsListComponent, + modules: { + tags: aliasedSource(tagsPropPath), + }, + }; + } + + async function buildTagDocListRoute(tag: VersionTag): Promise { + const tagProps = toTagDocListProp({ + allTagsPath: version.tagsPath, + tag, + docs: version.docs, + }); + const tagPropPath = await actions.createData( + `${docuHash(`tag-${tag.permalink}`)}.json`, + JSON.stringify(tagProps, null, 2), + ); + return { + path: tag.permalink, + component: options.docTagDocListComponent, + exact: true, + modules: { + tag: aliasedSource(tagPropPath), + }, + }; + } + + const [tagsListRoute, allTagsDocListRoutes] = await Promise.all([ + buildTagsListRoute(), + Promise.all(Object.values(versionTags).map(buildTagDocListRoute)), + ]); + + return _.compact([tagsListRoute, ...allTagsDocListRoutes]); +} + +type BuildVersionRoutesParam = Omit & { version: FullVersion; }; -async function createVersionRoutes( - param: CreateVersionRoutesParam, -): Promise { +async function buildVersionRoutes( + param: BuildVersionRoutesParam, +): Promise { const {version, actions, options, aliasedSource} = param; - async function doCreateVersionRoutes(): Promise { - const versionMetadata = toVersionMetadataProp(options.id, version); - const versionMetadataPropPath = await actions.createData( - `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`, - JSON.stringify(versionMetadata, null, 2), - ); - async function createVersionSubRoutes() { - const [docRoutes, sidebarsRoutes] = await Promise.all([ + async function createVersionSubRoutes() { + const [docRoutes, categoryGeneratedIndexRoutes, tagsRoutes] = + await Promise.all([ createVersionDocRoutes(param), - createVersionCategoryGeneratedIndexRoutes(param), + buildVersionCategoryGeneratedIndexRoutes(param), + buildVersionTagsRoutes(param), ]); - const routes = [...docRoutes, ...sidebarsRoutes]; - return routes.sort((a, b) => a.path.localeCompare(b.path)); - } + const routes = [ + ...docRoutes, + ...categoryGeneratedIndexRoutes, + ...tagsRoutes, + ]; + return routes.sort((a, b) => a.path.localeCompare(b.path)); + } - actions.addRoute({ + async function doBuildVersionRoutes(): Promise { + const versionMetadata = toVersionMetadataProp(options.id, version); + const versionMetadataPropPath = await actions.createData( + `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`, + JSON.stringify(versionMetadata, null, 2), + ); + return { path: version.path, // Allow matching /docs/* since this is the wrapping route exact: false, @@ -126,26 +191,56 @@ async function createVersionRoutes( versionMetadata: aliasedSource(versionMetadataPropPath), }, priority: version.routePriority, - }); + }; } try { - return await doCreateVersionRoutes(); + return doBuildVersionRoutes(); } catch (err) { logger.error`Can't create version routes for version name=${version.versionName}`; throw err; } } -async function createVersionsRoutes(param: CreateAllRoutesParam) { - await Promise.all( +async function buildVersionsRoutes( + param: BuildAllRoutesParam, +): Promise { + return Promise.all( + param.versions.map((version) => + buildVersionRoutes({ + ...param, + version, + }), + ), + ); +} + +type BuildAllRoutesParam = { + versions: FullVersion[]; + options: PluginOptions; + actions: Omit; + aliasedSource: (str: string) => string; +}; + +// TODO we want this build function to be easily testable +// Ideally, we should avoid side effects here (ie not injecting actions) +export async function buildAllRoutes( + param: BuildAllRoutesParam, +): Promise { + const versionRoutes = Promise.all( param.versions.map((version) => - createVersionRoutes({ + buildVersionRoutes({ ...param, version, }), ), ); + + // TODO do we want to wrap all versions under a single parent component? + // ie have a "root docs root" at the very top? + // could be convenient to register a global docs plugin provider? + + return versionRoutes; } type CreateAllRoutesParam = { @@ -158,66 +253,6 @@ type CreateAllRoutesParam = { export async function createAllRoutes( param: CreateAllRoutesParam, ): Promise { - const {versions, options, actions, aliasedSource} = param; - const {addRoute, createData} = actions; - - async function createVersionTagsRoutes(version: FullVersion) { - const versionTags = getVersionTags(version.docs); - - // TODO tags should be a sub route of the version route - async function createTagsListPage() { - const tagsProp: PropTagsListPage['tags'] = Object.values(versionTags).map( - (tagValue) => ({ - label: tagValue.label, - permalink: tagValue.permalink, - count: tagValue.docIds.length, - }), - ); - - // Only create /tags page if there are tags. - if (tagsProp.length > 0) { - const tagsPropPath = await createData( - `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, - JSON.stringify(tagsProp, null, 2), - ); - addRoute({ - path: version.tagsPath, - exact: true, - component: options.docTagsListComponent, - modules: { - tags: aliasedSource(tagsPropPath), - }, - }); - } - } - - // TODO tags should be a sub route of the version route - async function createTagDocListPage(tag: VersionTag) { - const tagProps = toTagDocListProp({ - allTagsPath: version.tagsPath, - tag, - docs: version.docs, - }); - const tagPropPath = await createData( - `${docuHash(`tag-${tag.permalink}`)}.json`, - JSON.stringify(tagProps, null, 2), - ); - addRoute({ - path: tag.permalink, - component: options.docTagDocListComponent, - exact: true, - modules: { - tag: aliasedSource(tagPropPath), - }, - }); - } - - await createTagsListPage(); - await Promise.all(Object.values(versionTags).map(createTagDocListPage)); - } - - await createVersionsRoutes(param); - - // TODO tags should be a sub route of the version route - await Promise.all(versions.map(createVersionTagsRoutes)); + const versionRoutes = await buildVersionsRoutes(param); + versionRoutes.forEach((versionRoute) => param.actions.addRoute(versionRoute)); } From 03cc6830d18ecb02f920d190612020ab9e197bfe Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 17 Aug 2022 19:51:01 +0200 Subject: [PATCH 03/15] fix routeConfig algo not recursive --- .../__snapshots__/routeConfig.test.ts.snap | 42 +++++++++++++++++ .../plugins/__tests__/routeConfig.test.ts | 46 +++++++++++++++++++ .../src/server/plugins/routeConfig.ts | 4 +- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap index e38931b90952..9d4fb06e800a 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap @@ -103,3 +103,45 @@ exports[`sortConfig sorts route config given a baseURL 1`] = ` }, ] `; + +exports[`sortConfig sorts route config recursively 1`] = ` +[ + { + "component": "", + "exact": true, + "path": "/some/page", + }, + { + "component": "", + "path": "/docs", + "routes": [ + { + "component": "", + "exact": true, + "path": "/docs/tags", + }, + { + "component": "", + "exact": true, + "path": "/docs/tags/someTag", + }, + { + "component": "", + "path": "/docs", + "routes": [ + { + "component": "", + "exact": true, + "path": "/docs/doc1", + }, + { + "component": "", + "exact": true, + "path": "/docs/doc2", + }, + ], + }, + ], + }, +] +`; diff --git a/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts b/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts index 3d0e6a5a8ec7..64c8034eb520 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts @@ -207,6 +207,52 @@ describe('sortConfig', () => { expect(routes).toMatchSnapshot(); }); + it('sorts route config recursively', () => { + const routes: RouteConfig[] = [ + { + path: '/docs', + component: '', + routes: [ + { + path: '/docs/tags', + component: '', + exact: true, + }, + { + path: '/docs', + component: '', + routes: [ + { + path: '/docs/doc1', + component: '', + exact: true, + }, + { + path: '/docs/doc2', + component: '', + exact: true, + }, + ], + }, + { + path: '/docs/tags/someTag', + component: '', + exact: true, + }, + ], + }, + { + path: '/some/page', + component: '', + exact: true, + }, + ]; + + sortConfig(routes); + + expect(routes).toMatchSnapshot(); + }); + it('sorts route config given a baseURL', () => { const baseURL = '/latest/'; const routes: RouteConfig[] = [ diff --git a/packages/docusaurus/src/server/plugins/routeConfig.ts b/packages/docusaurus/src/server/plugins/routeConfig.ts index 3731eb993d74..d757406bd09b 100644 --- a/packages/docusaurus/src/server/plugins/routeConfig.ts +++ b/packages/docusaurus/src/server/plugins/routeConfig.ts @@ -63,6 +63,8 @@ export function sortConfig( }); routeConfigs.forEach((routeConfig) => { - routeConfig.routes?.sort((a, b) => a.path.localeCompare(b.path)); + if (routeConfig.routes) { + sortConfig(routeConfig.routes, baseUrl); + } }); } From f5607240082467b4c246142ec6e3c82e3432cf01 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 17 Aug 2022 19:56:54 +0200 Subject: [PATCH 04/15] stable refactor --- .../__snapshots__/index.test.ts.snap | 750 ++++++++++-------- .../src/__tests__/options.test.ts | 1 + .../src/options.ts | 4 + .../src/plugin-content-docs.d.ts | 28 +- .../src/routes.ts | 56 +- .../src/theme/DocPage/Layout/index.tsx | 5 +- .../src/theme/DocPage/index.tsx | 51 +- .../src/theme/DocTagDocListPage/index.tsx | 94 ++- .../src/theme/DocTagsListPage/index.tsx | 49 +- .../src/theme/DocVersionPage/index.tsx | 60 ++ .../src/utils/ThemeClassNames.ts | 3 + .../src/utils/docsUtils.tsx | 6 +- 12 files changed, 628 insertions(+), 479 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index a047b9eac4df..e0339c1b45d9 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1243,175 +1243,14 @@ exports[`simple website content: global data 1`] = ` exports[`simple website content: route config 1`] = ` [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-current-metadata-prop-751.json", + "version": "~docs/version-current-metadata-prop-751.json", }, "path": "/docs", "priority": -1, "routes": [ - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/hello.md", - }, - "path": "/docs/", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/absoluteSlug.md", - }, - "path": "/docs/absoluteSlug", - }, - { - "component": "@theme/DocCategoryGeneratedIndexPage", - "exact": true, - "modules": { - "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", - }, - "path": "/docs/category/slugs", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/customLastUpdate.md", - }, - "path": "/docs/customLastUpdate", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/doc with space.md", - }, - "path": "/docs/doc with space", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/doc-draft.md", - }, - "path": "/docs/doc-draft", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/foo/bar.md", - }, - "path": "/docs/foo/bar", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/foo/baz.md", - }, - "path": "/docs/foo/bazSlug.html", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/headingAsTitle.md", - }, - "path": "/docs/headingAsTitle", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootResolvedSlug.md", - }, - "path": "/docs/hey/rootResolvedSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/ipsum.md", - }, - "path": "/docs/ipsum", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lastUpdateAuthorOnly.md", - }, - "path": "/docs/lastUpdateAuthorOnly", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lastUpdateDateOnly.md", - }, - "path": "/docs/lastUpdateDateOnly", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lorem.md", - }, - "path": "/docs/lorem", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootAbsoluteSlug.md", - }, - "path": "/docs/rootAbsoluteSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootRelativeSlug.md", - }, - "path": "/docs/rootRelativeSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootTryToEscapeSlug.md", - }, - "path": "/docs/rootTryToEscapeSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/resolvedSlug.md", - }, - "path": "/docs/slugs/hey/resolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/relativeSlug.md", - }, - "path": "/docs/slugs/relativeSlug", - }, { "component": "@theme/DocTagsListPage", "exact": true, @@ -1445,12 +1284,181 @@ exports[`simple website content: route config 1`] = ` "path": "/docs/tags/tag2-custom-permalink", }, { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/tryToEscapeSlug", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/docs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/hello.md", + }, + "path": "/docs/", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/absoluteSlug.md", + }, + "path": "/docs/absoluteSlug", + }, + { + "component": "@theme/DocCategoryGeneratedIndexPage", + "exact": true, + "modules": { + "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", + }, + "path": "/docs/category/slugs", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/customLastUpdate.md", + }, + "path": "/docs/customLastUpdate", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/doc with space.md", + }, + "path": "/docs/doc with space", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/doc-draft.md", + }, + "path": "/docs/doc-draft", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/bar.md", + }, + "path": "/docs/foo/bar", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/baz.md", + }, + "path": "/docs/foo/bazSlug.html", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/headingAsTitle.md", + }, + "path": "/docs/headingAsTitle", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootResolvedSlug.md", + }, + "path": "/docs/hey/rootResolvedSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/ipsum.md", + }, + "path": "/docs/ipsum", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lastUpdateAuthorOnly.md", + }, + "path": "/docs/lastUpdateAuthorOnly", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lastUpdateDateOnly.md", + }, + "path": "/docs/lastUpdateDateOnly", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lorem.md", + }, + "path": "/docs/lorem", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootAbsoluteSlug.md", + }, + "path": "/docs/rootAbsoluteSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootRelativeSlug.md", + }, + "path": "/docs/rootRelativeSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootTryToEscapeSlug.md", + }, + "path": "/docs/rootTryToEscapeSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/resolvedSlug.md", + }, + "path": "/docs/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/relativeSlug.md", + }, + "path": "/docs/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/tryToEscapeSlug", + }, + ], }, ], }, @@ -2724,42 +2732,58 @@ exports[`versioned website (community) content: global data 1`] = ` exports[`versioned website (community) content: route config 1`] = ` [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-current-metadata-prop-751.json", + "version": "~docs/version-current-metadata-prop-751.json", }, "path": "/community/next", "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", - }, - "path": "/community/next/team", - "sidebar": "community", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/community/next", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", + }, + "path": "/community/next/team", + "sidebar": "community", + }, + ], }, ], }, { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-1-0-0-metadata-prop-608.json", + "version": "~docs/version-1-0-0-metadata-prop-608.json", }, "path": "/community", "priority": -1, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/community_versioned_docs/version-1.0.0/team.md", - }, - "path": "/community/team", - "sidebar": "version-1.0.0/community", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/community", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/community_versioned_docs/version-1.0.0/team.md", + }, + "path": "/community/team", + "sidebar": "version-1.0.0/community", + }, + ], }, ], }, @@ -3931,94 +3955,60 @@ exports[`versioned website content: global data 1`] = ` exports[`versioned website content: route config 1`] = ` [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-1-0-0-metadata-prop-608.json", + "version": "~docs/version-1-0-0-metadata-prop-608.json", }, "path": "/docs/1.0.0", "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", - }, - "path": "/docs/1.0.0/", - "sidebar": "version-1.0.0/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.0/foo/bar.md", - }, - "path": "/docs/1.0.0/foo/barSlug", - "sidebar": "version-1.0.0/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.0/foo/baz.md", - }, - "path": "/docs/1.0.0/foo/baz", - "sidebar": "version-1.0.0/docs", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/docs/1.0.0", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", + }, + "path": "/docs/1.0.0/", + "sidebar": "version-1.0.0/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.0/foo/bar.md", + }, + "path": "/docs/1.0.0/foo/barSlug", + "sidebar": "version-1.0.0/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.0/foo/baz.md", + }, + "path": "/docs/1.0.0/foo/baz", + "sidebar": "version-1.0.0/docs", + }, + ], }, ], }, { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-current-metadata-prop-751.json", + "version": "~docs/version-current-metadata-prop-751.json", }, "path": "/docs/next", "priority": undefined, "routes": [ - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/hello.md", - }, - "path": "/docs/next/", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/absoluteSlug.md", - }, - "path": "/docs/next/absoluteSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/foo/bar.md", - }, - "path": "/docs/next/foo/barSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/resolvedSlug.md", - }, - "path": "/docs/next/slugs/hey/resolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/relativeSlug.md", - }, - "path": "/docs/next/slugs/relativeSlug", - }, { "component": "@theme/DocTagsListPage", "exact": true, @@ -4052,117 +4042,183 @@ exports[`versioned website content: route config 1`] = ` "path": "/docs/next/tags/barTag-3-permalink", }, { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/next/tryToEscapeSlug", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/docs/next", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/hello.md", + }, + "path": "/docs/next/", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/absoluteSlug.md", + }, + "path": "/docs/next/absoluteSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/bar.md", + }, + "path": "/docs/next/foo/barSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/resolvedSlug.md", + }, + "path": "/docs/next/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/relativeSlug.md", + }, + "path": "/docs/next/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/next/tryToEscapeSlug", + }, + ], }, ], }, { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-with-slugs-metadata-prop-2bf.json", + "version": "~docs/version-with-slugs-metadata-prop-2bf.json", }, "path": "/docs/withSlugs", "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", - }, - "path": "/docs/withSlugs/absoluteSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", - }, - "path": "/docs/withSlugs/hey/rootResolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", - }, - "path": "/docs/withSlugs/rootAbsoluteSlug", - "sidebar": "version-1.0.1/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", - }, - "path": "/docs/withSlugs/rootRelativeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", - }, - "path": "/docs/withSlugs/rootTryToEscapeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", - }, - "path": "/docs/withSlugs/slugs/hey/resolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", - }, - "path": "/docs/withSlugs/slugs/relativeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/withSlugs/tryToEscapeSlug", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/docs/withSlugs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", + }, + "path": "/docs/withSlugs/absoluteSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", + }, + "path": "/docs/withSlugs/hey/rootResolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", + }, + "path": "/docs/withSlugs/rootAbsoluteSlug", + "sidebar": "version-1.0.1/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", + }, + "path": "/docs/withSlugs/rootRelativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", + }, + "path": "/docs/withSlugs/rootTryToEscapeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", + }, + "path": "/docs/withSlugs/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", + }, + "path": "/docs/withSlugs/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/withSlugs/tryToEscapeSlug", + }, + ], }, ], }, { - "component": "@theme/DocPage", + "component": "@theme/DocVersionPage", "exact": false, "modules": { - "versionMetadata": "~docs/version-1-0-1-metadata-prop-e87.json", + "version": "~docs/version-1-0-1-metadata-prop-e87.json", }, "path": "/docs", "priority": -1, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.1/hello.md", - }, - "path": "/docs/", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.1/foo/bar.md", - }, - "path": "/docs/foo/bar", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "component": "@theme/DocPage", + "exact": false, + "modules": {}, + "path": "/docs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.1/hello.md", + }, + "path": "/docs/", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.1/foo/bar.md", + }, + "path": "/docs/foo/bar", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + }, + ], }, ], }, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 0cfa5aa02637..2bc952d8f30d 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -49,6 +49,7 @@ describe('normalizeDocsPluginOptions', () => { sidebarPath: 'my-sidebar', // Path to sidebar configuration for showing a list of markdown pages. sidebarItemsGenerator: DefaultSidebarItemsGenerator, numberPrefixParser: DefaultNumberPrefixParser, + docVersionLayoutComponent: '@theme/DocVersionPage', docLayoutComponent: '@theme/DocPage', docItemComponent: '@theme/DocItem', docTagDocListComponent: '@theme/DocTagDocListPage', diff --git a/packages/docusaurus-plugin-content-docs/src/options.ts b/packages/docusaurus-plugin-content-docs/src/options.ts index 7ef8c417a65d..dfa786cca262 100644 --- a/packages/docusaurus-plugin-content-docs/src/options.ts +++ b/packages/docusaurus-plugin-content-docs/src/options.ts @@ -30,6 +30,7 @@ export const DEFAULT_OPTIONS: Omit = { exclude: GlobExcludeDefault, sidebarItemsGenerator: DefaultSidebarItemsGenerator, numberPrefixParser: DefaultNumberPrefixParser, + docVersionLayoutComponent: '@theme/DocVersionPage', docLayoutComponent: '@theme/DocPage', docItemComponent: '@theme/DocItem', docTagDocListComponent: '@theme/DocTagDocListPage', @@ -104,6 +105,9 @@ const OptionsSchema = Joi.object({ }), ) .default(() => DEFAULT_OPTIONS.numberPrefixParser), + docVersionLayoutComponent: Joi.string().default( + DEFAULT_OPTIONS.docVersionLayoutComponent, + ), docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent), docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent), docTagsListComponent: Joi.string().default( diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 7bd8bbf3cbf0..6329f0ec7261 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -198,8 +198,19 @@ declare module '@docusaurus/plugin-content-docs' { */ exclude: string[]; /** - * Root layout component of each doc page. Provides the version data - * context, and is not unmounted when switching docs. + * Parent layout component of all versioned pages including: + * - docs pages with sidebars + * - tags pages + * Stays mounted when navigation between such pages. + * Provides the version data in context. + */ + docVersionLayoutComponent: string; + /** + * Parent layout component of doc page with sidebars: + * - regular docs pages + * - category generated index pages + * Stays mounted when navigation between such pages. + * Provides the sidebar data in context. */ docLayoutComponent: string; /** Main doc container, with TOC, pagination, etc. */ @@ -610,14 +621,23 @@ declare module '@theme/DocBreadcrumbs' { export default function DocBreadcrumbs(): JSX.Element; } -declare module '@theme/DocPage' { +declare module '@theme/DocVersionPage' { import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs'; import type {RouteConfigComponentProps} from 'react-router-config'; import type {Required} from 'utility-types'; export interface Props extends Required { - readonly versionMetadata: PropVersionMetadata; + readonly version: PropVersionMetadata; } export default function DocPage(props: Props): JSX.Element; } + +declare module '@theme/DocPage' { + import type {RouteConfigComponentProps} from 'react-router-config'; + import type {Required} from 'utility-types'; + + export interface Props extends Required {} + + export default function DocPage(props: Props): JSX.Element; +} diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index 0d083bae002e..f762e9ad9835 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -22,6 +22,12 @@ import type { PropTagsListPage, } from '@docusaurus/plugin-content-docs'; +function sortRoutes(routes: RouteConfig[]): RouteConfig[] { + const result = [...routes]; + result.sort((a, b) => a.path.localeCompare(b.path)); + return result; +} + async function buildVersionCategoryGeneratedIndexRoutes({ version, actions, @@ -62,7 +68,7 @@ async function buildVersionCategoryGeneratedIndexRoutes({ ); } -async function createVersionDocRoutes({ +async function buildVersionDocRoutes({ version, actions, options, @@ -96,6 +102,21 @@ async function createVersionDocRoutes({ ); } +async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) { + const [docRoutes, categoryGeneratedIndexRoutes] = await Promise.all([ + buildVersionDocRoutes(param), + buildVersionCategoryGeneratedIndexRoutes(param), + ]); + const subRoutes = sortRoutes([...docRoutes, ...categoryGeneratedIndexRoutes]); + return { + path: param.version.path, + exact: false, + component: param.options.docLayoutComponent, + routes: subRoutes, + modules: {}, + }; +} + async function buildVersionTagsRoutes( param: BuildVersionRoutesParam, ): Promise { @@ -159,36 +180,29 @@ async function buildVersionRoutes( ): Promise { const {version, actions, options, aliasedSource} = param; - async function createVersionSubRoutes() { - const [docRoutes, categoryGeneratedIndexRoutes, tagsRoutes] = - await Promise.all([ - createVersionDocRoutes(param), - buildVersionCategoryGeneratedIndexRoutes(param), - buildVersionTagsRoutes(param), - ]); + async function buildVersionSubRoutes() { + const [sidebarRoute, tagsRoutes] = await Promise.all([ + buildVersionSidebarRoute(param), + buildVersionTagsRoutes(param), + ]); - const routes = [ - ...docRoutes, - ...categoryGeneratedIndexRoutes, - ...tagsRoutes, - ]; - return routes.sort((a, b) => a.path.localeCompare(b.path)); + return [sidebarRoute, ...tagsRoutes]; } async function doBuildVersionRoutes(): Promise { - const versionMetadata = toVersionMetadataProp(options.id, version); - const versionMetadataPropPath = await actions.createData( + const versionProp = toVersionMetadataProp(options.id, version); + const versionPropPath = await actions.createData( `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`, - JSON.stringify(versionMetadata, null, 2), + JSON.stringify(versionProp, null, 2), ); + const subRoutes = await buildVersionSubRoutes(); return { path: version.path, - // Allow matching /docs/* since this is the wrapping route exact: false, - component: options.docLayoutComponent, - routes: await createVersionSubRoutes(), + component: options.docVersionLayoutComponent, + routes: subRoutes, modules: { - versionMetadata: aliasedSource(versionMetadataPropPath), + version: aliasedSource(versionPropPath), }, priority: version.routePriority, }; diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx index 0ff53b286d16..b41d7890f580 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx @@ -7,7 +7,6 @@ import React, {useState} from 'react'; import {useDocsSidebar} from '@docusaurus/theme-common/internal'; -import Layout from '@theme/Layout'; import BackToTopButton from '@theme/BackToTopButton'; import DocPageLayoutSidebar from '@theme/DocPage/Layout/Sidebar'; import DocPageLayoutMain from '@theme/DocPage/Layout/Main'; @@ -19,7 +18,7 @@ export default function DocPageLayout({children}: Props): JSX.Element { const sidebar = useDocsSidebar(); const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); return ( - +
{sidebar && ( @@ -33,6 +32,6 @@ export default function DocPageLayout({children}: Props): JSX.Element { {children}
- +
); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index 61a289c30f3d..3a38c528438d 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -7,65 +7,26 @@ import React from 'react'; import clsx from 'clsx'; +import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common'; import { - HtmlClassNameProvider, - ThemeClassNames, - PageMetadata, -} from '@docusaurus/theme-common'; -import { - docVersionSearchTag, DocsSidebarProvider, - DocsVersionProvider, useDocRouteMetadata, } from '@docusaurus/theme-common/internal'; import DocPageLayout from '@theme/DocPage/Layout'; import NotFound from '@theme/NotFound'; -import SearchMetadata from '@theme/SearchMetadata'; import type {Props} from '@theme/DocPage'; -function DocPageMetadata(props: Props): JSX.Element { - const {versionMetadata} = props; - return ( - <> - - - {versionMetadata.noIndex && ( - - )} - - - ); -} - export default function DocPage(props: Props): JSX.Element { - const {versionMetadata} = props; const currentDocRouteMetadata = useDocRouteMetadata(props); if (!currentDocRouteMetadata) { return ; } const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata; return ( - <> - - - - - {docElement} - - - - + + + {docElement} + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx index a928644a9bd6..f32b32ffdba4 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx @@ -15,7 +15,6 @@ import { usePluralForm, } from '@docusaurus/theme-common'; import Translate, {translate} from '@docusaurus/Translate'; -import Layout from '@theme/Layout'; import SearchMetadata from '@theme/SearchMetadata'; import type {Props} from '@theme/DocTagDocListPage'; @@ -37,6 +36,18 @@ function useNDocsTaggedPlural() { ); } +function usePageTitle(props: Props): string { + const nDocsTaggedPlural = useNDocsTaggedPlural(); + return translate( + { + id: 'theme.docs.tagDocListPageTitle', + description: 'The title of the page for a docs tag', + message: '{nDocsTagged} with "{tagName}"', + }, + {nDocsTagged: nDocsTaggedPlural(props.tag.count), tagName: props.tag.label}, + ); +} + function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element { return (
@@ -48,48 +59,55 @@ function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element { ); } -export default function DocTagDocListPage({tag}: Props): JSX.Element { - const nDocsTaggedPlural = useNDocsTaggedPlural(); - const title = translate( - { - id: 'theme.docs.tagDocListPageTitle', - description: 'The title of the page for a docs tag', - message: '{nDocsTagged} with "{tagName}"', - }, - {nDocsTagged: nDocsTaggedPlural(tag.count), tagName: tag.label}, +function DocTagDocListPageMetadata({ + title, +}: Props & {title: string}): JSX.Element { + return ( + <> + + + ); +} +function DocTagDocListPageContent({ + tag, + title, +}: Props & {title: string}): JSX.Element { return ( - - - -
-
-
-
-

{title}

- - - View All Tags - - -
-
- {tag.items.map((doc) => ( - - ))} -
-
-
+ className={clsx(ThemeClassNames.page.docsTagDocListPage)}> +
+
+
+
+

{title}

+ + + View All Tags + + +
+
+ {tag.items.map((doc) => ( + + ))} +
+
- +
); } + +export default function DocTagDocListPage(props: Props): JSX.Element { + const title = usePageTitle(props); + return ( + <> + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx index e848128fedf0..5603797ab6bf 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx @@ -13,31 +13,46 @@ import { ThemeClassNames, translateTagsPageTitle, } from '@docusaurus/theme-common'; -import Layout from '@theme/Layout'; import TagsListByLetter from '@theme/TagsListByLetter'; import SearchMetadata from '@theme/SearchMetadata'; import type {Props} from '@theme/DocTagsListPage'; -export default function DocTagsListPage({tags}: Props): JSX.Element { - const title = translateTagsPageTitle(); +function DocTagsListPageMetadata({ + title, +}: Props & {title: string}): JSX.Element { return ( - + <> - -
-
-
-

{title}

- -
-
+ + ); +} + +function DocTagsListPageContent({ + tags, + title, +}: Props & {title: string}): JSX.Element { + return ( + +
+
+
+

{title}

+ +
- +
); } + +export default function DocTagsListPage(props: Props): JSX.Element { + const title = translateTagsPageTitle(); + return ( + <> + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx new file mode 100644 index 000000000000..17b5a2ffcccc --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx @@ -0,0 +1,60 @@ +/** + * 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 React from 'react'; +import clsx from 'clsx'; +import { + ThemeClassNames, + HtmlClassNameProvider, + PageMetadata, +} from '@docusaurus/theme-common'; +import { + docVersionSearchTag, + DocsVersionProvider, +} from '@docusaurus/theme-common/internal'; +import renderRoutes from '@docusaurus/renderRoutes'; +import SearchMetadata from '@theme/SearchMetadata'; +import Layout from '@theme/Layout'; + +import type {Props} from '@theme/DocVersionPage'; + +function DocVersionPageMetadata(props: Props): JSX.Element { + const {version} = props; + return ( + <> + + + {version.noIndex && } + + + ); +} + +function DocVersionPageContent(props: Props): JSX.Element { + const {version, route} = props; + return ( + + + + {renderRoutes(route.routes!)} + + + + ); +} +export default function DocVersionPage(props: Props): JSX.Element { + return ( + <> + + + + ); +} diff --git a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts index 9b4623214b6f..8f82f5213bbb 100644 --- a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts +++ b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts @@ -27,6 +27,9 @@ export const ThemeClassNames = { }, wrapper: { main: 'main-wrapper', + // TODO these wrapper class names are now quite useless + // TODO do breaking change later in 3.0 + // we already add plugin name/id class on : that's enough blogPages: 'blog-wrapper', docsPages: 'docs-wrapper', mdxPages: 'mdx-wrapper', diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 7ce3222df3e1..7825d8aa3c38 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -294,10 +294,7 @@ Available doc ids are: * @returns The data of the relevant document at the current location, or `null` * if no document associated with the current location can be found. */ -export function useDocRouteMetadata({ - route, - versionMetadata, -}: DocPageProps): null | { +export function useDocRouteMetadata({route}: DocPageProps): null | { /** The element that should be rendered at the current location. */ docElement: JSX.Element; /** @@ -309,6 +306,7 @@ export function useDocRouteMetadata({ sidebarItems: PropSidebar | undefined; } { const location = useLocation(); + const versionMetadata = useDocsVersion(); const docRoutes = route.routes!; const currentDocRoute = docRoutes.find((docRoute) => matchPath(location.pathname, docRoute), From 925495ad09684977a2831924a6449dcc9367bd03 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 10:41:28 +0200 Subject: [PATCH 05/15] prettier --- packages/docusaurus-plugin-content-docs/src/versions/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-docs/src/versions/index.ts b/packages/docusaurus-plugin-content-docs/src/versions/index.ts index 473cbc8e3cba..f9be8149a853 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions/index.ts @@ -18,7 +18,8 @@ import {createSidebarsUtils} from '../sidebars/utils'; import {getCategoryGeneratedIndexMetadataList} from '../categoryGeneratedIndex'; import type {FullVersion} from '../types'; import type {LoadContext} from '@docusaurus/types'; -import type {LoadedVersion, +import type { + LoadedVersion, PluginOptions, VersionBanner, VersionMetadata, From 5878a16f8426b19c3659871e3db0bafd4f505c66 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 10:54:12 +0200 Subject: [PATCH 06/15] update doc --- .../src/plugin-content-docs.d.ts | 6 ++---- website/docs/api/plugins/plugin-content-docs.md | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 6329f0ec7261..80d15acefeb5 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -198,19 +198,17 @@ declare module '@docusaurus/plugin-content-docs' { */ exclude: string[]; /** - * Parent layout component of all versioned pages including: + * Parent layout component of all versioned docs pages: * - docs pages with sidebars * - tags pages * Stays mounted when navigation between such pages. - * Provides the version data in context. */ docVersionLayoutComponent: string; /** - * Parent layout component of doc page with sidebars: + * Parent layout component of docs pages with sidebars: * - regular docs pages * - category generated index pages * Stays mounted when navigation between such pages. - * Provides the sidebar data in context. */ docLayoutComponent: string; /** Main doc container, with TOC, pagination, etc. */ diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index 6e60b02e9176..a6b4bed6acef 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -46,7 +46,8 @@ Accepted fields: | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) | | `sidebarItemsGenerator` | SidebarGenerator | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` with real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | | `numberPrefixParser` | boolean \| PrefixParser | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) | -| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root layout component of each doc page. Provides the version data context, and is not unmounted when switching docs. | +| `docVersionLayoutComponent` | `string` | `'@theme/DocPage'` | Parent layout component of all versioned docs pages (doc pages with sidebars, tags pages). Stays mounted when navigation between such pages. | +| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Parent layout component of all doc pages with sidebars (regular docs pages, category generated index pages). Stays mounted when navigation between such pages. | | `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. | | `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page | | `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag X" page. | From e5b60b331790892f453c10466d5ad624091ef805 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 11:01:23 +0200 Subject: [PATCH 07/15] remove useless sortRoutes --- packages/docusaurus-plugin-content-docs/src/routes.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index f762e9ad9835..315bc4c5eb55 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -22,12 +22,6 @@ import type { PropTagsListPage, } from '@docusaurus/plugin-content-docs'; -function sortRoutes(routes: RouteConfig[]): RouteConfig[] { - const result = [...routes]; - result.sort((a, b) => a.path.localeCompare(b.path)); - return result; -} - async function buildVersionCategoryGeneratedIndexRoutes({ version, actions, @@ -107,7 +101,7 @@ async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) { buildVersionDocRoutes(param), buildVersionCategoryGeneratedIndexRoutes(param), ]); - const subRoutes = sortRoutes([...docRoutes, ...categoryGeneratedIndexRoutes]); + const subRoutes = [...docRoutes, ...categoryGeneratedIndexRoutes]; return { path: param.version.path, exact: false, From ac57a60c6bb9f4f1e8762c725bb2c6bf6d925919 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 11:03:11 +0200 Subject: [PATCH 08/15] add missing await useful for try/catch --- packages/docusaurus-plugin-content-docs/src/routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index 315bc4c5eb55..5deeed6ed3b7 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -203,7 +203,7 @@ async function buildVersionRoutes( } try { - return doBuildVersionRoutes(); + return await doBuildVersionRoutes(); } catch (err) { logger.error`Can't create version routes for version name=${version.versionName}`; throw err; From 2c5c28eff4e615c47beac020ab2d0f1b289da4ad Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 13:22:23 +0200 Subject: [PATCH 09/15] refactor plugin options and component names --- .../__snapshots__/index.test.ts.snap | 883 +++++++++--------- .../src/__tests__/options.test.ts | 5 +- .../src/index.ts | 1 + .../src/options.ts | 12 +- .../src/plugin-content-docs.d.ts | 30 +- .../src/routes.ts | 49 +- .../src/theme-classic.d.ts | 16 +- .../Layout/Main/index.tsx | 4 +- .../Layout/Main/styles.module.css | 0 .../Layout/Sidebar/ExpandButton/index.tsx | 4 +- .../Sidebar/ExpandButton/styles.module.css | 0 .../Layout/Sidebar/index.tsx | 6 +- .../Layout/Sidebar/styles.module.css | 0 .../{DocPage => DocRoot}/Layout/index.tsx | 16 +- .../Layout/styles.module.css | 2 +- .../src/theme/{DocPage => DocRoot}/index.tsx | 12 +- .../index.tsx | 33 +- .../src/theme/DocsRoot/index.tsx | 22 + .../docusaurus-theme-common/src/internal.ts | 2 +- .../src/utils/docsUtils.tsx | 6 +- .../src/server/__tests__/routes.test.ts | 2 +- .../docs/api/plugins/plugin-content-docs.md | 3 +- 22 files changed, 575 insertions(+), 533 deletions(-) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Main/index.tsx (89%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Main/styles.module.css (100%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Sidebar/ExpandButton/index.tsx (89%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Sidebar/ExpandButton/styles.module.css (100%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Sidebar/index.tsx (92%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/Sidebar/styles.module.css (100%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/index.tsx (68%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/Layout/styles.module.css (95%) rename packages/docusaurus-theme-classic/src/theme/{DocPage => DocRoot}/index.tsx (73%) rename packages/docusaurus-theme-classic/src/theme/{DocVersionPage => DocVersionRoot}/index.tsx (51%) create mode 100644 packages/docusaurus-theme-classic/src/theme/DocsRoot/index.tsx diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index e0339c1b45d9..53e7b6bfb87c 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1243,220 +1243,227 @@ exports[`simple website content: global data 1`] = ` exports[`simple website content: route config 1`] = ` [ { - "component": "@theme/DocVersionPage", + "component": "@theme/DocsRoot", "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, - "path": "/docs", - "priority": -1, + "path": "docs", "routes": [ { - "component": "@theme/DocTagsListPage", - "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, - "path": "/docs/tags", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-1-b3f.json", - }, - "path": "/docs/tags/tag-1", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-3-ab5.json", - }, - "path": "/docs/tags/tag-3", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, + "component": "@theme/DocVersionRoot", + "exact": false, "modules": { - "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", + "version": "~docs/version-current-metadata-prop-751.json", }, - "path": "/docs/tags/tag2-custom-permalink", - }, - { - "component": "@theme/DocPage", - "exact": false, - "modules": {}, "path": "/docs", + "priority": -1, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/hello.md", - }, - "path": "/docs/", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/absoluteSlug.md", - }, - "path": "/docs/absoluteSlug", - }, - { - "component": "@theme/DocCategoryGeneratedIndexPage", - "exact": true, - "modules": { - "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", - }, - "path": "/docs/category/slugs", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/customLastUpdate.md", - }, - "path": "/docs/customLastUpdate", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/doc with space.md", - }, - "path": "/docs/doc with space", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/doc-draft.md", - }, - "path": "/docs/doc-draft", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/foo/bar.md", - }, - "path": "/docs/foo/bar", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/foo/baz.md", - }, - "path": "/docs/foo/bazSlug.html", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/headingAsTitle.md", - }, - "path": "/docs/headingAsTitle", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootResolvedSlug.md", - }, - "path": "/docs/hey/rootResolvedSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/ipsum.md", - }, - "path": "/docs/ipsum", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lastUpdateAuthorOnly.md", - }, - "path": "/docs/lastUpdateAuthorOnly", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lastUpdateDateOnly.md", - }, - "path": "/docs/lastUpdateDateOnly", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/lorem.md", - }, - "path": "/docs/lorem", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/rootAbsoluteSlug.md", - }, - "path": "/docs/rootAbsoluteSlug", - "sidebar": "docs", - }, - { - "component": "@theme/DocItem", + "component": "@theme/DocTagsListPage", "exact": true, "modules": { - "content": "@site/docs/rootRelativeSlug.md", + "tags": "~docs/tags-list-current-prop-15a.json", }, - "path": "/docs/rootRelativeSlug", - "sidebar": "docs", + "path": "/docs/tags", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/rootTryToEscapeSlug.md", + "tag": "~docs/tag-docs-tags-tag-1-b3f.json", }, - "path": "/docs/rootTryToEscapeSlug", - "sidebar": "docs", + "path": "/docs/tags/tag-1", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/slugs/resolvedSlug.md", + "tag": "~docs/tag-docs-tags-tag-3-ab5.json", }, - "path": "/docs/slugs/hey/resolvedSlug", + "path": "/docs/tags/tag-3", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/slugs/relativeSlug.md", + "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", }, - "path": "/docs/slugs/relativeSlug", + "path": "/docs/tags/tag2-custom-permalink", }, { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/tryToEscapeSlug", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/docs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/hello.md", + }, + "path": "/docs/", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/absoluteSlug.md", + }, + "path": "/docs/absoluteSlug", + }, + { + "component": "@theme/DocCategoryGeneratedIndexPage", + "exact": true, + "modules": { + "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", + }, + "path": "/docs/category/slugs", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/customLastUpdate.md", + }, + "path": "/docs/customLastUpdate", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/doc with space.md", + }, + "path": "/docs/doc with space", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/doc-draft.md", + }, + "path": "/docs/doc-draft", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/bar.md", + }, + "path": "/docs/foo/bar", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/baz.md", + }, + "path": "/docs/foo/bazSlug.html", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/headingAsTitle.md", + }, + "path": "/docs/headingAsTitle", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootResolvedSlug.md", + }, + "path": "/docs/hey/rootResolvedSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/ipsum.md", + }, + "path": "/docs/ipsum", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lastUpdateAuthorOnly.md", + }, + "path": "/docs/lastUpdateAuthorOnly", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lastUpdateDateOnly.md", + }, + "path": "/docs/lastUpdateDateOnly", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/lorem.md", + }, + "path": "/docs/lorem", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootAbsoluteSlug.md", + }, + "path": "/docs/rootAbsoluteSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootRelativeSlug.md", + }, + "path": "/docs/rootRelativeSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/rootTryToEscapeSlug.md", + }, + "path": "/docs/rootTryToEscapeSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/resolvedSlug.md", + }, + "path": "/docs/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/relativeSlug.md", + }, + "path": "/docs/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/tryToEscapeSlug", + }, + ], }, ], }, @@ -2732,56 +2739,63 @@ exports[`versioned website (community) content: global data 1`] = ` exports[`versioned website (community) content: route config 1`] = ` [ { - "component": "@theme/DocVersionPage", + "component": "@theme/DocsRoot", "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, - "path": "/community/next", - "priority": undefined, + "path": "community", "routes": [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionRoot", "exact": false, - "modules": {}, + "modules": { + "version": "~docs/version-current-metadata-prop-751.json", + }, "path": "/community/next", + "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", - }, - "path": "/community/next/team", - "sidebar": "community", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/community/next", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", + }, + "path": "/community/next/team", + "sidebar": "community", + }, + ], }, ], }, - ], - }, - { - "component": "@theme/DocVersionPage", - "exact": false, - "modules": { - "version": "~docs/version-1-0-0-metadata-prop-608.json", - }, - "path": "/community", - "priority": -1, - "routes": [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionRoot", "exact": false, - "modules": {}, + "modules": { + "version": "~docs/version-1-0-0-metadata-prop-608.json", + }, "path": "/community", + "priority": -1, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/community_versioned_docs/version-1.0.0/team.md", - }, - "path": "/community/team", - "sidebar": "version-1.0.0/community", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/community", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/community_versioned_docs/version-1.0.0/team.md", + }, + "path": "/community/team", + "sidebar": "version-1.0.0/community", + }, + ], }, ], }, @@ -3955,268 +3969,275 @@ exports[`versioned website content: global data 1`] = ` exports[`versioned website content: route config 1`] = ` [ { - "component": "@theme/DocVersionPage", + "component": "@theme/DocsRoot", "exact": false, - "modules": { - "version": "~docs/version-1-0-0-metadata-prop-608.json", - }, - "path": "/docs/1.0.0", - "priority": undefined, + "path": "docs", "routes": [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionRoot", "exact": false, - "modules": {}, + "modules": { + "version": "~docs/version-1-0-0-metadata-prop-608.json", + }, "path": "/docs/1.0.0", + "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", - }, - "path": "/docs/1.0.0/", - "sidebar": "version-1.0.0/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.0/foo/bar.md", - }, - "path": "/docs/1.0.0/foo/barSlug", - "sidebar": "version-1.0.0/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.0/foo/baz.md", - }, - "path": "/docs/1.0.0/foo/baz", - "sidebar": "version-1.0.0/docs", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/docs/1.0.0", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", + }, + "path": "/docs/1.0.0/", + "sidebar": "version-1.0.0/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.0/foo/bar.md", + }, + "path": "/docs/1.0.0/foo/barSlug", + "sidebar": "version-1.0.0/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.0/foo/baz.md", + }, + "path": "/docs/1.0.0/foo/baz", + "sidebar": "version-1.0.0/docs", + }, + ], }, ], }, - ], - }, - { - "component": "@theme/DocVersionPage", - "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, - "path": "/docs/next", - "priority": undefined, - "routes": [ - { - "component": "@theme/DocTagsListPage", - "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, - "path": "/docs/next/tags", - }, { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", - }, - "path": "/docs/next/tags/bar-tag-1", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", - }, - "path": "/docs/next/tags/bar-tag-2", - }, - { - "component": "@theme/DocTagDocListPage", - "exact": true, + "component": "@theme/DocVersionRoot", + "exact": false, "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", + "version": "~docs/version-current-metadata-prop-751.json", }, - "path": "/docs/next/tags/barTag-3-permalink", - }, - { - "component": "@theme/DocPage", - "exact": false, - "modules": {}, "path": "/docs/next", + "priority": undefined, "routes": [ { - "component": "@theme/DocItem", + "component": "@theme/DocTagsListPage", "exact": true, "modules": { - "content": "@site/docs/hello.md", + "tags": "~docs/tags-list-current-prop-15a.json", }, - "path": "/docs/next/", - "sidebar": "docs", + "path": "/docs/next/tags", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/slugs/absoluteSlug.md", + "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", }, - "path": "/docs/next/absoluteSlug", + "path": "/docs/next/tags/bar-tag-1", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/foo/bar.md", + "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", }, - "path": "/docs/next/foo/barSlug", - "sidebar": "docs", + "path": "/docs/next/tags/bar-tag-2", }, { - "component": "@theme/DocItem", + "component": "@theme/DocTagDocListPage", "exact": true, "modules": { - "content": "@site/docs/slugs/resolvedSlug.md", + "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", }, - "path": "/docs/next/slugs/hey/resolvedSlug", + "path": "/docs/next/tags/barTag-3-permalink", }, { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/relativeSlug.md", - }, - "path": "/docs/next/slugs/relativeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/docs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/next/tryToEscapeSlug", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/docs/next", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/hello.md", + }, + "path": "/docs/next/", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/absoluteSlug.md", + }, + "path": "/docs/next/absoluteSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/foo/bar.md", + }, + "path": "/docs/next/foo/barSlug", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/resolvedSlug.md", + }, + "path": "/docs/next/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/relativeSlug.md", + }, + "path": "/docs/next/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/next/tryToEscapeSlug", + }, + ], }, ], }, - ], - }, - { - "component": "@theme/DocVersionPage", - "exact": false, - "modules": { - "version": "~docs/version-with-slugs-metadata-prop-2bf.json", - }, - "path": "/docs/withSlugs", - "priority": undefined, - "routes": [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionRoot", "exact": false, - "modules": {}, + "modules": { + "version": "~docs/version-with-slugs-metadata-prop-2bf.json", + }, "path": "/docs/withSlugs", + "priority": undefined, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", - }, - "path": "/docs/withSlugs/absoluteSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", - }, - "path": "/docs/withSlugs/hey/rootResolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", - }, - "path": "/docs/withSlugs/rootAbsoluteSlug", - "sidebar": "version-1.0.1/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", - }, - "path": "/docs/withSlugs/rootRelativeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", - }, - "path": "/docs/withSlugs/rootTryToEscapeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", - }, - "path": "/docs/withSlugs/slugs/hey/resolvedSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", - }, - "path": "/docs/withSlugs/slugs/relativeSlug", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", - }, - "path": "/docs/withSlugs/tryToEscapeSlug", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/docs/withSlugs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", + }, + "path": "/docs/withSlugs/absoluteSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", + }, + "path": "/docs/withSlugs/hey/rootResolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", + }, + "path": "/docs/withSlugs/rootAbsoluteSlug", + "sidebar": "version-1.0.1/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", + }, + "path": "/docs/withSlugs/rootRelativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", + }, + "path": "/docs/withSlugs/rootTryToEscapeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", + }, + "path": "/docs/withSlugs/slugs/hey/resolvedSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", + }, + "path": "/docs/withSlugs/slugs/relativeSlug", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", + }, + "path": "/docs/withSlugs/tryToEscapeSlug", + }, + ], }, ], }, - ], - }, - { - "component": "@theme/DocVersionPage", - "exact": false, - "modules": { - "version": "~docs/version-1-0-1-metadata-prop-e87.json", - }, - "path": "/docs", - "priority": -1, - "routes": [ { - "component": "@theme/DocPage", + "component": "@theme/DocVersionRoot", "exact": false, - "modules": {}, + "modules": { + "version": "~docs/version-1-0-1-metadata-prop-e87.json", + }, "path": "/docs", + "priority": -1, "routes": [ { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.1/hello.md", - }, - "path": "/docs/", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - }, - { - "component": "@theme/DocItem", - "exact": true, - "modules": { - "content": "@site/versioned_docs/version-1.0.1/foo/bar.md", - }, - "path": "/docs/foo/bar", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "component": "@theme/DocRoot", + "exact": false, + "modules": {}, + "path": "/docs", + "routes": [ + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.1/hello.md", + }, + "path": "/docs/", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/versioned_docs/version-1.0.1/foo/bar.md", + }, + "path": "/docs/foo/bar", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + }, + ], }, ], }, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 2bc952d8f30d..47535f746ce0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -49,8 +49,9 @@ describe('normalizeDocsPluginOptions', () => { sidebarPath: 'my-sidebar', // Path to sidebar configuration for showing a list of markdown pages. sidebarItemsGenerator: DefaultSidebarItemsGenerator, numberPrefixParser: DefaultNumberPrefixParser, - docVersionLayoutComponent: '@theme/DocVersionPage', - docLayoutComponent: '@theme/DocPage', + docsRootComponent: '@theme/DocsRoot', + docVersionRootComponent: '@theme/DocVersionRoot', + docRootComponent: '@theme/DocRoot', docItemComponent: '@theme/DocItem', docTagDocListComponent: '@theme/DocTagDocListPage', docTagsListComponent: '@theme/DocTagsListPage', diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index ce25a87f0ea3..69bb8077aa7d 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -207,6 +207,7 @@ export default async function pluginContentDocs( const versions: FullVersion[] = content.loadedVersions.map(toFullVersion); await createAllRoutes({ + baseUrl, versions, options, actions, diff --git a/packages/docusaurus-plugin-content-docs/src/options.ts b/packages/docusaurus-plugin-content-docs/src/options.ts index dfa786cca262..01d97d7684ec 100644 --- a/packages/docusaurus-plugin-content-docs/src/options.ts +++ b/packages/docusaurus-plugin-content-docs/src/options.ts @@ -30,8 +30,9 @@ export const DEFAULT_OPTIONS: Omit = { exclude: GlobExcludeDefault, sidebarItemsGenerator: DefaultSidebarItemsGenerator, numberPrefixParser: DefaultNumberPrefixParser, - docVersionLayoutComponent: '@theme/DocVersionPage', - docLayoutComponent: '@theme/DocPage', + docsRootComponent: '@theme/DocsRoot', + docVersionRootComponent: '@theme/DocVersionRoot', + docRootComponent: '@theme/DocRoot', docItemComponent: '@theme/DocItem', docTagDocListComponent: '@theme/DocTagDocListPage', docTagsListComponent: '@theme/DocTagsListPage', @@ -105,10 +106,11 @@ const OptionsSchema = Joi.object({ }), ) .default(() => DEFAULT_OPTIONS.numberPrefixParser), - docVersionLayoutComponent: Joi.string().default( - DEFAULT_OPTIONS.docVersionLayoutComponent, + docsRootComponent: Joi.string().default(DEFAULT_OPTIONS.docsRootComponent), + docVersionRootComponent: Joi.string().default( + DEFAULT_OPTIONS.docVersionRootComponent, ), - docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent), + docRootComponent: Joi.string().default(DEFAULT_OPTIONS.docRootComponent), docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent), docTagsListComponent: Joi.string().default( DEFAULT_OPTIONS.docTagsListComponent, diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 80d15acefeb5..54e29f95365c 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -198,19 +198,24 @@ declare module '@docusaurus/plugin-content-docs' { */ exclude: string[]; /** - * Parent layout component of all versioned docs pages: + * Parent component of all the docs plugin pages (all versions). + * Stays mounted when navigation between versions. + */ + docsRootComponent: string; + /** + * Parent component of all versioned docs pages: * - docs pages with sidebars * - tags pages * Stays mounted when navigation between such pages. */ - docVersionLayoutComponent: string; + docVersionRootComponent: string; /** - * Parent layout component of docs pages with sidebars: + * Parent component of all docs pages with sidebars: * - regular docs pages * - category generated index pages * Stays mounted when navigation between such pages. */ - docLayoutComponent: string; + docRootComponent: string; /** Main doc container, with TOC, pagination, etc. */ docItemComponent: string; /** Root component of the "docs containing tag X" page. */ @@ -619,7 +624,16 @@ declare module '@theme/DocBreadcrumbs' { export default function DocBreadcrumbs(): JSX.Element; } -declare module '@theme/DocVersionPage' { +declare module '@theme/DocsRoot' { + import type {RouteConfigComponentProps} from 'react-router-config'; + import type {Required} from 'utility-types'; + + export interface Props extends Required {} + + export default function DocsRoot(props: Props): JSX.Element; +} + +declare module '@theme/DocVersionRoot' { import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs'; import type {RouteConfigComponentProps} from 'react-router-config'; import type {Required} from 'utility-types'; @@ -628,14 +642,14 @@ declare module '@theme/DocVersionPage' { readonly version: PropVersionMetadata; } - export default function DocPage(props: Props): JSX.Element; + export default function DocVersionRoot(props: Props): JSX.Element; } -declare module '@theme/DocPage' { +declare module '@theme/DocRoot' { import type {RouteConfigComponentProps} from 'react-router-config'; import type {Required} from 'utility-types'; export interface Props extends Required {} - export default function DocPage(props: Props): JSX.Element; + export default function DocRoot(props: Props): JSX.Element; } diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index 5deeed6ed3b7..ed67b1acaac4 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import logger from '@docusaurus/logger'; -import {docuHash, createSlugger} from '@docusaurus/utils'; +import {docuHash, createSlugger, normalizeUrl} from '@docusaurus/utils'; import { toTagDocListProp, toTagsListTagsProp, @@ -83,7 +83,7 @@ async function buildVersionDocRoutes({ modules: { content: metadataItem.source, }, - // Because the parent (DocPage) comp need to access it easily + // Because the parent (DocRoot) comp need to access it easily // This permits to render the sidebar once without unmount/remount when // navigating (and preserve sidebar state) ...(metadataItem.sidebar && { @@ -105,7 +105,7 @@ async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) { return { path: param.version.path, exact: false, - component: param.options.docLayoutComponent, + component: param.options.docRootComponent, routes: subRoutes, modules: {}, }; @@ -193,7 +193,7 @@ async function buildVersionRoutes( return { path: version.path, exact: false, - component: options.docVersionLayoutComponent, + component: options.docVersionRootComponent, routes: subRoutes, modules: { version: aliasedSource(versionPropPath), @@ -210,32 +210,16 @@ async function buildVersionRoutes( } } -async function buildVersionsRoutes( - param: BuildAllRoutesParam, -): Promise { - return Promise.all( - param.versions.map((version) => - buildVersionRoutes({ - ...param, - version, - }), - ), - ); -} - -type BuildAllRoutesParam = { - versions: FullVersion[]; - options: PluginOptions; +type BuildAllRoutesParam = Omit & { actions: Omit; - aliasedSource: (str: string) => string; }; -// TODO we want this build function to be easily testable +// TODO we want this buildAllRoutes function to be easily testable // Ideally, we should avoid side effects here (ie not injecting actions) export async function buildAllRoutes( param: BuildAllRoutesParam, ): Promise { - const versionRoutes = Promise.all( + const subRoutes = await Promise.all( param.versions.map((version) => buildVersionRoutes({ ...param, @@ -244,14 +228,19 @@ export async function buildAllRoutes( ), ); - // TODO do we want to wrap all versions under a single parent component? - // ie have a "root docs root" at the very top? - // could be convenient to register a global docs plugin provider? - - return versionRoutes; + // + return [ + { + path: normalizeUrl([param.baseUrl, param.options.routeBasePath]), + exact: false, + component: param.options.docsRootComponent, + routes: subRoutes, + }, + ]; } type CreateAllRoutesParam = { + baseUrl: string; versions: FullVersion[]; options: PluginOptions; actions: PluginContentLoadedActions; @@ -261,6 +250,6 @@ type CreateAllRoutesParam = { export async function createAllRoutes( param: CreateAllRoutesParam, ): Promise { - const versionRoutes = await buildVersionsRoutes(param); - versionRoutes.forEach((versionRoute) => param.actions.addRoute(versionRoute)); + const routes = await buildAllRoutes(param); + routes.forEach(param.actions.addRoute); } diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 5c6db4e29825..4847a64ee486 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -379,17 +379,17 @@ declare module '@theme/DocItem/Footer' { export default function DocItemFooter(): JSX.Element; } -declare module '@theme/DocPage/Layout' { +declare module '@theme/DocRoot/Layout' { import type {ReactNode} from 'react'; export interface Props { readonly children: ReactNode; } - export default function DocPageLayout(props: Props): JSX.Element; + export default function DocRootLayout(props: Props): JSX.Element; } -declare module '@theme/DocPage/Layout/Sidebar' { +declare module '@theme/DocRoot/Layout/Sidebar' { import type {Dispatch, SetStateAction} from 'react'; import type {PropSidebar} from '@docusaurus/plugin-content-docs'; @@ -399,20 +399,20 @@ declare module '@theme/DocPage/Layout/Sidebar' { readonly setHiddenSidebarContainer: Dispatch>; } - export default function DocPageLayoutSidebar(props: Props): JSX.Element; + export default function DocRootLayoutSidebar(props: Props): JSX.Element; } -declare module '@theme/DocPage/Layout/Sidebar/ExpandButton' { +declare module '@theme/DocRoot/Layout/Sidebar/ExpandButton' { export interface Props { toggleSidebar: () => void; } - export default function DocPageLayoutSidebarExpandButton( + export default function DocRootLayoutSidebarExpandButton( props: Props, ): JSX.Element; } -declare module '@theme/DocPage/Layout/Main' { +declare module '@theme/DocRoot/Layout/Main' { import type {ReactNode} from 'react'; export interface Props { @@ -420,7 +420,7 @@ declare module '@theme/DocPage/Layout/Main' { readonly children: ReactNode; } - export default function DocPageLayoutMain(props: Props): JSX.Element; + export default function DocRootLayoutMain(props: Props): JSX.Element; } declare module '@theme/DocPaginator' { diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/index.tsx similarity index 89% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/index.tsx index eb19b3549c89..b8432909ef37 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/index.tsx @@ -8,11 +8,11 @@ import React from 'react'; import clsx from 'clsx'; import {useDocsSidebar} from '@docusaurus/theme-common/internal'; -import type {Props} from '@theme/DocPage/Layout/Main'; +import type {Props} from '@theme/DocRoot/Layout/Main'; import styles from './styles.module.css'; -export default function DocPageLayoutMain({ +export default function DocRootLayoutMain({ hiddenSidebarContainer, children, }: Props): JSX.Element { diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css similarity index 100% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Main/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/ExpandButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx similarity index 89% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/ExpandButton/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx index 688501a0ace5..564d27475ccb 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/ExpandButton/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.tsx @@ -8,11 +8,11 @@ import React from 'react'; import {translate} from '@docusaurus/Translate'; import IconArrow from '@theme/Icon/Arrow'; -import type {Props} from '@theme/DocPage/Layout/Sidebar/ExpandButton'; +import type {Props} from '@theme/DocRoot/Layout/Sidebar/ExpandButton'; import styles from './styles.module.css'; -export default function DocPageLayoutSidebarExpandButton({ +export default function DocRootLayoutSidebarExpandButton({ toggleSidebar, }: Props): JSX.Element { return ( diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/ExpandButton/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css similarity index 100% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/ExpandButton/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/index.tsx similarity index 92% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/index.tsx index a88302612113..243511230c0d 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/index.tsx @@ -11,8 +11,8 @@ import {ThemeClassNames} from '@docusaurus/theme-common'; import {useDocsSidebar} from '@docusaurus/theme-common/internal'; import {useLocation} from '@docusaurus/router'; import DocSidebar from '@theme/DocSidebar'; -import ExpandButton from '@theme/DocPage/Layout/Sidebar/ExpandButton'; -import type {Props} from '@theme/DocPage/Layout/Sidebar'; +import ExpandButton from '@theme/DocRoot/Layout/Sidebar/ExpandButton'; +import type {Props} from '@theme/DocRoot/Layout/Sidebar'; import styles from './styles.module.css'; @@ -28,7 +28,7 @@ function ResetOnSidebarChange({children}: {children: ReactNode}) { ); } -export default function DocPageLayoutSidebar({ +export default function DocRootLayoutSidebar({ sidebar, hiddenSidebarContainer, setHiddenSidebarContainer, diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css similarity index 100% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Sidebar/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/Sidebar/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/index.tsx similarity index 68% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/index.tsx index b41d7890f580..45a12d28cfe5 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/index.tsx @@ -8,29 +8,29 @@ import React, {useState} from 'react'; import {useDocsSidebar} from '@docusaurus/theme-common/internal'; import BackToTopButton from '@theme/BackToTopButton'; -import DocPageLayoutSidebar from '@theme/DocPage/Layout/Sidebar'; -import DocPageLayoutMain from '@theme/DocPage/Layout/Main'; -import type {Props} from '@theme/DocPage/Layout'; +import DocRootLayoutSidebar from '@theme/DocRoot/Layout/Sidebar'; +import DocRootLayoutMain from '@theme/DocRoot/Layout/Main'; +import type {Props} from '@theme/DocRoot/Layout'; import styles from './styles.module.css'; -export default function DocPageLayout({children}: Props): JSX.Element { +export default function DocRootLayout({children}: Props): JSX.Element { const sidebar = useDocsSidebar(); const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); return (
-
+
{sidebar && ( - )} - + {children} - +
); diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/styles.module.css similarity index 95% rename from packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/styles.module.css index 2516de55e3d4..d80285c4c1c0 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/Layout/styles.module.css @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -.docPage { +.docRoot { display: flex; width: 100%; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx similarity index 73% rename from packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx index 3a38c528438d..67d7999e0c80 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx @@ -10,14 +10,14 @@ import clsx from 'clsx'; import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common'; import { DocsSidebarProvider, - useDocRouteMetadata, + useDocRootMetadata, } from '@docusaurus/theme-common/internal'; -import DocPageLayout from '@theme/DocPage/Layout'; +import DocRootLayout from '@theme/DocRoot/Layout'; import NotFound from '@theme/NotFound'; -import type {Props} from '@theme/DocPage'; +import type {Props} from '@theme/DocRoot'; -export default function DocPage(props: Props): JSX.Element { - const currentDocRouteMetadata = useDocRouteMetadata(props); +export default function DocRoot(props: Props): JSX.Element { + const currentDocRouteMetadata = useDocRootMetadata(props); if (!currentDocRouteMetadata) { return ; } @@ -25,7 +25,7 @@ export default function DocPage(props: Props): JSX.Element { return ( - {docElement} + {docElement} ); diff --git a/packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocVersionRoot/index.tsx similarity index 51% rename from packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx rename to packages/docusaurus-theme-classic/src/theme/DocVersionRoot/index.tsx index 17b5a2ffcccc..9c1952ce1b5c 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocVersionPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocVersionRoot/index.tsx @@ -6,23 +6,17 @@ */ import React from 'react'; -import clsx from 'clsx'; -import { - ThemeClassNames, - HtmlClassNameProvider, - PageMetadata, -} from '@docusaurus/theme-common'; +import {HtmlClassNameProvider, PageMetadata} from '@docusaurus/theme-common'; import { docVersionSearchTag, DocsVersionProvider, } from '@docusaurus/theme-common/internal'; import renderRoutes from '@docusaurus/renderRoutes'; import SearchMetadata from '@theme/SearchMetadata'; -import Layout from '@theme/Layout'; -import type {Props} from '@theme/DocVersionPage'; +import type {Props} from '@theme/DocVersionRoot'; -function DocVersionPageMetadata(props: Props): JSX.Element { +function DocVersionRootMetadata(props: Props): JSX.Element { const {version} = props; return ( <> @@ -37,24 +31,21 @@ function DocVersionPageMetadata(props: Props): JSX.Element { ); } -function DocVersionPageContent(props: Props): JSX.Element { +function DocVersionRootContent(props: Props): JSX.Element { const {version, route} = props; return ( - - - - {renderRoutes(route.routes!)} - - - + + + {renderRoutes(route.routes!)} + + ); } -export default function DocVersionPage(props: Props): JSX.Element { +export default function DocVersionRoot(props: Props): JSX.Element { return ( <> - - + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocsRoot/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocsRoot/index.tsx new file mode 100644 index 000000000000..ea65d7414f17 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocsRoot/index.tsx @@ -0,0 +1,22 @@ +/** + * 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 React from 'react'; +import clsx from 'clsx'; +import {ThemeClassNames, HtmlClassNameProvider} from '@docusaurus/theme-common'; +import renderRoutes from '@docusaurus/renderRoutes'; +import Layout from '@theme/Layout'; + +import type {Props} from '@theme/DocVersionRoot'; + +export default function DocsRoot(props: Props): JSX.Element { + return ( + + {renderRoutes(props.route.routes!)} + + ); +} diff --git a/packages/docusaurus-theme-common/src/internal.ts b/packages/docusaurus-theme-common/src/internal.ts index 79812c968634..8415cc967bfe 100644 --- a/packages/docusaurus-theme-common/src/internal.ts +++ b/packages/docusaurus-theme-common/src/internal.ts @@ -73,7 +73,7 @@ export { useDocsVersionCandidates, useLayoutDoc, useLayoutDocsSidebar, - useDocRouteMetadata, + useDocRootMetadata, } from './utils/docsUtils'; export {useTitleFormatter} from './utils/generalUtils'; diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 7825d8aa3c38..d480172b87c8 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -17,7 +17,7 @@ import { type GlobalSidebar, type GlobalDoc, } from '@docusaurus/plugin-content-docs/client'; -import type {Props as DocPageProps} from '@theme/DocPage'; +import type {Props as DocRootProps} from '@theme/DocRoot'; import {useDocsPreferredVersion} from '../contexts/docsPreferredVersion'; import {useDocsVersion} from '../contexts/docsVersion'; import {useDocsSidebar} from '../contexts/docsSidebar'; @@ -290,11 +290,11 @@ Available doc ids are: * version metadata, and the subroutes creating individual doc pages. This hook * will match the current location against all known sub-routes. * - * @param props The props received by `@theme/DocPage` + * @param props The props received by `@theme/DocRoot` * @returns The data of the relevant document at the current location, or `null` * if no document associated with the current location can be found. */ -export function useDocRouteMetadata({route}: DocPageProps): null | { +export function useDocRootMetadata({route}: DocRootProps): null | { /** The element that should be rendered at the current location. */ docElement: JSX.Element; /** diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index a2f22058da4b..ada2f9be9d59 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -103,7 +103,7 @@ describe('handleDuplicateRoutes', () => { describe('loadRoutes', () => { it('loads nested route config', () => { const nestedRouteConfig: RouteConfig = { - component: '@theme/DocPage', + component: '@theme/DocRoot', path: '/docs:route', modules: { docsMetadata: 'docs-b5f.json', diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index a6b4bed6acef..2581448ed941 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -46,7 +46,8 @@ Accepted fields: | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) | | `sidebarItemsGenerator` | SidebarGenerator | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` with real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | | `numberPrefixParser` | boolean \| PrefixParser | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) | -| `docVersionLayoutComponent` | `string` | `'@theme/DocPage'` | Parent layout component of all versioned docs pages (doc pages with sidebars, tags pages). Stays mounted when navigation between such pages. | +| `docsLayoutComponent` | `string` | `'@theme/DocRootLayout'` | Parent layout component of all the docs plugin pages (all versions.. Stays mounted when navigation between versions. | +| `docVersionLayoutComponent` | `string` | `'@theme/DocVersionLayout'` | Parent layout component of all versioned docs pages (doc pages with sidebars, tags pages). Stays mounted when navigation between such pages. | | `docLayoutComponent` | `string` | `'@theme/DocPage'` | Parent layout component of all doc pages with sidebars (regular docs pages, category generated index pages). Stays mounted when navigation between such pages. | | `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. | | `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page | From 42d7ebbfbd026a91661d022ebe3aef858fc8ce13 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 13:26:26 +0200 Subject: [PATCH 10/15] better doc --- .../src/plugin-content-docs.d.ts | 8 ++++---- website/docs/api/plugins/plugin-content-docs.md | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 54e29f95365c..3ae1e0fb7acc 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -198,15 +198,15 @@ declare module '@docusaurus/plugin-content-docs' { */ exclude: string[]; /** - * Parent component of all the docs plugin pages (all versions). - * Stays mounted when navigation between versions. + * Parent component of all the docs plugin pages (including all versions). + * Stays mounted when navigation between docs pages and versions. */ docsRootComponent: string; /** - * Parent component of all versioned docs pages: + * Parent component of all docs pages of an individual version: * - docs pages with sidebars * - tags pages - * Stays mounted when navigation between such pages. + * Stays mounted when navigation between pages of that specific version. */ docVersionRootComponent: string; /** diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index 2581448ed941..9b9a124e0c47 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -46,9 +46,9 @@ Accepted fields: | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) | | `sidebarItemsGenerator` | SidebarGenerator | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` with real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | | `numberPrefixParser` | boolean \| PrefixParser | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) | -| `docsLayoutComponent` | `string` | `'@theme/DocRootLayout'` | Parent layout component of all the docs plugin pages (all versions.. Stays mounted when navigation between versions. | -| `docVersionLayoutComponent` | `string` | `'@theme/DocVersionLayout'` | Parent layout component of all versioned docs pages (doc pages with sidebars, tags pages). Stays mounted when navigation between such pages. | -| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Parent layout component of all doc pages with sidebars (regular docs pages, category generated index pages). Stays mounted when navigation between such pages. | +| `docsRootComponent` | `string` | `'@theme/DocsRoot'` | Parent component of all the docs plugin pages (including all versions). Stays mounted when navigation between docs pages and versions. | +| `docVersionRootComponent` | `string` | `'@theme/DocVersionLayout'` | Parent component of all docs pages of an individual version (doc pages with sidebars, tags pages). Stays mounted when navigation between pages of that specific version. | +| `docRootComponent` | `string` | `'@theme/DocPage'` | Parent component of all doc pages with sidebars (regular docs pages, category generated index pages). Stays mounted when navigation between such pages. | | `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. | | `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page | | `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag X" page. | From e74837b1cb3638820c344fb81b82b3f5b90cc80a Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 13:36:54 +0200 Subject: [PATCH 11/15] update snapshot + complete comment --- .../src/__tests__/__snapshots__/index.test.ts.snap | 13 +++---------- .../docusaurus-plugin-content-docs/src/routes.ts | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 53e7b6bfb87c..244c608c1c0b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1245,7 +1245,7 @@ exports[`simple website content: route config 1`] = ` { "component": "@theme/DocsRoot", "exact": false, - "path": "docs", + "path": "/docs", "routes": [ { "component": "@theme/DocVersionRoot", @@ -1291,7 +1291,6 @@ exports[`simple website content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/docs", "routes": [ { @@ -2741,7 +2740,7 @@ exports[`versioned website (community) content: route config 1`] = ` { "component": "@theme/DocsRoot", "exact": false, - "path": "community", + "path": "/community", "routes": [ { "component": "@theme/DocVersionRoot", @@ -2755,7 +2754,6 @@ exports[`versioned website (community) content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/community/next", "routes": [ { @@ -2783,7 +2781,6 @@ exports[`versioned website (community) content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/community", "routes": [ { @@ -3971,7 +3968,7 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocsRoot", "exact": false, - "path": "docs", + "path": "/docs", "routes": [ { "component": "@theme/DocVersionRoot", @@ -3985,7 +3982,6 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/docs/1.0.0", "routes": [ { @@ -4063,7 +4059,6 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/docs/next", "routes": [ { @@ -4132,7 +4127,6 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/docs/withSlugs", "routes": [ { @@ -4216,7 +4210,6 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocRoot", "exact": false, - "modules": {}, "path": "/docs", "routes": [ { diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index ed67b1acaac4..0b7a6425594f 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -107,7 +107,6 @@ async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) { exact: false, component: param.options.docRootComponent, routes: subRoutes, - modules: {}, }; } @@ -228,7 +227,8 @@ export async function buildAllRoutes( ), ); - // + // all docs routes are wrapped under a single parent route, this ensures + // the theme layout never unmounts/remounts when navigating between versions return [ { path: normalizeUrl([param.baseUrl, param.options.routeBasePath]), From 53f86dc1aec543418c739b35683f48a7e323eab8 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 13:45:21 +0200 Subject: [PATCH 12/15] update snapshot --- .../server/__tests__/__snapshots__/routes.test.ts.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index 391f3f0530c9..9fe2fabb5ff4 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -60,7 +60,7 @@ exports[`loadRoutes loads nested route config 1`] = ` { "registry": { "__comp---theme-doc-item-178-a40": "@theme/DocItem", - "__comp---theme-doc-page-1-be-9be": "@theme/DocPage", + "__comp---theme-doc-roota-94-67a": "@theme/DocRoot", "content---docs-foo-baz-8-ce-61e": "docs/foo/baz.md", "content---docs-helloaff-811": "docs/hello.md", "docsMetadata---docs-routef-34-881": "docs-b5f.json", @@ -77,8 +77,8 @@ exports[`loadRoutes loads nested route config 1`] = ` "content": "content---docs-helloaff-811", "metadata": "metadata---docs-hello-956-741", }, - "/docs:route-502": { - "__comp": "__comp---theme-doc-page-1-be-9be", + "/docs:route-9d0": { + "__comp": "__comp---theme-doc-roota-94-67a", "docsMetadata": "docsMetadata---docs-routef-34-881", }, "docs/foo/baz-eb2": { @@ -96,7 +96,7 @@ import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/docs:route', - component: ComponentCreator('/docs:route', '502'), + component: ComponentCreator('/docs:route', '9d0'), routes: [ { path: '/docs/hello', From ca177b358d9be189c81f78f2c1841fb02f0f246e Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 16:27:08 +0200 Subject: [PATCH 13/15] Fix notfound docs double-layout issue --- .../src/theme-classic.d.ts | 8 +++ .../src/theme/DocRoot/index.tsx | 6 ++- .../src/theme/NotFound.tsx | 54 ------------------- .../src/theme/NotFound/Content/index.tsx | 44 +++++++++++++++ .../src/theme/NotFound/index.tsx | 27 ++++++++++ 5 files changed, 83 insertions(+), 56 deletions(-) delete mode 100644 packages/docusaurus-theme-classic/src/theme/NotFound.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/NotFound/Content/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/NotFound/index.tsx diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 4847a64ee486..8cf475b8400c 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -662,6 +662,14 @@ declare module '@theme/Heading' { export default function Heading(props: Props): JSX.Element; } +declare module '@theme/NotFound/Content' { + export interface Props { + readonly className?: string; + } + + export default function NotFoundContent(props: Props): JSX.Element; +} + declare module '@theme/Layout' { import type {ReactNode} from 'react'; diff --git a/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx index 67d7999e0c80..8c5eb805d13f 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocRoot/index.tsx @@ -13,13 +13,15 @@ import { useDocRootMetadata, } from '@docusaurus/theme-common/internal'; import DocRootLayout from '@theme/DocRoot/Layout'; -import NotFound from '@theme/NotFound'; +import NotFoundContent from '@theme/NotFound/Content'; import type {Props} from '@theme/DocRoot'; export default function DocRoot(props: Props): JSX.Element { const currentDocRouteMetadata = useDocRootMetadata(props); if (!currentDocRouteMetadata) { - return ; + // We only render the not found content to avoid a double layout + // see https://github.com/facebook/docusaurus/pull/7966#pullrequestreview-1077276692 + return ; } const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata; return ( diff --git a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx b/packages/docusaurus-theme-classic/src/theme/NotFound.tsx deleted file mode 100644 index e6b9542f3d50..000000000000 --- a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx +++ /dev/null @@ -1,54 +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 React from 'react'; -import Translate, {translate} from '@docusaurus/Translate'; -import {PageMetadata} from '@docusaurus/theme-common'; -import Layout from '@theme/Layout'; - -export default function NotFound(): JSX.Element { - return ( - <> - - -
-
-
-

- - Page Not Found - -

-

- - We could not find what you were looking for. - -

-

- - Please contact the owner of the site that linked you to the - original URL and let them know their link is broken. - -

-
-
-
-
- - ); -} diff --git a/packages/docusaurus-theme-classic/src/theme/NotFound/Content/index.tsx b/packages/docusaurus-theme-classic/src/theme/NotFound/Content/index.tsx new file mode 100644 index 000000000000..f5288dec00e6 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/NotFound/Content/index.tsx @@ -0,0 +1,44 @@ +/** + * 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 React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import type {Props} from '@theme/NotFound/Content'; + +export default function NotFoundContent({className}: Props): JSX.Element { + return ( +
+
+
+

+ + Page Not Found + +

+

+ + We could not find what you were looking for. + +

+

+ + Please contact the owner of the site that linked you to the + original URL and let them know their link is broken. + +

+
+
+
+ ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/NotFound/index.tsx b/packages/docusaurus-theme-classic/src/theme/NotFound/index.tsx new file mode 100644 index 000000000000..7be3617f7154 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/NotFound/index.tsx @@ -0,0 +1,27 @@ +/** + * 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 React from 'react'; +import {translate} from '@docusaurus/Translate'; +import {PageMetadata} from '@docusaurus/theme-common'; +import Layout from '@theme/Layout'; +import NotFoundContent from '@theme/NotFound/Content'; + +export default function Index(): JSX.Element { + const title = translate({ + id: 'theme.NotFound.title', + message: 'Page Not Found', + }); + return ( + <> + + + + + + ); +} From 9ae5d5356a927f39d922bcfb4fb669d8a4dd1f2a Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 16:34:39 +0200 Subject: [PATCH 14/15] test commit From 5f535738023d2aaa6bee0e3c1467a7fd4323a677 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 18 Aug 2022 17:12:30 +0200 Subject: [PATCH 15/15] test commit