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 c5a35f6bda..ad14dbad20 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 @@ -60,54 +60,67 @@ Object { Object { "id": "foo/bar", "path": "/docs/foo/bar", + "sidebar": "docs", }, Object { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", + "sidebar": "docs", }, Object { "id": "hello", "path": "/docs/", + "sidebar": "docs", }, Object { "id": "ipsum", "path": "/docs/ipsum", + "sidebar": undefined, }, Object { "id": "lorem", "path": "/docs/lorem", + "sidebar": undefined, }, Object { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", + "sidebar": undefined, }, Object { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", + "sidebar": undefined, }, Object { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", + "sidebar": undefined, }, Object { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", + "sidebar": undefined, }, Object { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", + "sidebar": undefined, }, Object { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", + "sidebar": undefined, }, Object { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", + "sidebar": undefined, }, Object { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", + "sidebar": undefined, }, ], "isLast": true, @@ -362,54 +375,67 @@ Object { Object { "id": "foo/bar", "path": "/docs/foo/bar", + "sidebar": "docs", }, Object { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", + "sidebar": "docs", }, Object { "id": "hello", "path": "/docs/", + "sidebar": "docs", }, Object { "id": "ipsum", "path": "/docs/ipsum", + "sidebar": undefined, }, Object { "id": "lorem", "path": "/docs/lorem", + "sidebar": undefined, }, Object { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", + "sidebar": undefined, }, Object { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", + "sidebar": undefined, }, Object { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", + "sidebar": undefined, }, Object { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", + "sidebar": undefined, }, Object { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", + "sidebar": undefined, }, Object { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", + "sidebar": undefined, }, Object { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", + "sidebar": undefined, }, Object { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", + "sidebar": undefined, }, ], "isLast": true, @@ -661,6 +687,7 @@ Object { Object { "id": "team", "path": "/community/next/team", + "sidebar": "community", }, ], "isLast": false, @@ -674,6 +701,7 @@ Object { Object { "id": "team", "path": "/community/team", + "sidebar": "version-1.0.0/community", }, ], "isLast": true, @@ -1228,26 +1256,32 @@ Object { Object { "id": "foo/bar", "path": "/docs/next/foo/barSlug", + "sidebar": "docs", }, Object { "id": "hello", "path": "/docs/next/", + "sidebar": "docs", }, Object { "id": "slugs/absoluteSlug", "path": "/docs/next/absoluteSlug", + "sidebar": undefined, }, Object { "id": "slugs/relativeSlug", "path": "/docs/next/slugs/relativeSlug", + "sidebar": undefined, }, Object { "id": "slugs/resolvedSlug", "path": "/docs/next/slugs/hey/resolvedSlug", + "sidebar": undefined, }, Object { "id": "slugs/tryToEscapeSlug", "path": "/docs/next/tryToEscapeSlug", + "sidebar": undefined, }, ], "isLast": false, @@ -1261,10 +1295,12 @@ Object { Object { "id": "foo/bar", "path": "/docs/foo/bar", + "sidebar": "version-1.0.1/docs", }, Object { "id": "hello", "path": "/docs/", + "sidebar": "version-1.0.1/docs", }, ], "isLast": true, @@ -1278,14 +1314,17 @@ Object { Object { "id": "foo/bar", "path": "/docs/1.0.0/foo/barSlug", + "sidebar": "version-1.0.0/docs", }, Object { "id": "foo/baz", "path": "/docs/1.0.0/foo/baz", + "sidebar": "version-1.0.0/docs", }, Object { "id": "hello", "path": "/docs/1.0.0/", + "sidebar": "version-1.0.0/docs", }, ], "isLast": false, @@ -1299,34 +1338,42 @@ Object { Object { "id": "rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug", + "sidebar": "version-1.0.1/docs", }, Object { "id": "rootRelativeSlug", "path": "/docs/withSlugs/rootRelativeSlug", + "sidebar": undefined, }, Object { "id": "rootResolvedSlug", "path": "/docs/withSlugs/hey/rootResolvedSlug", + "sidebar": undefined, }, Object { "id": "rootTryToEscapeSlug", "path": "/docs/withSlugs/rootTryToEscapeSlug", + "sidebar": undefined, }, Object { "id": "slugs/absoluteSlug", "path": "/docs/withSlugs/absoluteSlug", + "sidebar": undefined, }, Object { "id": "slugs/relativeSlug", "path": "/docs/withSlugs/slugs/relativeSlug", + "sidebar": undefined, }, Object { "id": "slugs/resolvedSlug", "path": "/docs/withSlugs/slugs/hey/resolvedSlug", + "sidebar": undefined, }, Object { "id": "slugs/tryToEscapeSlug", "path": "/docs/withSlugs/tryToEscapeSlug", + "sidebar": undefined, }, ], "isLast": false, diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index 80d9bc8e93..64ca58bd11 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -11,6 +11,7 @@ export function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { return { id: doc.unversionedId, path: doc.permalink, + sidebar: doc.sidebar, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 0555102f83..79f0c6c3c4 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -148,6 +148,7 @@ export type LoadedContent = { export type GlobalDoc = { id: string; path: string; + sidebar: string | undefined; }; export type GlobalVersion = { diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx new file mode 100644 index 0000000000..602843f06c --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx @@ -0,0 +1,48 @@ +/** + * 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 DefaultNavbarItem from './DefaultNavbarItem'; +import {useLatestVersion, useActiveDocContext} from '@theme/hooks/useDocs'; +import clsx from 'clsx'; +import type {Props} from '@theme/NavbarItem/DocNavbarItem'; + +export default function DocNavbarItem({ + docId, + activeSidebarClassName, + label: staticLabel, + docsPluginId, + ...props +}: Props): JSX.Element { + const latestVersion = useLatestVersion(docsPluginId); + const {activeVersion, activeDoc} = useActiveDocContext(docsPluginId); + + const version = activeVersion ?? latestVersion; + + const doc = version.docs.find((versionDoc) => versionDoc.id === docId); + if (!doc) { + throw new Error( + `DocNavbarItem: couldn't find any doc with id=${docId} in version ${ + version.name + }. +Available docIds=\n- ${version.docs.join('\n- ')}`, + ); + } + + return ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx index 71db1f6ee1..5322d7988e 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx @@ -20,6 +20,7 @@ const getVersionMainDoc = (version) => export default function DocsVersionDropdownNavbarItem({ mobile, docsPluginId, + dropdownActiveClassDisabled, ...props }: Props): JSX.Element { const activeDocContext = useActiveDocContext(docsPluginId); @@ -64,6 +65,7 @@ export default function DocsVersionDropdownNavbarItem({ label={dropdownLabel} to={dropdownTo} items={getItems()} + isActive={dropdownActiveClassDisabled ? () => false : undefined} /> ); } diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx index dd5257dd99..fbcfc6868c 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx @@ -20,6 +20,9 @@ const NavbarItemComponents = { docsVersionDropdown: () => // eslint-disable-next-line @typescript-eslint/no-var-requires require('@theme/NavbarItem/DocsVersionDropdownNavbarItem').default, + doc: () => + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@theme/NavbarItem/DocNavbarItem').default, } as const; const getNavbarItemComponent = ( diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index 3c93176d88..f99f2f8736 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -284,10 +284,12 @@ declare module '@theme/NavbarItem/DefaultNavbarItem' { activeBasePath?: string; activeBaseRegex?: string; to?: string; + exact?: boolean; href?: string; label?: string; activeClassName?: string; prependBaseUrlToHref?: string; + isActive?: () => boolean; } & ComponentProps<'a'>; export type DesktopOrMobileNavBarItemProps = NavLinkProps & { @@ -307,7 +309,10 @@ declare module '@theme/NavbarItem/DefaultNavbarItem' { declare module '@theme/NavbarItem/DocsVersionDropdownNavbarItem' { import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; - export type Props = DefaultNavbarItemProps & {readonly docsPluginId?: string}; + export type Props = DefaultNavbarItemProps & { + readonly docsPluginId?: string; + dropdownActiveClassDisabled?: boolean; + }; const DocsVersionDropdownNavbarItem: (props: Props) => JSX.Element; export default DocsVersionDropdownNavbarItem; @@ -322,6 +327,19 @@ declare module '@theme/NavbarItem/DocsVersionNavbarItem' { export default DocsVersionNavbarItem; } +declare module '@theme/NavbarItem/DocNavbarItem' { + import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; + + export type Props = DefaultNavbarItemProps & { + readonly docId: string; + readonly activeSidebarClassName: string; + readonly docsPluginId?: string; + }; + + const DocsSidebarNavbarItem: (props: Props) => JSX.Element; + export default DocsSidebarNavbarItem; +} + declare module '@theme/NavbarItem' { import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; import type {Props as DocsVersionDropdownNavbarItemProps} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.js b/packages/docusaurus-theme-classic/src/validateThemeConfig.js index 6b86e99b40..ee77935bc8 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.js +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.js @@ -68,6 +68,16 @@ const DocsVersionDropdownNavbarItemSchema = Joi.object({ type: Joi.string().equal('docsVersionDropdown').required(), position: NavbarItemPosition, docsPluginId: Joi.string(), + dropdownActiveClassDisabled: Joi.boolean(), +}); + +const DocItemSchema = Joi.object({ + type: Joi.string().equal('doc').required(), + position: NavbarItemPosition, + docId: Joi.string().required(), + label: Joi.string(), + docsPluginId: Joi.string(), + activeSidebarClassName: Joi.string().default('navbar__link--active'), }); // Can this be made easier? :/ @@ -94,6 +104,10 @@ const NavbarItemSchema = Joi.object().when({ is: isOfType('docsVersionDropdown'), then: DocsVersionDropdownNavbarItemSchema, }, + { + is: isOfType('doc'), + then: DocItemSchema, + }, { is: isOfType(undefined), then: Joi.forbidden().messages({ diff --git a/website/docs/theme-classic.md b/website/docs/theme-classic.md index 29f683493d..4e457f90a5 100644 --- a/website/docs/theme-classic.md +++ b/website/docs/theme-classic.md @@ -262,6 +262,28 @@ module.exports = { }; ``` +### Navbar doc link + +If you want to link to a specific doc, this special navbar item type will render the link to the doc of the provided `docId`. It will get the class `navbar__link--active` as long as you browse a doc of the same sidebar. + +```js {5-10} title="docusaurus.config.js" +module.exports = { + themeConfig: { + navbar: { + items: [ + { + type: 'doc', + position: 'left', + docId: 'introduction', + label: 'Docs', + activeSidebarClassName: 'navbar__link--active', + }, + ], + }, + }, +}; +``` + ### Navbar docs version dropdown If you use docs with versioning, this special navbar item type that will render a dropdown with all your site's available versions. The user will be able to switch from one version to another, while staying on the same doc (as long as the doc id is constant across versions). @@ -274,6 +296,7 @@ module.exports = { { type: 'docsVersionDropdown', position: 'left', + // dropdownActiveClassDisabled: true, // }, ], }, diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 2a370e02be..d92a72095c 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -264,6 +264,19 @@ module.exports = { { type: 'docsVersionDropdown', position: 'left', + dropdownActiveClassDisabled: true, + }, + { + type: 'doc', + position: 'left', + docId: 'introduction', + label: 'Docs', + }, + { + type: 'doc', + position: 'left', + docId: 'cli', + label: 'API', }, {to: 'blog', label: 'Blog', position: 'left'}, {to: 'showcase', label: 'Showcase', position: 'left'}, diff --git a/website/sidebars.js b/website/sidebars.js index 18d6622046..2866dcae1d 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -39,16 +39,12 @@ module.exports = { label: 'Advanced Guides', items: ['using-plugins', 'using-themes', 'presets'], }, - { - type: 'category', - label: 'API Reference', - items: [ - 'cli', - 'docusaurus-core', - 'api/docusaurus.config.js', - 'lifecycle-apis', - 'theme-classic', - ], - }, + ], + api: [ + 'cli', + 'docusaurus-core', + 'api/docusaurus.config.js', + 'lifecycle-apis', + 'theme-classic', ], }; diff --git a/website/versioned_sidebars/version-2.0.0-alpha.65-sidebars.json b/website/versioned_sidebars/version-2.0.0-alpha.65-sidebars.json index bbbc82115e..b855328f14 100644 --- a/website/versioned_sidebars/version-2.0.0-alpha.65-sidebars.json +++ b/website/versioned_sidebars/version-2.0.0-alpha.65-sidebars.json @@ -110,33 +110,28 @@ "id": "version-2.0.0-alpha.65/presets" } ] + } + ], + "api": [ + { + "type": "doc", + "id": "version-2.0.0-alpha.65/cli" }, { - "collapsed": true, - "type": "category", - "label": "API Reference", - "items": [ - { - "type": "doc", - "id": "version-2.0.0-alpha.65/cli" - }, - { - "type": "doc", - "id": "version-2.0.0-alpha.65/docusaurus-core" - }, - { - "type": "doc", - "id": "version-2.0.0-alpha.65/api/docusaurus.config.js" - }, - { - "type": "doc", - "id": "version-2.0.0-alpha.65/lifecycle-apis" - }, - { - "type": "doc", - "id": "version-2.0.0-alpha.65/theme-classic" - } - ] + "type": "doc", + "id": "version-2.0.0-alpha.65/docusaurus-core" + }, + { + "type": "doc", + "id": "version-2.0.0-alpha.65/api/docusaurus.config.js" + }, + { + "type": "doc", + "id": "version-2.0.0-alpha.65/lifecycle-apis" + }, + { + "type": "doc", + "id": "version-2.0.0-alpha.65/theme-classic" } ] }