refactor(v2): toggle data-theme with vanilla js instead of react helmet (#2127)

* refactor(v2): toggle data-theme with vanilla js instead of react helmet

* use document documentElement
This commit is contained in:
Endi 2019-12-16 07:57:24 +07:00 committed by Yangshun Tay
parent ee00ecf569
commit 33622c5347
4 changed files with 114 additions and 116 deletions

View file

@ -12,7 +12,7 @@ const path = require('path');
const storageKey = 'theme'; const storageKey = 'theme';
const noFlash = `(function() { const noFlash = `(function() {
function setDataThemeAttribute(theme) { function setDataThemeAttribute(theme) {
document.querySelector('html').setAttribute('data-theme', theme); document.documentElement.setAttribute('data-theme', theme);
} }
function getPreferredTheme() { function getPreferredTheme() {

View file

@ -7,7 +7,6 @@
import React, {useCallback, useState} from 'react'; import React, {useCallback, useState} from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
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';
@ -68,122 +67,116 @@ function Navbar() {
const logoUrl = useBaseUrl(logo.src); const logoUrl = useBaseUrl(logo.src);
return ( return (
<> <nav
<Head> ref={navbarRef}
{/* TODO: Do not assume that it is in english language */} className={classnames('navbar', 'navbar--light', 'navbar--fixed-top', {
<html lang="en" data-theme={theme} /> 'navbar-sidebar--show': sidebarShown,
</Head> [styles.navbarHideable]: hideOnScroll,
<nav [styles.navbarHidden]: !isNavbarVisible,
ref={navbarRef} })}>
className={classnames('navbar', 'navbar--light', 'navbar--fixed-top', { <div className="navbar__inner">
'navbar-sidebar--show': sidebarShown, <div className="navbar__items">
[styles.navbarHideable]: hideOnScroll, <div
[styles.navbarHidden]: !isNavbarVisible, aria-label="Navigation bar toggle"
})}> className="navbar__toggle"
<div className="navbar__inner"> role="button"
<div className="navbar__items"> tabIndex={0}
<div onClick={showSidebar}
aria-label="Navigation bar toggle" onKeyDown={showSidebar}>
className="navbar__toggle" <svg
role="button" xmlns="http://www.w3.org/2000/svg"
tabIndex={0} width="30"
onClick={showSidebar} height="30"
onKeyDown={showSidebar}> viewBox="0 0 30 30"
<svg role="img"
xmlns="http://www.w3.org/2000/svg" focusable="false">
width="30" <title>Menu</title>
height="30" <path
viewBox="0 0 30 30" stroke="currentColor"
role="img" strokeLinecap="round"
focusable="false"> strokeMiterlimit="10"
<title>Menu</title> strokeWidth="2"
<path d="M4 7h22M4 15h22M4 23h22"
stroke="currentColor"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="2"
d="M4 7h22M4 15h22M4 23h22"
/>
</svg>
</div>
<Link className="navbar__brand" to={baseUrl}>
{logo != null && (
<img className="navbar__logo" src={logoUrl} alt={logo.alt} />
)}
{title != null && (
<strong
className={isSearchBarExpanded ? styles.hideLogoText : ''}>
{title}
</strong>
)}
</Link>
{links
.filter(linkItem => linkItem.position !== 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
</div>
<div className="navbar__items navbar__items--right">
{links
.filter(linkItem => linkItem.position === 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
{!disableDarkMode && (
<Toggle
className={styles.displayOnlyInLargeViewport}
aria-label="Dark mode toggle"
checked={theme === 'dark'}
onChange={onToggleChange}
/> />
</svg>
</div>
<Link className="navbar__brand" to={baseUrl}>
{logo != null && (
<img className="navbar__logo" src={logoUrl} alt={logo.alt} />
)} )}
<SearchBar {title != null && (
handleSearchBarToggle={setIsSearchBarExpanded} <strong
isSearchBarExpanded={isSearchBarExpanded} className={isSearchBarExpanded ? styles.hideLogoText : ''}>
{title}
</strong>
)}
</Link>
{links
.filter(linkItem => linkItem.position !== 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
</div>
<div className="navbar__items navbar__items--right">
{links
.filter(linkItem => linkItem.position === 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
{!disableDarkMode && (
<Toggle
className={styles.displayOnlyInLargeViewport}
aria-label="Dark mode toggle"
checked={theme === 'dark'}
onChange={onToggleChange}
/> />
</div> )}
<SearchBar
handleSearchBarToggle={setIsSearchBarExpanded}
isSearchBarExpanded={isSearchBarExpanded}
/>
</div> </div>
<div </div>
role="presentation" <div
className="navbar-sidebar__backdrop" role="presentation"
onClick={() => { className="navbar-sidebar__backdrop"
setSidebarShown(false); onClick={() => {
}} setSidebarShown(false);
/> }}
<div className="navbar-sidebar"> />
<div className="navbar-sidebar__brand"> <div className="navbar-sidebar">
<Link className="navbar__brand" onClick={hideSidebar} to={baseUrl}> <div className="navbar-sidebar__brand">
{logo != null && ( <Link className="navbar__brand" onClick={hideSidebar} to={baseUrl}>
<img className="navbar__logo" src={logoUrl} alt={logo.alt} /> {logo != null && (
)} <img className="navbar__logo" src={logoUrl} alt={logo.alt} />
{title != null && <strong>{title}</strong>}
</Link>
{!disableDarkMode && sidebarShown && (
<Toggle
aria-label="Dark mode toggle in sidebar"
checked={theme === 'dark'}
onChange={onToggleChange}
/>
)} )}
</div> {title != null && <strong>{title}</strong>}
<div className="navbar-sidebar__items"> </Link>
<div className="menu"> {!disableDarkMode && sidebarShown && (
<ul className="menu__list"> <Toggle
{links.map((linkItem, i) => ( aria-label="Dark mode toggle in sidebar"
<li className="menu__list-item" key={i}> checked={theme === 'dark'}
<NavLink onChange={onToggleChange}
className="menu__link" />
{...linkItem} )}
onClick={hideSidebar} </div>
/> <div className="navbar-sidebar__items">
</li> <div className="menu">
))} <ul className="menu__list">
</ul> {links.map((linkItem, i) => (
</div> <li className="menu__list-item" key={i}>
<NavLink
className="menu__link"
{...linkItem}
onClick={hideSidebar}
/>
</li>
))}
</ul>
</div> </div>
</div> </div>
</nav> </div>
</> </nav>
); );
} }

View file

@ -9,9 +9,14 @@ import * as React from 'react';
const useTheme = () => { const useTheme = () => {
const [theme, setTheme] = React.useState( const [theme, setTheme] = React.useState(
typeof document !== 'undefined' typeof document !== 'undefined'
? document.querySelector('html').getAttribute('data-theme') ? document.documentElement.getAttribute('data-theme')
: '', : '',
); );
React.useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
}, [theme]);
React.useEffect(() => { React.useEffect(() => {
try { try {
const localStorageTheme = localStorage.getItem('theme'); const localStorageTheme = localStorage.getItem('theme');

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 React, {useEffect} from 'react'; import React, {useEffect, useRef} from 'react';
import {NavLink} from 'react-router-dom'; import {NavLink} from 'react-router-dom';
const internalRegex = /^\/(?!\/)/; const internalRegex = /^\/(?!\/)/;
@ -14,7 +14,7 @@ function Link(props) {
const {to, href} = props; const {to, href} = props;
const targetLink = to || href; const targetLink = to || href;
const isInternal = internalRegex.test(targetLink); const isInternal = internalRegex.test(targetLink);
let preloaded = false; const preloaded = useRef(false);
const IOSupported = const IOSupported =
typeof window !== 'undefined' && 'IntersectionObserver' in window; typeof window !== 'undefined' && 'IntersectionObserver' in window;
@ -48,9 +48,9 @@ function Link(props) {
}; };
const onMouseEnter = () => { const onMouseEnter = () => {
if (!preloaded) { if (!preloaded.current) {
window.docusaurus.preload(targetLink); window.docusaurus.preload(targetLink);
preloaded = true; preloaded.current = true;
} }
}; };