feat: allow using pure HTML as label in navbar links (#7079)

Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
Alexey Pyltsyn 2022-04-07 13:33:52 +03:00 committed by GitHub
parent 529d853ab8
commit bfbc78e52a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 27 deletions

View file

@ -112,6 +112,13 @@ describe('themeConfig', () => {
docId: 'intro', docId: 'intro',
label: 'Introduction', label: 'Introduction',
}, },
// Doc link with HTML as label
{
type: 'doc',
position: 'left',
docId: 'intro',
html: '<b>Introduction</b>',
},
// Regular link // Regular link
{ {
to: '/guide/', to: '/guide/',
@ -119,6 +126,13 @@ describe('themeConfig', () => {
position: 'left', position: 'left',
activeBaseRegex: '/guide/', activeBaseRegex: '/guide/',
}, },
// Regular link with HTML as label
{
to: '/guide/',
html: '<b>Guide</b>',
position: 'left',
activeBaseRegex: '/guide/',
},
// Regular dropdown // Regular dropdown
{ {
label: 'Community', label: 'Community',
@ -136,10 +150,10 @@ describe('themeConfig', () => {
}, },
], ],
}, },
// Dropdown with name // Dropdown with label as HTML
{ {
type: 'dropdown', type: 'dropdown',
label: 'Tools', label: 'Tools <sup>new</sup>',
position: 'left', position: 'left',
items: [ items: [
{ {

View file

@ -651,6 +651,7 @@ declare module '@theme/NavbarItem/NavbarNavLink' {
readonly activeBaseRegex?: string; readonly activeBaseRegex?: string;
readonly exact?: boolean; readonly exact?: boolean;
readonly label?: ReactNode; readonly label?: ReactNode;
readonly html?: string;
readonly prependBaseUrlToHref?: string; readonly prependBaseUrlToHref?: string;
} }

View file

@ -21,6 +21,7 @@ export default function NavbarNavLink({
to, to,
href, href,
label, label,
html,
activeClassName = '', activeClassName = '',
prependBaseUrlToHref, prependBaseUrlToHref,
...props ...props
@ -33,32 +34,47 @@ export default function NavbarNavLink({
const isExternalLink = label && href && !isInternalUrl(href); const isExternalLink = label && href && !isInternalUrl(href);
const isDropdownLink = activeClassName === dropdownLinkActiveClass; const isDropdownLink = activeClassName === dropdownLinkActiveClass;
// Link content is set through html XOR label
const linkContentProps = html
? {dangerouslySetInnerHTML: {__html: html}}
: {
children: (
<>
{label}
{isExternalLink && (
<IconExternalLink
{...(isDropdownLink && {width: 12, height: 12})}
/>
)}
</>
),
};
if (href) {
return (
<Link
href={prependBaseUrlToHref ? normalizedHref : href}
{...props}
{...linkContentProps}
/>
);
}
return ( return (
<Link <Link
{...(href to={toUrl}
? { isNavLink
href: prependBaseUrlToHref ? normalizedHref : href, activeClassName={
} !props.className?.includes(activeClassName) ? activeClassName : ''
: { }
isNavLink: true, {...((activeBasePath || activeBaseRegex) && {
activeClassName: !props.className?.includes(activeClassName) isActive: (_match, location) =>
? activeClassName activeBaseRegex
: '', ? isRegexpStringMatch(activeBaseRegex, location.pathname)
to: toUrl, : location.pathname.startsWith(activeBaseUrl),
...(activeBasePath || activeBaseRegex })}
? { {...props}
isActive: (_match, location) => {...linkContentProps}
activeBaseRegex />
? isRegexpStringMatch(activeBaseRegex, location.pathname)
: location.pathname.startsWith(activeBaseUrl),
}
: null),
})}
{...props}>
{label}
{isExternalLink && (
<IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} />
)}
</Link>
); );
} }

View file

@ -49,8 +49,10 @@ const NavbarItemPosition = Joi.string().equal('left', 'right').default('left');
const NavbarItemBaseSchema = Joi.object({ const NavbarItemBaseSchema = Joi.object({
label: Joi.string(), label: Joi.string(),
html: Joi.string(),
className: Joi.string(), className: Joi.string(),
}) })
.nand('html', 'label')
// We allow any unknown attributes on the links (users may need additional // We allow any unknown attributes on the links (users may need additional
// attributes like target, aria-role, data-customAttribute...) // attributes like target, aria-role, data-customAttribute...)
.unknown(); .unknown();

View file

@ -259,6 +259,7 @@ Accepted fields:
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `type` | `'default'` | Optional | Sets the type of this item to a link. | | `type` | `'default'` | Optional | Sets the type of this item to a link. |
| `label` | `string` | **Required** | The name to be shown for this item. | | `label` | `string` | **Required** | The name to be shown for this item. |
| `html` | `string` | Optional | Same as `label`, but renders pure HTML instead of text content. |
| `to` | `string` | **Required** | Client-side routing, used for navigating within the website. The baseUrl will be automatically prepended to this value. | | `to` | `string` | **Required** | Client-side routing, used for navigating within the website. The baseUrl will be automatically prepended to this value. |
| `href` | `string` | **Required** | A full-page navigation, used for navigating outside of the website. **Only one of `to` or `href` should be used.** | | `href` | `string` | **Required** | A full-page navigation, used for navigating outside of the website. **Only one of `to` or `href` should be used.** |
| `prependBaseUrlToHref` | `boolean` | `false` | Prepends the baseUrl to `href` values. | | `prependBaseUrlToHref` | `boolean` | `false` | Prepends the baseUrl to `href` values. |
@ -288,6 +289,8 @@ module.exports = {
// Only one of "to" or "href" should be used // Only one of "to" or "href" should be used
// href: 'https://www.facebook.com', // href: 'https://www.facebook.com',
label: 'Introduction', label: 'Introduction',
// Only one of "label" or "html" should be used
// html: '<b>Introduction</b>'
position: 'left', position: 'left',
activeBaseRegex: 'docs/(next|v8)', activeBaseRegex: 'docs/(next|v8)',
target: '_blank', target: '_blank',