mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-03 11:22:30 +02:00
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:
parent
dad50823b6
commit
92c68ed742
9 changed files with 84 additions and 9 deletions
|
@ -12,6 +12,8 @@ import defaultTheme from 'prism-react-renderer/themes/palenight';
|
|||
import Clipboard from 'clipboard';
|
||||
import rangeParser from 'parse-numeric-range';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const highlightLinesRangeRegex = /{([\d,-]+)}/;
|
||||
|
@ -26,6 +28,9 @@ export default ({children, className: languageClassName, metastring}) => {
|
|||
const target = useRef(null);
|
||||
const button = useRef(null);
|
||||
let highlightLines = [];
|
||||
const {theme} = useThemeContext();
|
||||
const prismTheme =
|
||||
theme === 'dark' ? prism.darkTheme : prism.theme || defaultTheme;
|
||||
|
||||
if (metastring && highlightLinesRangeRegex.test(metastring)) {
|
||||
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
|
||||
|
@ -65,7 +70,7 @@ export default ({children, className: languageClassName, metastring}) => {
|
|||
return (
|
||||
<Highlight
|
||||
{...defaultProps}
|
||||
theme={prism.theme || defaultTheme}
|
||||
theme={prismTheme}
|
||||
code={children.trim()}
|
||||
language={language}>
|
||||
{({className, style, tokens, getLineProps, getTokenProps}) => (
|
||||
|
|
|
@ -9,6 +9,8 @@ import React from 'react';
|
|||
import Head from '@docusaurus/Head';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
import ThemeProvider from '@theme/ThemeProvider';
|
||||
import Navbar from '@theme/Navbar';
|
||||
import Footer from '@theme/Footer';
|
||||
|
||||
|
@ -37,8 +39,9 @@ function Layout(props) {
|
|||
const metaImage = image || defaultImage;
|
||||
const metaImageUrl = siteUrl + useBaseUrl(metaImage);
|
||||
const faviconUrl = useBaseUrl(favicon);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ThemeProvider>
|
||||
<Head>
|
||||
{/* TODO: Do not assume that it is in english language */}
|
||||
<html lang="en" />
|
||||
|
@ -66,7 +69,7 @@ function Layout(props) {
|
|||
<Navbar />
|
||||
<div className="main-wrapper">{children}</div>
|
||||
{!noFooter && <Footer />}
|
||||
</>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import Toggle from '@theme/Toggle';
|
|||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import useTheme from '@theme/hooks/useTheme';
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
@ -47,10 +47,11 @@ function Navbar() {
|
|||
const {baseUrl, themeConfig = {}} = siteConfig;
|
||||
const {navbar = {}, disableDarkMode = false} = themeConfig;
|
||||
const {title, logo = {}, links = [], hideOnScroll = false} = navbar;
|
||||
|
||||
const [sidebarShown, setSidebarShown] = useState(false);
|
||||
const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false);
|
||||
const [theme, setTheme] = useTheme();
|
||||
|
||||
const {theme, setTheme} = useThemeContext();
|
||||
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
|
||||
|
||||
const showSidebar = useCallback(() => {
|
||||
|
@ -63,7 +64,10 @@ function Navbar() {
|
|||
}, [setSidebarShown]);
|
||||
|
||||
const onToggleChange = useCallback(
|
||||
e => setTheme(e.target.checked ? 'dark' : ''),
|
||||
e => {
|
||||
const newTheme = e.target.checked ? 'dark' : '';
|
||||
setTheme(newTheme);
|
||||
},
|
||||
[setTheme],
|
||||
);
|
||||
|
||||
|
|
15
packages/docusaurus-theme-classic/src/theme/ThemeContext.js
Normal file
15
packages/docusaurus-theme-classic/src/theme/ThemeContext.js
Normal 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;
|
|
@ -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;
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
const useTheme = () => {
|
||||
const [theme, setTheme] = React.useState(
|
||||
|
|
|
@ -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;
|
|
@ -12,7 +12,9 @@ import defaultTheme from 'prism-react-renderer/themes/palenight';
|
|||
import Clipboard from 'clipboard';
|
||||
import rangeParser from 'parse-numeric-range';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
||||
import Playground from '@theme/Playground';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const highlightLinesRangeRegex = /{([\d,-]+)}/;
|
||||
|
@ -33,6 +35,9 @@ export default ({
|
|||
const target = useRef(null);
|
||||
const button = useRef(null);
|
||||
let highlightLines = [];
|
||||
const {theme} = useThemeContext();
|
||||
const prismTheme =
|
||||
theme === 'dark' ? prism.darkTheme : prism.theme || defaultTheme;
|
||||
|
||||
if (metastring && highlightLinesRangeRegex.test(metastring)) {
|
||||
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
|
||||
|
@ -60,7 +65,7 @@ export default ({
|
|||
<Playground
|
||||
scope={{...React}}
|
||||
code={children.trim()}
|
||||
theme={prism.theme || defaultTheme}
|
||||
theme={prismTheme}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -83,7 +88,7 @@ export default ({
|
|||
return (
|
||||
<Highlight
|
||||
{...defaultProps}
|
||||
theme={prism.theme || defaultTheme}
|
||||
theme={prismTheme}
|
||||
code={children.trim()}
|
||||
language={language}>
|
||||
{({className, style, tokens, getLineProps, getTokenProps}) => (
|
||||
|
|
|
@ -59,6 +59,10 @@ module.exports = {
|
|||
],
|
||||
],
|
||||
themeConfig: {
|
||||
prism: {
|
||||
theme: require('prism-react-renderer/themes/github'),
|
||||
darkTheme: require('prism-react-renderer/themes/dracula'),
|
||||
},
|
||||
image: 'img/docusaurus.png',
|
||||
gtag: {
|
||||
trackingID: 'UA-141789564-1',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue