diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.js b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.js
index 2cb8b91ef92b..706aff7bfdbd 100644
--- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.js
+++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.js
@@ -11,14 +11,19 @@ const {ThemeConfigSchema, DEFAULT_CONFIG} = require('../validateThemeConfig');
const {normalizeThemeConfig} = require('@docusaurus/utils-validation');
-function testValidateThemeConfig(themeConfig) {
- return normalizeThemeConfig(ThemeConfigSchema, themeConfig);
+function testValidateThemeConfig(partialThemeConfig) {
+ return normalizeThemeConfig(ThemeConfigSchema, {
+ ...DEFAULT_CONFIG,
+ ...partialThemeConfig,
+ });
}
-function testOk(partialConfig) {
- expect(testValidateThemeConfig(partialConfig)).toEqual({
+function testOk(partialThemeConfig) {
+ expect(
+ testValidateThemeConfig({...DEFAULT_CONFIG, ...partialThemeConfig}),
+ ).toEqual({
...DEFAULT_CONFIG,
- ...partialConfig,
+ ...partialThemeConfig,
});
}
@@ -101,7 +106,10 @@ describe('themeConfig', () => {
};
expect(testValidateThemeConfig(altTagConfig)).toEqual({
...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', () => {
testOk({
customCss: undefined,
diff --git a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
index de339ea493a9..95b147b94e20 100644
--- a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
@@ -7,21 +7,23 @@
import React from 'react';
import clsx from 'clsx';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import useThemeConfig from '../../utils/useThemeConfig';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import styles from './styles.module.css';
function AnnouncementBar(): JSX.Element | null {
- const {
- siteConfig: {themeConfig: {announcementBar = {}} = {}} = {},
- } = useDocusaurusContext();
- const {content, backgroundColor, textColor, isCloseable} = announcementBar;
const {
isAnnouncementBarClosed,
closeAnnouncementBar,
} = useUserPreferencesContext();
+ const {announcementBar} = useThemeConfig();
+
+ if (!announcementBar) {
+ return null;
+ }
+ const {content, backgroundColor, textColor, isCloseable} = announcementBar;
if (!content || (isCloseable && isAnnouncementBarClosed)) {
return null;
}
diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
index 458dd2c1d061..416cb4030782 100644
--- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
@@ -12,11 +12,11 @@ import clsx from 'clsx';
import Highlight, {defaultProps} from 'prism-react-renderer';
import copy from 'copy-text-to-clipboard';
import rangeParser from 'parse-numeric-range';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import usePrismTheme from '@theme/hooks/usePrismTheme';
import type {Props} from '@theme/CodeBlock';
import styles from './styles.module.css';
+import useThemeConfig from '../../utils/useThemeConfig';
const highlightLinesRangeRegex = /{([\d,-]+)}/;
const getHighlightDirectiveRegex = (
@@ -93,11 +93,7 @@ export default ({
className: languageClassName,
metastring,
}: Props): JSX.Element => {
- const {
- siteConfig: {
- themeConfig: {prism = {}},
- },
- } = useDocusaurusContext();
+ const {prism} = useThemeConfig();
const [showCopied, setShowCopied] = useState(false);
const [mounted, setMounted] = useState(false);
diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx
index 3a6b2eef7c3f..eab7e8988070 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx
@@ -24,7 +24,7 @@ import {
} from '@theme/hooks/useDocs';
function DocItem(props: Props): JSX.Element {
- const {siteConfig = {}} = useDocusaurusContext();
+ const {siteConfig} = useDocusaurusContext();
const {url: siteUrl, title: siteTitle, titleDelimiter} = siteConfig;
const {content: DocContent} = props;
const {metadata} = DocContent;
diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
index e1f4e42d072e..1a76709f4ffb 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
@@ -8,6 +8,7 @@
import React, {useState, useCallback, useEffect, useRef} from 'react';
import clsx from 'clsx';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import useThemeConfig from '../../utils/useThemeConfig';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
@@ -171,11 +172,9 @@ function DocSidebar({
}: Props): JSX.Element | null {
const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false);
const {
- siteConfig: {
- themeConfig: {navbar: {title = '', hideOnScroll = false} = {}} = {},
- } = {},
- isClient,
- } = useDocusaurusContext();
+ navbar: {title, hideOnScroll},
+ } = useThemeConfig();
+ const {isClient} = useDocusaurusContext();
const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
const {isAnnouncementBarClosed} = useUserPreferencesContext();
const {scrollY} = useScrollPosition();
diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
index a942520f1b9f..5cb11111cdfb 100644
--- a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
@@ -9,7 +9,7 @@ import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import useThemeConfig from '../../utils/useThemeConfig';
import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css';
@@ -40,10 +40,7 @@ const FooterLogo = ({url, alt}) => (
);
function Footer(): JSX.Element | null {
- const context = useDocusaurusContext();
- const {siteConfig = {}} = context;
- const {themeConfig = {}} = siteConfig;
- const {footer} = themeConfig;
+ const {footer} = useThemeConfig();
const {copyright, links = [], logo = {}} = footer || {};
const logoUrl = useBaseUrl(logo.src);
diff --git a/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx b/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
index 8724028afa92..9d4b1d4cb4ca 100644
--- a/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
@@ -9,8 +9,8 @@
import React from 'react';
import clsx from 'clsx';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import type {HeadingType, Props} from '@theme/Heading';
+import useThemeConfig from '../../utils/useThemeConfig';
import './styles.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) =>
function TargetComponent({id, ...props}) {
const {
- siteConfig: {
- themeConfig: {navbar: {hideOnScroll = false} = {}} = {},
- } = {},
- } = useDocusaurusContext();
+ navbar: {hideOnScroll},
+ } = useThemeConfig();
if (!id) {
return ;
diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
index fe606ba63e92..89addc41ebe7 100644
--- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
@@ -13,6 +13,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle';
import useThemeContext from '@theme/hooks/useThemeContext';
+import useThemeConfig from '../../utils/useThemeConfig';
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
@@ -40,20 +41,13 @@ function splitNavItemsByPosition(items) {
}
function Navbar(): JSX.Element {
+ const {isClient} = useDocusaurusContext();
+
const {
- siteConfig: {
- themeConfig: {
- navbar: {
- title = '',
- items = [],
- hideOnScroll = false,
- style = undefined,
- } = {},
- colorMode: {disableSwitch: disableColorModeSwitch = false} = {},
- },
- },
- isClient,
- } = useDocusaurusContext();
+ navbar: {title, items, hideOnScroll, style},
+ colorMode: {disableSwitch: disableColorModeSwitch},
+ } = useThemeConfig();
+
const [sidebarShown, setSidebarShown] = useState(false);
const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false);
diff --git a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
index 3ab914e4a242..07eea1e64fa5 100644
--- a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
@@ -7,7 +7,7 @@
import React, {ComponentProps} from 'react';
import Toggle from 'react-toggle';
-
+import useThemeConfig from '../../utils/useThemeConfig';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import clsx from 'clsx';
@@ -26,20 +26,11 @@ const Light = ({icon, style}) => (
export default function (props: ComponentProps): JSX.Element {
const {
- siteConfig: {
- themeConfig: {
- colorMode: {
- switchConfig: {
- darkIcon,
- darkIconStyle,
- lightIcon,
- lightIconStyle,
- },
- },
- },
- },
- isClient
- } = useDocusaurusContext();
+ colorMode: {
+ switchConfig: {darkIcon, darkIconStyle, lightIcon, lightIconStyle},
+ },
+ } = useThemeConfig();
+ const {isClient} = useDocusaurusContext();
return (
{
- const {announcementBar} = useDocusaurusContext().siteConfig.themeConfig;
+ const {announcementBar} = useThemeConfig();
const [isClosed, setClosed] = useState(true);
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
index 198a33a3f7d7..39377ada6906 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
@@ -5,16 +5,16 @@
* LICENSE file in the root directory of this source tree.
*/
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl';
import type {LogoLinkProps, useLogoReturns} from '@theme/hooks/useLogo';
+import useThemeConfig from '../../utils/useThemeConfig';
const useLogo = (): useLogoReturns => {
const {
- siteConfig: {themeConfig: {navbar: {logo = {}} = {}} = {}} = {},
- } = useDocusaurusContext();
+ navbar: {logo},
+ } = useThemeConfig();
const {isDarkTheme} = useThemeContext();
const logoLink = useBaseUrl(logo.href || '/');
let logoLinkProps: LogoLinkProps = {};
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts b/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
index 90ac0a4673f4..e8287d3cd9e3 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
@@ -6,15 +6,11 @@
*/
import defaultTheme from 'prism-react-renderer/themes/palenight';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext';
+import useThemeConfig from '../../utils/useThemeConfig';
const usePrismTheme = (): typeof defaultTheme => {
- const {
- siteConfig: {
- themeConfig: {prism = {}},
- },
- } = useDocusaurusContext();
+ const {prism} = useThemeConfig();
const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme;
const darkModeTheme = prism.darkTheme || lightModeTheme;
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
index 24d3c770cde6..74265b0eac31 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
@@ -7,9 +7,9 @@
import {useState, useCallback, useEffect} from 'react';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import type {useThemeReturns} from '@theme/hooks/useTheme';
+import useThemeConfig from '../../utils/useThemeConfig';
const themes = {
light: 'light',
@@ -38,10 +38,8 @@ const storeTheme = (newTheme) => {
const useTheme = (): useThemeReturns => {
const {
- siteConfig: {
- themeConfig: {colorMode: {disableSwitch = false} = {}} = {},
- } = {},
- } = useDocusaurusContext();
+ colorMode: {disableSwitch = false},
+ } = useThemeConfig();
const [theme, setTheme] = useState(getInitialTheme);
const setLightTheme = useCallback(() => {
diff --git a/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts
new file mode 100644
index 000000000000..db8b66a6b6d3
--- /dev/null
+++ b/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts
@@ -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;
+}
diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.js b/packages/docusaurus-theme-classic/src/validateThemeConfig.js
index f365bfd05d0f..6b86e99b4098 100644
--- a/packages/docusaurus-theme-classic/src/validateThemeConfig.js
+++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.js
@@ -23,6 +23,13 @@ const DEFAULT_COLOR_MODE_CONFIG = {
const DEFAULT_CONFIG = {
colorMode: DEFAULT_COLOR_MODE_CONFIG,
metadatas: [],
+ prism: {
+ additionalLanguages: [],
+ },
+ navbar: {
+ hideOnScroll: false,
+ items: [],
+ },
};
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
@@ -195,13 +202,15 @@ const ThemeConfigSchema = Joi.object({
}).optional(),
navbar: Joi.object({
style: Joi.string().equal('dark', 'primary'),
- hideOnScroll: Joi.bool().default(false),
+ hideOnScroll: Joi.bool().default(DEFAULT_CONFIG.navbar.hideOnScroll),
// TODO temporary (@alpha-58)
links: Joi.any().forbidden().messages({
'any.unknown':
'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),
logo: Joi.object({
alt: Joi.string().allow(''),
@@ -210,7 +219,7 @@ const ThemeConfigSchema = Joi.object({
href: Joi.string(),
target: Joi.string(),
}),
- }),
+ }).default(DEFAULT_CONFIG.navbar),
footer: Joi.object({
style: Joi.string().equal('dark', 'light').default('light'),
logo: Joi.object({
@@ -219,13 +228,15 @@ const ThemeConfigSchema = Joi.object({
href: Joi.string(),
}),
copyright: Joi.string(),
- links: Joi.array().items(
- Joi.object({
- title: Joi.string().required(),
- items: Joi.array().items(FooterLinkItemSchema).default([]),
- }),
- ),
- }),
+ links: Joi.array()
+ .items(
+ Joi.object({
+ title: Joi.string().required(),
+ items: Joi.array().items(FooterLinkItemSchema).default([]),
+ }),
+ )
+ .default([]),
+ }).optional(),
prism: Joi.object({
theme: Joi.object({
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(),
}),
defaultLanguage: Joi.string(),
- additionalLanguages: Joi.array().items(Joi.string()),
- }).unknown(),
+ additionalLanguages: Joi.array()
+ .items(Joi.string())
+ .default(DEFAULT_CONFIG.prism.additionalLanguages),
+ })
+ .default(DEFAULT_CONFIG.prism)
+ .unknown(),
});
exports.ThemeConfigSchema = ThemeConfigSchema;
diff --git a/website/versioned_docs/version-2.0.0-alpha.64/theme-bootstrap.md b/website/versioned_docs/version-2.0.0-alpha.64/theme-bootstrap.md
index c5abde38f948..7331da5a6fd1 100644
--- a/website/versioned_docs/version-2.0.0-alpha.64/theme-bootstrap.md
+++ b/website/versioned_docs/version-2.0.0-alpha.64/theme-bootstrap.md
@@ -24,18 +24,13 @@ import useLogo from '@theme/hooks/useLogo';
const Example = () => {
// highlight-next-line
- const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
+ const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
return (
- {logoImageUrl != null && (
-
- )}
+ {logoImageUrl != null && }
- )
+ );
};
```
@@ -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.
-
## 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.
@@ -125,58 +119,58 @@ You can add logo and a copyright to the footer via `themeConfig.footer`. Logo ca
```
## 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"
module.exports = {
// ...
footer: {
- links: [
- {
- // Label of the section of these links
- title: 'Docs',
- items: [
- {
- // Label of the link
- label: 'Style Guide',
- // Client-side routing, used for navigating within the website.
- // The baseUrl will be automatically prepended to this value.
- to: 'docs/',
- },
- {
- label: 'Second Doc',
- to: 'docs/doc2/',
- },
- ],
- },
- {
- title: 'Community',
- items: [
- {
- label: 'Stack Overflow',
- // A full-page navigation, used for navigating outside of the website.
- href: 'https://stackoverflow.com/questions/tagged/docusaurus',
- },
- {
- label: 'Discord',
- href: 'https://discordapp.com/invite/docusaurus',
- },
- {
- label: 'Twitter',
- href: 'https://twitter.com/docusaurus',
- },
- {
- //Renders the html pass-through instead of a simple link
- html: `
+ links: [
+ {
+ // Label of the section of these links
+ title: 'Docs',
+ items: [
+ {
+ // Label of the link
+ label: 'Style Guide',
+ // Client-side routing, used for navigating within the website.
+ // The baseUrl will be automatically prepended to this value.
+ to: 'docs/',
+ },
+ {
+ label: 'Second Doc',
+ to: 'docs/doc2/',
+ },
+ ],
+ },
+ {
+ title: 'Community',
+ items: [
+ {
+ label: 'Stack Overflow',
+ // A full-page navigation, used for navigating outside of the website.
+ href: 'https://stackoverflow.com/questions/tagged/docusaurus',
+ },
+ {
+ label: 'Discord',
+ href: 'https://discordapp.com/invite/docusaurus',
+ },
+ {
+ label: 'Twitter',
+ href: 'https://twitter.com/docusaurus',
+ },
+ {
+ //Renders the html pass-through instead of a simple link
+ html: `
`,
- },
- ],
- },
- ],
- },
+ },
+ ],
+ },
+ ],
+ },
};
```