refactor(v2): add useThemeConfig hook + cleanup useless theme default values (#3394)

* refactor(theme-classic): clean default or fallback values

* refactor(theme-classic): fix announcementbar undefined error

* refactor(theme-classic): fixed react hook warning error

* refactor(theme-classic): revert prism destruct

* create useThemeConfig and use it whenever possible

* validateThemeConfig => add [] as default value for almost all arrays

* fix tests

Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
Shubham Kumar 2020-10-02 22:53:34 +05:30 committed by GitHub
parent f5f2064656
commit 0951eef2d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 154 additions and 142 deletions

View file

@ -11,14 +11,19 @@ const {ThemeConfigSchema, DEFAULT_CONFIG} = require('../validateThemeConfig');
const {normalizeThemeConfig} = require('@docusaurus/utils-validation'); const {normalizeThemeConfig} = require('@docusaurus/utils-validation');
function testValidateThemeConfig(themeConfig) { function testValidateThemeConfig(partialThemeConfig) {
return normalizeThemeConfig(ThemeConfigSchema, themeConfig); return normalizeThemeConfig(ThemeConfigSchema, {
...DEFAULT_CONFIG,
...partialThemeConfig,
});
} }
function testOk(partialConfig) { function testOk(partialThemeConfig) {
expect(testValidateThemeConfig(partialConfig)).toEqual({ expect(
testValidateThemeConfig({...DEFAULT_CONFIG, ...partialThemeConfig}),
).toEqual({
...DEFAULT_CONFIG, ...DEFAULT_CONFIG,
...partialConfig, ...partialThemeConfig,
}); });
} }
@ -101,7 +106,10 @@ describe('themeConfig', () => {
}; };
expect(testValidateThemeConfig(altTagConfig)).toEqual({ expect(testValidateThemeConfig(altTagConfig)).toEqual({
...DEFAULT_CONFIG, ...DEFAULT_CONFIG,
...altTagConfig, navbar: {
...DEFAULT_CONFIG.navbar,
...altTagConfig.navbar,
},
}); });
}); });
@ -117,7 +125,7 @@ describe('themeConfig', () => {
}); });
}); });
describe.only('customCss config', () => { describe('customCss config', () => {
test('should accept customCss undefined', () => { test('should accept customCss undefined', () => {
testOk({ testOk({
customCss: undefined, customCss: undefined,

View file

@ -7,21 +7,23 @@
import React from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useThemeConfig from '../../utils/useThemeConfig';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext'; import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import styles from './styles.module.css'; import styles from './styles.module.css';
function AnnouncementBar(): JSX.Element | null { function AnnouncementBar(): JSX.Element | null {
const {
siteConfig: {themeConfig: {announcementBar = {}} = {}} = {},
} = useDocusaurusContext();
const {content, backgroundColor, textColor, isCloseable} = announcementBar;
const { const {
isAnnouncementBarClosed, isAnnouncementBarClosed,
closeAnnouncementBar, closeAnnouncementBar,
} = useUserPreferencesContext(); } = useUserPreferencesContext();
const {announcementBar} = useThemeConfig();
if (!announcementBar) {
return null;
}
const {content, backgroundColor, textColor, isCloseable} = announcementBar;
if (!content || (isCloseable && isAnnouncementBarClosed)) { if (!content || (isCloseable && isAnnouncementBarClosed)) {
return null; return null;
} }

View file

@ -12,11 +12,11 @@ import clsx from 'clsx';
import Highlight, {defaultProps} from 'prism-react-renderer'; import Highlight, {defaultProps} from 'prism-react-renderer';
import copy from 'copy-text-to-clipboard'; import copy from 'copy-text-to-clipboard';
import rangeParser from 'parse-numeric-range'; import rangeParser from 'parse-numeric-range';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import usePrismTheme from '@theme/hooks/usePrismTheme'; import usePrismTheme from '@theme/hooks/usePrismTheme';
import type {Props} from '@theme/CodeBlock'; import type {Props} from '@theme/CodeBlock';
import styles from './styles.module.css'; import styles from './styles.module.css';
import useThemeConfig from '../../utils/useThemeConfig';
const highlightLinesRangeRegex = /{([\d,-]+)}/; const highlightLinesRangeRegex = /{([\d,-]+)}/;
const getHighlightDirectiveRegex = ( const getHighlightDirectiveRegex = (
@ -93,11 +93,7 @@ export default ({
className: languageClassName, className: languageClassName,
metastring, metastring,
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { const {prism} = useThemeConfig();
siteConfig: {
themeConfig: {prism = {}},
},
} = useDocusaurusContext();
const [showCopied, setShowCopied] = useState(false); const [showCopied, setShowCopied] = useState(false);
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);

View file

@ -24,7 +24,7 @@ import {
} from '@theme/hooks/useDocs'; } from '@theme/hooks/useDocs';
function DocItem(props: Props): JSX.Element { function DocItem(props: Props): JSX.Element {
const {siteConfig = {}} = useDocusaurusContext(); const {siteConfig} = useDocusaurusContext();
const {url: siteUrl, title: siteTitle, titleDelimiter} = siteConfig; const {url: siteUrl, title: siteTitle, titleDelimiter} = siteConfig;
const {content: DocContent} = props; const {content: DocContent} = props;
const {metadata} = DocContent; const {metadata} = DocContent;

View file

@ -8,6 +8,7 @@
import React, {useState, useCallback, useEffect, useRef} from 'react'; import React, {useState, useCallback, useEffect, useRef} from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeConfig from '../../utils/useThemeConfig';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext'; import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize'; import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
@ -171,11 +172,9 @@ function DocSidebar({
}: Props): JSX.Element | null { }: Props): JSX.Element | null {
const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false); const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false);
const { const {
siteConfig: { navbar: {title, hideOnScroll},
themeConfig: {navbar: {title = '', hideOnScroll = false} = {}} = {}, } = useThemeConfig();
} = {}, const {isClient} = useDocusaurusContext();
isClient,
} = useDocusaurusContext();
const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo(); const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
const {isAnnouncementBarClosed} = useUserPreferencesContext(); const {isAnnouncementBarClosed} = useUserPreferencesContext();
const {scrollY} = useScrollPosition(); const {scrollY} = useScrollPosition();

View file

@ -9,7 +9,7 @@ import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useThemeConfig from '../../utils/useThemeConfig';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -40,10 +40,7 @@ const FooterLogo = ({url, alt}) => (
); );
function Footer(): JSX.Element | null { function Footer(): JSX.Element | null {
const context = useDocusaurusContext(); const {footer} = useThemeConfig();
const {siteConfig = {}} = context;
const {themeConfig = {}} = siteConfig;
const {footer} = themeConfig;
const {copyright, links = [], logo = {}} = footer || {}; const {copyright, links = [], logo = {}} = footer || {};
const logoUrl = useBaseUrl(logo.src); const logoUrl = useBaseUrl(logo.src);

View file

@ -9,8 +9,8 @@
import React from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import type {HeadingType, Props} from '@theme/Heading'; import type {HeadingType, Props} from '@theme/Heading';
import useThemeConfig from '../../utils/useThemeConfig';
import './styles.css'; import './styles.css';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -18,10 +18,8 @@ import styles from './styles.module.css';
const Heading = (Tag: HeadingType): ((props: Props) => JSX.Element) => const Heading = (Tag: HeadingType): ((props: Props) => JSX.Element) =>
function TargetComponent({id, ...props}) { function TargetComponent({id, ...props}) {
const { const {
siteConfig: { navbar: {hideOnScroll},
themeConfig: {navbar: {hideOnScroll = false} = {}} = {}, } = useThemeConfig();
} = {},
} = useDocusaurusContext();
if (!id) { if (!id) {
return <Tag {...props} />; return <Tag {...props} />;

View file

@ -13,6 +13,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import SearchBar from '@theme/SearchBar'; import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle'; import Toggle from '@theme/Toggle';
import useThemeContext from '@theme/hooks/useThemeContext'; import useThemeContext from '@theme/hooks/useThemeContext';
import useThemeConfig from '../../utils/useThemeConfig';
import useHideableNavbar from '@theme/hooks/useHideableNavbar'; import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize'; import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
@ -40,20 +41,13 @@ function splitNavItemsByPosition(items) {
} }
function Navbar(): JSX.Element { function Navbar(): JSX.Element {
const {isClient} = useDocusaurusContext();
const { const {
siteConfig: { navbar: {title, items, hideOnScroll, style},
themeConfig: { colorMode: {disableSwitch: disableColorModeSwitch},
navbar: { } = useThemeConfig();
title = '',
items = [],
hideOnScroll = false,
style = undefined,
} = {},
colorMode: {disableSwitch: disableColorModeSwitch = false} = {},
},
},
isClient,
} = useDocusaurusContext();
const [sidebarShown, setSidebarShown] = useState(false); const [sidebarShown, setSidebarShown] = useState(false);
const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false); const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false);

View file

@ -7,7 +7,7 @@
import React, {ComponentProps} from 'react'; import React, {ComponentProps} from 'react';
import Toggle from 'react-toggle'; import Toggle from 'react-toggle';
import useThemeConfig from '../../utils/useThemeConfig';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import clsx from 'clsx'; import clsx from 'clsx';
@ -26,20 +26,11 @@ const Light = ({icon, style}) => (
export default function (props: ComponentProps<typeof Toggle>): JSX.Element { export default function (props: ComponentProps<typeof Toggle>): JSX.Element {
const { const {
siteConfig: { colorMode: {
themeConfig: { switchConfig: {darkIcon, darkIconStyle, lightIcon, lightIconStyle},
colorMode: { },
switchConfig: { } = useThemeConfig();
darkIcon, const {isClient} = useDocusaurusContext();
darkIconStyle,
lightIcon,
lightIconStyle,
},
},
},
},
isClient
} = useDocusaurusContext();
return ( return (
<Toggle <Toggle

View file

@ -6,14 +6,14 @@
*/ */
import {useState, useEffect, useCallback} from 'react'; import {useState, useEffect, useCallback} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useThemeConfig from '../../utils/useThemeConfig';
import type {useAnnouncementBarReturns} from '@theme/hooks/useAnnoucementBar'; import type {useAnnouncementBarReturns} from '@theme/hooks/useAnnoucementBar';
const STORAGE_DISMISS_KEY = 'docusaurus.announcement.dismiss'; const STORAGE_DISMISS_KEY = 'docusaurus.announcement.dismiss';
const STORAGE_ID_KEY = 'docusaurus.announcement.id'; const STORAGE_ID_KEY = 'docusaurus.announcement.id';
const useAnnouncementBar = (): useAnnouncementBarReturns => { const useAnnouncementBar = (): useAnnouncementBarReturns => {
const {announcementBar} = useDocusaurusContext().siteConfig.themeConfig; const {announcementBar} = useThemeConfig();
const [isClosed, setClosed] = useState(true); const [isClosed, setClosed] = useState(true);

View file

@ -5,16 +5,16 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext'; import useThemeContext from '@theme/hooks/useThemeContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl'; import isInternalUrl from '@docusaurus/isInternalUrl';
import type {LogoLinkProps, useLogoReturns} from '@theme/hooks/useLogo'; import type {LogoLinkProps, useLogoReturns} from '@theme/hooks/useLogo';
import useThemeConfig from '../../utils/useThemeConfig';
const useLogo = (): useLogoReturns => { const useLogo = (): useLogoReturns => {
const { const {
siteConfig: {themeConfig: {navbar: {logo = {}} = {}} = {}} = {}, navbar: {logo},
} = useDocusaurusContext(); } = useThemeConfig();
const {isDarkTheme} = useThemeContext(); const {isDarkTheme} = useThemeContext();
const logoLink = useBaseUrl(logo.href || '/'); const logoLink = useBaseUrl(logo.href || '/');
let logoLinkProps: LogoLinkProps = {}; let logoLinkProps: LogoLinkProps = {};

View file

@ -6,15 +6,11 @@
*/ */
import defaultTheme from 'prism-react-renderer/themes/palenight'; import defaultTheme from 'prism-react-renderer/themes/palenight';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext'; import useThemeContext from '@theme/hooks/useThemeContext';
import useThemeConfig from '../../utils/useThemeConfig';
const usePrismTheme = (): typeof defaultTheme => { const usePrismTheme = (): typeof defaultTheme => {
const { const {prism} = useThemeConfig();
siteConfig: {
themeConfig: {prism = {}},
},
} = useDocusaurusContext();
const {isDarkTheme} = useThemeContext(); const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme; const lightModeTheme = prism.theme || defaultTheme;
const darkModeTheme = prism.darkTheme || lightModeTheme; const darkModeTheme = prism.darkTheme || lightModeTheme;

View file

@ -7,9 +7,9 @@
import {useState, useCallback, useEffect} from 'react'; import {useState, useCallback, useEffect} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import type {useThemeReturns} from '@theme/hooks/useTheme'; import type {useThemeReturns} from '@theme/hooks/useTheme';
import useThemeConfig from '../../utils/useThemeConfig';
const themes = { const themes = {
light: 'light', light: 'light',
@ -38,10 +38,8 @@ const storeTheme = (newTheme) => {
const useTheme = (): useThemeReturns => { const useTheme = (): useThemeReturns => {
const { const {
siteConfig: { colorMode: {disableSwitch = false},
themeConfig: {colorMode: {disableSwitch = false} = {}} = {}, } = useThemeConfig();
} = {},
} = useDocusaurusContext();
const [theme, setTheme] = useState(getInitialTheme); const [theme, setTheme] = useState(getInitialTheme);
const setLightTheme = useCallback(() => { const setLightTheme = useCallback(() => {

View file

@ -0,0 +1,24 @@
/**
* 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 useDocusaurusContext from '@docusaurus/useDocusaurusContext';
type ThemeConfig = {
// TODO we should complete this theme config type over time
// and share it across all themes
// and use it in the Joi validation schema?
// TODO temporary types
navbar: any;
colorMode: any;
announcementBar: any;
prism: any;
footer: any;
};
export default function useThemeConfig(): ThemeConfig {
return useDocusaurusContext().siteConfig.themeConfig as ThemeConfig;
}

View file

@ -23,6 +23,13 @@ const DEFAULT_COLOR_MODE_CONFIG = {
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
colorMode: DEFAULT_COLOR_MODE_CONFIG, colorMode: DEFAULT_COLOR_MODE_CONFIG,
metadatas: [], metadatas: [],
prism: {
additionalLanguages: [],
},
navbar: {
hideOnScroll: false,
items: [],
},
}; };
exports.DEFAULT_CONFIG = DEFAULT_CONFIG; exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
@ -195,13 +202,15 @@ const ThemeConfigSchema = Joi.object({
}).optional(), }).optional(),
navbar: Joi.object({ navbar: Joi.object({
style: Joi.string().equal('dark', 'primary'), style: Joi.string().equal('dark', 'primary'),
hideOnScroll: Joi.bool().default(false), hideOnScroll: Joi.bool().default(DEFAULT_CONFIG.navbar.hideOnScroll),
// TODO temporary (@alpha-58) // TODO temporary (@alpha-58)
links: Joi.any().forbidden().messages({ links: Joi.any().forbidden().messages({
'any.unknown': 'any.unknown':
'themeConfig.navbar.links has been renamed as themeConfig.navbar.items', 'themeConfig.navbar.links has been renamed as themeConfig.navbar.items',
}), }),
items: Joi.array().items(NavbarItemSchema), items: Joi.array()
.items(NavbarItemSchema)
.default(DEFAULT_CONFIG.navbar.items),
title: Joi.string().allow('', null), title: Joi.string().allow('', null),
logo: Joi.object({ logo: Joi.object({
alt: Joi.string().allow(''), alt: Joi.string().allow(''),
@ -210,7 +219,7 @@ const ThemeConfigSchema = Joi.object({
href: Joi.string(), href: Joi.string(),
target: Joi.string(), target: Joi.string(),
}), }),
}), }).default(DEFAULT_CONFIG.navbar),
footer: Joi.object({ footer: Joi.object({
style: Joi.string().equal('dark', 'light').default('light'), style: Joi.string().equal('dark', 'light').default('light'),
logo: Joi.object({ logo: Joi.object({
@ -219,13 +228,15 @@ const ThemeConfigSchema = Joi.object({
href: Joi.string(), href: Joi.string(),
}), }),
copyright: Joi.string(), copyright: Joi.string(),
links: Joi.array().items( links: Joi.array()
Joi.object({ .items(
title: Joi.string().required(), Joi.object({
items: Joi.array().items(FooterLinkItemSchema).default([]), title: Joi.string().required(),
}), items: Joi.array().items(FooterLinkItemSchema).default([]),
), }),
}), )
.default([]),
}).optional(),
prism: Joi.object({ prism: Joi.object({
theme: Joi.object({ theme: Joi.object({
plain: Joi.alternatives().try(Joi.array(), Joi.object()).required(), plain: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
@ -236,8 +247,12 @@ const ThemeConfigSchema = Joi.object({
styles: Joi.alternatives().try(Joi.array(), Joi.object()).required(), styles: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
}), }),
defaultLanguage: Joi.string(), defaultLanguage: Joi.string(),
additionalLanguages: Joi.array().items(Joi.string()), additionalLanguages: Joi.array()
}).unknown(), .items(Joi.string())
.default(DEFAULT_CONFIG.prism.additionalLanguages),
})
.default(DEFAULT_CONFIG.prism)
.unknown(),
}); });
exports.ThemeConfigSchema = ThemeConfigSchema; exports.ThemeConfigSchema = ThemeConfigSchema;

View file

@ -24,18 +24,13 @@ import useLogo from '@theme/hooks/useLogo';
const Example = () => { const Example = () => {
// highlight-next-line // highlight-next-line
const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo(); const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
return ( return (
<Link to={logoLink} {...logoLinkProps}> <Link to={logoLink} {...logoLinkProps}>
{logoImageUrl != null && ( {logoImageUrl != null && <img src={logoImageUrl} alt={logoAlt} />}
<img
src={logoImageUrl}
alt={logoAlt}
/>
)}
</Link> </Link>
) );
}; };
``` ```
@ -107,7 +102,6 @@ React Router should automatically apply active link styling to links, but you ca
Outbound (external) links automatically get `target="_blank" rel="noopener noreferrer"` attributes. Outbound (external) links automatically get `target="_blank" rel="noopener noreferrer"` attributes.
## Footer ## Footer
You can add logo and a copyright to the footer via `themeConfig.footer`. Logo can be placed in [static folder](static-assets.md). Logo URL works in the same way of the navbar logo. You can add logo and a copyright to the footer via `themeConfig.footer`. Logo can be placed in [static folder](static-assets.md). Logo URL works in the same way of the navbar logo.
@ -125,58 +119,58 @@ You can add logo and a copyright to the footer via `themeConfig.footer`. Logo ca
``` ```
## Footer Links ## Footer Links
You can add links to the navbar via `themeConfig.footer.links`:
You can add links to the navbar via `themeConfig.footer.links`:
```js {5-15} title="docusaurus.config.js" ```js {5-15} title="docusaurus.config.js"
module.exports = { module.exports = {
// ... // ...
footer: { footer: {
links: [ links: [
{ {
// Label of the section of these links // Label of the section of these links
title: 'Docs', title: 'Docs',
items: [ items: [
{ {
// Label of the link // Label of the link
label: 'Style Guide', label: 'Style Guide',
// Client-side routing, used for navigating within the website. // Client-side routing, used for navigating within the website.
// The baseUrl will be automatically prepended to this value. // The baseUrl will be automatically prepended to this value.
to: 'docs/', to: 'docs/',
}, },
{ {
label: 'Second Doc', label: 'Second Doc',
to: 'docs/doc2/', to: 'docs/doc2/',
}, },
], ],
}, },
{ {
title: 'Community', title: 'Community',
items: [ items: [
{ {
label: 'Stack Overflow', label: 'Stack Overflow',
// A full-page navigation, used for navigating outside of the website. // A full-page navigation, used for navigating outside of the website.
href: 'https://stackoverflow.com/questions/tagged/docusaurus', href: 'https://stackoverflow.com/questions/tagged/docusaurus',
}, },
{ {
label: 'Discord', label: 'Discord',
href: 'https://discordapp.com/invite/docusaurus', href: 'https://discordapp.com/invite/docusaurus',
}, },
{ {
label: 'Twitter', label: 'Twitter',
href: 'https://twitter.com/docusaurus', href: 'https://twitter.com/docusaurus',
}, },
{ {
//Renders the html pass-through instead of a simple link //Renders the html pass-through instead of a simple link
html: ` html: `
<a href="https://www.netlify.com" target="_blank" rel="noreferrer noopener" aria-label="Deploys by Netlify"> <a href="https://www.netlify.com" target="_blank" rel="noreferrer noopener" aria-label="Deploys by Netlify">
<img src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" alt="Deploys by Netlify" /> <img src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" alt="Deploys by Netlify" />
</a> </a>
`, `,
}, },
], ],
}, },
], ],
}, },
}; };
``` ```