feat(v2): add support another Prism theme for dark mode (#1984)

* feat(v2): add support another Prism theme for dark mode

* add dynamically change Prism theme

* Prepare for review

* PR review changes

* feat(v2): useThemeContext

Co-authored-by: Yangshun Tay <tay.yang.shun@gmail.com>
This commit is contained in:
Alexey Pyltsyn 2019-12-25 17:52:34 +03:00 committed by Yangshun Tay
parent dad50823b6
commit 92c68ed742
9 changed files with 84 additions and 9 deletions

View file

@ -12,6 +12,8 @@ import defaultTheme from 'prism-react-renderer/themes/palenight';
import Clipboard from 'clipboard'; import Clipboard from 'clipboard';
import rangeParser from 'parse-numeric-range'; import rangeParser from 'parse-numeric-range';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext';
import styles from './styles.module.css'; import styles from './styles.module.css';
const highlightLinesRangeRegex = /{([\d,-]+)}/; const highlightLinesRangeRegex = /{([\d,-]+)}/;
@ -26,6 +28,9 @@ export default ({children, className: languageClassName, metastring}) => {
const target = useRef(null); const target = useRef(null);
const button = useRef(null); const button = useRef(null);
let highlightLines = []; let highlightLines = [];
const {theme} = useThemeContext();
const prismTheme =
theme === 'dark' ? prism.darkTheme : prism.theme || defaultTheme;
if (metastring && highlightLinesRangeRegex.test(metastring)) { if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1]; const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
@ -65,7 +70,7 @@ export default ({children, className: languageClassName, metastring}) => {
return ( return (
<Highlight <Highlight
{...defaultProps} {...defaultProps}
theme={prism.theme || defaultTheme} theme={prismTheme}
code={children.trim()} code={children.trim()}
language={language}> language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => ( {({className, style, tokens, getLineProps, getTokenProps}) => (

View file

@ -9,6 +9,8 @@ import React from 'react';
import Head from '@docusaurus/Head'; import Head from '@docusaurus/Head';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import ThemeProvider from '@theme/ThemeProvider';
import Navbar from '@theme/Navbar'; import Navbar from '@theme/Navbar';
import Footer from '@theme/Footer'; import Footer from '@theme/Footer';
@ -37,8 +39,9 @@ function Layout(props) {
const metaImage = image || defaultImage; const metaImage = image || defaultImage;
const metaImageUrl = siteUrl + useBaseUrl(metaImage); const metaImageUrl = siteUrl + useBaseUrl(metaImage);
const faviconUrl = useBaseUrl(favicon); const faviconUrl = useBaseUrl(favicon);
return ( return (
<> <ThemeProvider>
<Head> <Head>
{/* TODO: Do not assume that it is in english language */} {/* TODO: Do not assume that it is in english language */}
<html lang="en" /> <html lang="en" />
@ -66,7 +69,7 @@ function Layout(props) {
<Navbar /> <Navbar />
<div className="main-wrapper">{children}</div> <div className="main-wrapper">{children}</div>
{!noFooter && <Footer />} {!noFooter && <Footer />}
</> </ThemeProvider>
); );
} }

View file

@ -15,7 +15,7 @@ import Toggle from '@theme/Toggle';
import classnames from 'classnames'; import classnames from 'classnames';
import useTheme from '@theme/hooks/useTheme'; import useThemeContext from '@theme/hooks/useThemeContext';
import useHideableNavbar from '@theme/hooks/useHideableNavbar'; import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -47,10 +47,11 @@ function Navbar() {
const {baseUrl, themeConfig = {}} = siteConfig; const {baseUrl, themeConfig = {}} = siteConfig;
const {navbar = {}, disableDarkMode = false} = themeConfig; const {navbar = {}, disableDarkMode = false} = themeConfig;
const {title, logo = {}, links = [], hideOnScroll = false} = navbar; const {title, logo = {}, links = [], hideOnScroll = false} = navbar;
const [sidebarShown, setSidebarShown] = useState(false); const [sidebarShown, setSidebarShown] = useState(false);
const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false); const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false);
const [theme, setTheme] = useTheme();
const {theme, setTheme} = useThemeContext();
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll); const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
const showSidebar = useCallback(() => { const showSidebar = useCallback(() => {
@ -63,7 +64,10 @@ function Navbar() {
}, [setSidebarShown]); }, [setSidebarShown]);
const onToggleChange = useCallback( const onToggleChange = useCallback(
e => setTheme(e.target.checked ? 'dark' : ''), e => {
const newTheme = e.target.checked ? 'dark' : '';
setTheme(newTheme);
},
[setTheme], [setTheme],
); );

View file

@ -0,0 +1,15 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* 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';
const ThemeContext = React.createContext({
theme: null,
setTheme: () => {},
});
export default ThemeContext;

View file

@ -0,0 +1,23 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* 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 useTheme from '@theme/hooks/useTheme';
import ThemeContext from '@theme/ThemeContext';
function ThemeProvider(props) {
const [theme, setTheme] = useTheme();
return (
<ThemeContext.Provider value={{theme, setTheme}}>
{props.children}
</ThemeContext.Provider>
);
}
export default ThemeProvider;

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import * as React from 'react'; import React from 'react';
const useTheme = () => { const useTheme = () => {
const [theme, setTheme] = React.useState( const [theme, setTheme] = React.useState(

View file

@ -0,0 +1,16 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useContext} from 'react';
import ThemeContext from '@theme/ThemeContext';
function useThemeContext() {
return useContext(ThemeContext);
}
export default useThemeContext;

View file

@ -12,7 +12,9 @@ import defaultTheme from 'prism-react-renderer/themes/palenight';
import Clipboard from 'clipboard'; import Clipboard from 'clipboard';
import rangeParser from 'parse-numeric-range'; import rangeParser from 'parse-numeric-range';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext';
import Playground from '@theme/Playground'; import Playground from '@theme/Playground';
import styles from './styles.module.css'; import styles from './styles.module.css';
const highlightLinesRangeRegex = /{([\d,-]+)}/; const highlightLinesRangeRegex = /{([\d,-]+)}/;
@ -33,6 +35,9 @@ export default ({
const target = useRef(null); const target = useRef(null);
const button = useRef(null); const button = useRef(null);
let highlightLines = []; let highlightLines = [];
const {theme} = useThemeContext();
const prismTheme =
theme === 'dark' ? prism.darkTheme : prism.theme || defaultTheme;
if (metastring && highlightLinesRangeRegex.test(metastring)) { if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1]; const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
@ -60,7 +65,7 @@ export default ({
<Playground <Playground
scope={{...React}} scope={{...React}}
code={children.trim()} code={children.trim()}
theme={prism.theme || defaultTheme} theme={prismTheme}
{...props} {...props}
/> />
); );
@ -83,7 +88,7 @@ export default ({
return ( return (
<Highlight <Highlight
{...defaultProps} {...defaultProps}
theme={prism.theme || defaultTheme} theme={prismTheme}
code={children.trim()} code={children.trim()}
language={language}> language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => ( {({className, style, tokens, getLineProps, getTokenProps}) => (

View file

@ -59,6 +59,10 @@ module.exports = {
], ],
], ],
themeConfig: { themeConfig: {
prism: {
theme: require('prism-react-renderer/themes/github'),
darkTheme: require('prism-react-renderer/themes/dracula'),
},
image: 'img/docusaurus.png', image: 'img/docusaurus.png',
gtag: { gtag: {
trackingID: 'UA-141789564-1', trackingID: 'UA-141789564-1',