feat(theme-classic): new 'html' type navbar item (#7058)

* feat(theme-classic): allow using html in dropdown items

* Fix tests

* Introduce HTML type for navbar item

* Update packages/docusaurus-theme-classic/src/theme/NavbarItem/HtmlNavbarItem.tsx

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
Alexey Pyltsyn 2022-04-15 13:58:15 +03:00 committed by GitHub
parent 5273a534d3
commit 84d04ed6ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 1 deletions

View file

@ -150,12 +150,22 @@ describe('themeConfig', () => {
},
],
},
// HTML-only
{
type: 'html',
position: 'right',
value: '<button>Give feedback</button>',
},
// Dropdown with label as HTML
{
type: 'dropdown',
label: 'Tools <sup>new</sup>',
position: 'left',
items: [
{
type: 'html',
value: '<b>Supported package managers</b>',
},
{
type: 'doc',
docId: 'npm',
@ -181,6 +191,10 @@ describe('themeConfig', () => {
},
],
dropdownItemsAfter: [
{
type: 'html',
value: '<hr/>',
},
{
to: '/versions',
label: 'All versions',

View file

@ -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';

View file

@ -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 (
<Comp
className={clsx(
{
navbar__item: !mobile && !isDropdownItem,
'menu__list-item': mobile,
},
className,
)}
dangerouslySetInnerHTML={{__html: value}}
/>
);
}

View file

@ -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

View file

@ -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('.', {

View file

@ -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.
<APITable name="navbar-html">
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `'html'` | **Required** | Sets the type of this item to a HTML element. |
| `position` | <code>'left' \| 'right'</code> | `'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. |
</APITable>
```js title="docusaurus.config.js"
module.exports = {
themeConfig: {
navbar: {
items: [
// highlight-start
{
type: 'html',
position: 'right',
value: '<button>Give feedback</button>',
},
// 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.

View file

@ -419,6 +419,15 @@ const config = {
position: 'right',
dropdownActiveClassDisabled: true,
dropdownItemsAfter: [
{
type: 'html',
value: '<hr class="dropdown-separator">',
},
{
type: 'html',
className: 'dropdown-archived-versions',
value: '<b>Archived versions</b>',
},
...ArchivedVersionsDropdownItems.map(
([versionName, versionUrl]) => ({
label: versionName,
@ -429,6 +438,10 @@ const config = {
href: 'https://v1.docusaurus.io',
label: '1.x.x',
},
{
type: 'html',
value: '<hr class="dropdown-separator">',
},
{
to: '/versions',
label: 'All versions',
@ -439,6 +452,10 @@ const config = {
type: 'localeDropdown',
position: 'right',
dropdownItemsAfter: [
{
type: 'html',
value: '<hr style="margin: 0.3rem 0;">',
},
{
href: 'https://github.com/facebook/docusaurus/issues/3526',
label: 'Help Us Translate',

View file

@ -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;
}