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');
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,

View file

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

View file

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

View file

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

View file

@ -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();

View file

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

View file

@ -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 <Tag {...props} />;

View file

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

View file

@ -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<typeof Toggle>): JSX.Element {
const {
siteConfig: {
themeConfig: {
colorMode: {
switchConfig: {
darkIcon,
darkIconStyle,
lightIcon,
lightIconStyle,
switchConfig: {darkIcon, darkIconStyle, lightIcon, lightIconStyle},
},
},
},
},
isClient
} = useDocusaurusContext();
} = useThemeConfig();
const {isClient} = useDocusaurusContext();
return (
<Toggle

View file

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

View file

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

View file

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

View file

@ -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(() => {

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 = {
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(
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;

View file

@ -28,14 +28,9 @@ const Example = () => {
return (
<Link to={logoLink} {...logoLinkProps}>
{logoImageUrl != null && (
<img
src={logoImageUrl}
alt={logoAlt}
/>
)}
{logoImageUrl != null && <img src={logoImageUrl} alt={logoAlt} />}
</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.
## 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,8 +119,8 @@ 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 = {