diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index 4817935c52f7..7ac6a7eda81e 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -150,12 +150,22 @@ describe('themeConfig', () => { }, ], }, + // HTML-only + { + type: 'html', + position: 'right', + value: '', + }, // Dropdown with label as HTML { type: 'dropdown', label: 'Tools new', position: 'left', items: [ + { + type: 'html', + value: 'Supported package managers', + }, { type: 'doc', docId: 'npm', @@ -181,6 +191,10 @@ describe('themeConfig', () => { }, ], dropdownItemsAfter: [ + { + type: 'html', + value: '
', + }, { to: '/versions', label: 'All versions', diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 233f229c9f84..d9462dfee076 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -872,6 +872,16 @@ declare module '@theme/NavbarItem/DocSidebarNavbarItem' { export default function DocSidebarNavbarItem(props: Props): JSX.Element; } +declare module '@theme/NavbarItem/HtmlNavbarItem' { + import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; + + export interface Props extends DefaultNavbarItemProps { + readonly value: string; + } + + export default function HtmlNavbarItem(props: Props): JSX.Element; +} + declare module '@theme/NavbarItem' { import type {ComponentProps} from 'react'; import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; @@ -882,12 +892,14 @@ declare module '@theme/NavbarItem' { import type {Props as DocsVersionDropdownNavbarItemProps} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; import type {Props as LocaleDropdownNavbarItemProps} from '@theme/NavbarItem/LocaleDropdownNavbarItem'; import type {Props as SearchNavbarItemProps} from '@theme/NavbarItem/SearchNavbarItem'; + import type {Props as HtmlNavbarItemProps} from '@theme/NavbarItem/HtmlNavbarItem'; export type LinkLikeNavbarItemProps = | ({readonly type?: 'default'} & DefaultNavbarItemProps) | ({readonly type: 'doc'} & DocNavbarItemProps) | ({readonly type: 'docsVersion'} & DocsVersionNavbarItemProps) - | ({readonly type: 'docSidebar'} & DocSidebarNavbarItemProps); + | ({readonly type: 'docSidebar'} & DocSidebarNavbarItemProps) + | ({readonly type: 'html'} & HtmlNavbarItemProps); export type Props = ComponentProps<'a'> & { readonly position?: 'left' | 'right'; diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/HtmlNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/HtmlNavbarItem.tsx new file mode 100644 index 000000000000..19ead028756b --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/HtmlNavbarItem.tsx @@ -0,0 +1,32 @@ +/** + * 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 type {Props} from '@theme/NavbarItem/HtmlNavbarItem'; + +export default function HtmlNavbarItem({ + value, + className, + mobile = false, + isDropdownItem = false, +}: Props): JSX.Element { + const Comp = isDropdownItem ? 'li' : 'div'; + return ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx index d9c5e9d30df8..7c3c9b07b56f 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx @@ -12,6 +12,7 @@ import DropdownNavbarItem, { } from '@theme/NavbarItem/DropdownNavbarItem'; import LocaleDropdownNavbarItem from '@theme/NavbarItem/LocaleDropdownNavbarItem'; import SearchNavbarItem from '@theme/NavbarItem/SearchNavbarItem'; +import HtmlNavbarItem from '@theme/NavbarItem/HtmlNavbarItem'; import type {Types, Props} from '@theme/NavbarItem'; const NavbarItemComponents: { @@ -23,6 +24,7 @@ const NavbarItemComponents: { localeDropdown: () => LocaleDropdownNavbarItem, search: () => SearchNavbarItem, dropdown: () => DropdownNavbarItem, + html: () => HtmlNavbarItem, // Need to lazy load these items as we don't know for sure the docs plugin is // loaded. See https://github.com/facebook/docusaurus/issues/3360 diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts index 70f28373cec4..6708539c2730 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts @@ -93,6 +93,12 @@ const DocSidebarItemSchema = NavbarItemBaseSchema.append({ docsPluginId: Joi.string(), }); +const HtmlNavbarItemSchema = Joi.object({ + className: Joi.string(), + type: Joi.string().equal('html').required(), + value: Joi.string().required(), +}); + const itemWithType = (type: string | undefined) => { // because equal(undefined) is not supported :/ const typeSchema = type @@ -125,6 +131,10 @@ const DropdownSubitemSchema = Joi.object({ is: itemWithType(undefined), then: DefaultNavbarItemSchema, }, + { + is: itemWithType('html'), + then: HtmlNavbarItemSchema, + }, { is: Joi.alternatives().try( itemWithType('dropdown'), @@ -196,6 +206,10 @@ const NavbarItemSchema = Joi.object({ is: itemWithType('search'), then: SearchItemSchema, }, + { + is: itemWithType('html'), + then: HtmlNavbarItemSchema, + }, { is: itemWithType(undefined), then: Joi.object().when('.', { diff --git a/website/docs/api/themes/theme-configuration.md b/website/docs/api/themes/theme-configuration.md index fd1e4ac30659..d496a7ed8bd6 100644 --- a/website/docs/api/themes/theme-configuration.md +++ b/website/docs/api/themes/theme-configuration.md @@ -312,6 +312,7 @@ Navbar dropdown items only accept the following **"link-like" item types**: - [Navbar doc link](#navbar-doc-link) - [Navbar docs version](#navbar-docs-version) - [Navbar doc sidebar](#navbar-doc-sidebar) +- [Navbar with custom HTML](#navbar-with-custom-html) Note that the dropdown base item is a clickable link as well, so this item can receive any of the props of a [plain navbar link](#navbar-link). @@ -621,6 +622,39 @@ module.exports = { }; ``` +#### Navbar with custom HTML {#navbar-with-custom-html} + +You can also render your own HTML markup inside a navbar item using this navbar item type. + + + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `type` | `'html'` | **Required** | Sets the type of this item to a HTML element. | +| `position` | 'left' \| 'right' | `'left'` | The side of the navbar this item should appear on. | +| `className` | `string` | `''` | Custom CSS class for this navbar item. | +| `value` | `string` | `''` | Custom HTML to be rendered inside this navbar item. | + + + +```js title="docusaurus.config.js" +module.exports = { + themeConfig: { + navbar: { + items: [ + // highlight-start + { + type: 'html', + position: 'right', + value: '', + }, + // highlight-end + ], + }, + }, +}; +``` + ### Auto-hide sticky navbar {#auto-hide-sticky-navbar} You can enable this cool UI feature that automatically hides the navbar when a user starts scrolling down the page, and show it again when the user scrolls up. diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 8c4bebc928a8..8e396e641b41 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -419,6 +419,15 @@ const config = { position: 'right', dropdownActiveClassDisabled: true, dropdownItemsAfter: [ + { + type: 'html', + value: '', + }, + { + type: 'html', + className: 'dropdown-archived-versions', + value: 'Archived versions', + }, ...ArchivedVersionsDropdownItems.map( ([versionName, versionUrl]) => ({ label: versionName, @@ -429,6 +438,10 @@ const config = { href: 'https://v1.docusaurus.io', label: '1.x.x', }, + { + type: 'html', + value: '', + }, { to: '/versions', label: 'All versions', @@ -439,6 +452,10 @@ const config = { type: 'localeDropdown', position: 'right', dropdownItemsAfter: [ + { + type: 'html', + value: '
', + }, { href: 'https://github.com/facebook/docusaurus/issues/3526', label: 'Help Us Translate', diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 728c5d628a99..11b4f2fa04e4 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -207,3 +207,12 @@ div[class^='announcementBar_'] { height: 100%; } } + +.dropdown-separator { + margin: 0.3rem 0; +} + +.dropdown-archived-versions { + font-size: 0.875rem; + padding: 0.2rem 0.5rem; +}