mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-24 06:27:02 +02:00
refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook (#6930)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
This commit is contained in:
parent
8a1421a938
commit
ecbe0b26c5
12 changed files with 156 additions and 165 deletions
|
@ -746,12 +746,16 @@ declare module '@theme/TOCCollapsible' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/ColorModeToggle' {
|
declare module '@theme/ColorModeToggle' {
|
||||||
import type {SyntheticEvent} from 'react';
|
import type {ColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
readonly checked: boolean;
|
readonly value: ColorMode;
|
||||||
readonly onChange: (e: SyntheticEvent) => void;
|
/**
|
||||||
|
* The parameter represents the "to-be" value. For example, if currently in
|
||||||
|
* dark mode, clicking the button should call `onChange("light")`
|
||||||
|
*/
|
||||||
|
readonly onChange: (colorMode: ColorMode) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Toggle(props: Props): JSX.Element;
|
export default function Toggle(props: Props): JSX.Element;
|
||||||
|
|
|
@ -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, {useState, useRef, useEffect} from 'react';
|
import React from 'react';
|
||||||
import type {Props} from '@theme/ColorModeToggle';
|
import type {Props} from '@theme/ColorModeToggle';
|
||||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
@ -15,78 +15,51 @@ import IconDarkMode from '@theme/IconDarkMode';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function ColorModeToggle({
|
function ColorModeToggle({className, value, onChange}: Props): JSX.Element {
|
||||||
className,
|
|
||||||
checked: defaultChecked,
|
|
||||||
onChange,
|
|
||||||
}: Props): JSX.Element {
|
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser();
|
||||||
const [checked, setChecked] = useState(defaultChecked);
|
|
||||||
const [focused, setFocused] = useState(false);
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const title = translate(
|
||||||
setChecked(defaultChecked);
|
{
|
||||||
}, [defaultChecked]);
|
message: 'Switch between dark and light mode (currently {mode})',
|
||||||
|
id: 'theme.colorToggle.ariaLabel',
|
||||||
|
description: 'The ARIA label for the navbar color mode toggle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode:
|
||||||
|
value === 'dark'
|
||||||
|
? translate({
|
||||||
|
message: 'dark mode',
|
||||||
|
id: 'theme.colorToggle.ariaLabel.mode.dark',
|
||||||
|
description: 'The name for the dark color mode',
|
||||||
|
})
|
||||||
|
: translate({
|
||||||
|
message: 'light mode',
|
||||||
|
id: 'theme.colorToggle.ariaLabel.mode.light',
|
||||||
|
description: 'The name for the light color mode',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={clsx(styles.toggle, className)}>
|
||||||
className={clsx(
|
<button
|
||||||
styles.toggle,
|
className={clsx(
|
||||||
className,
|
'clean-btn',
|
||||||
checked && styles.toggleChecked,
|
styles.toggleButton,
|
||||||
focused && styles.toggleFocused,
|
!isBrowser && styles.toggleButtonDisabled,
|
||||||
!isBrowser && styles.toggleDisabled,
|
)}
|
||||||
)}>
|
type="button"
|
||||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
|
||||||
<div
|
disabled={!isBrowser}
|
||||||
className={styles.toggleButton}
|
title={title}
|
||||||
role="button"
|
aria-label={title}>
|
||||||
tabIndex={-1}
|
|
||||||
onClick={() => inputRef.current?.click()}>
|
|
||||||
<IconLightMode
|
<IconLightMode
|
||||||
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
|
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
|
||||||
/>
|
/>
|
||||||
<IconDarkMode
|
<IconDarkMode
|
||||||
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
|
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<input
|
|
||||||
ref={inputRef}
|
|
||||||
checked={checked}
|
|
||||||
type="checkbox"
|
|
||||||
className={styles.toggleScreenReader}
|
|
||||||
aria-label={translate(
|
|
||||||
{
|
|
||||||
message: 'Switch between dark and light mode (currently {mode})',
|
|
||||||
id: 'theme.colorToggle.ariaLabel',
|
|
||||||
description: 'The ARIA label for the navbar color mode toggle',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: checked
|
|
||||||
? translate({
|
|
||||||
message: 'dark mode',
|
|
||||||
id: 'theme.colorToggle.ariaLabel.mode.dark',
|
|
||||||
description: 'The name for the dark color mode',
|
|
||||||
})
|
|
||||||
: translate({
|
|
||||||
message: 'light mode',
|
|
||||||
id: 'theme.colorToggle.ariaLabel.mode.light',
|
|
||||||
description: 'The name for the light color mode',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
onChange={onChange}
|
|
||||||
onClick={() => setChecked(!checked)}
|
|
||||||
onFocus={() => setFocused(true)}
|
|
||||||
onBlur={() => setFocused(false)}
|
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
inputRef.current?.click();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,28 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
position: relative;
|
width: 2rem;
|
||||||
width: 32px;
|
height: 2rem;
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggleScreenReader {
|
|
||||||
border: 0;
|
|
||||||
clip: rect(0 0 0 0);
|
|
||||||
height: 1px;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggleDisabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleButton {
|
.toggleButton {
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -35,17 +18,18 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
transition: background var(--ifm-transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleButton:hover {
|
.toggleButton:hover {
|
||||||
background-color: #00000010;
|
background: var(--ifm-color-emphasis-200);
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .toggleButton:hover {
|
|
||||||
background-color: #ffffff20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='light'] .darkToggleIcon,
|
[data-theme='light'] .darkToggleIcon,
|
||||||
[data-theme='dark'] .lightToggleIcon {
|
[data-theme='dark'] .lightToggleIcon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggleButtonDisabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
|
@ -88,12 +88,12 @@ function useColorModeToggle() {
|
||||||
const {
|
const {
|
||||||
colorMode: {disableSwitch},
|
colorMode: {disableSwitch},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
|
const {colorMode, setColorMode} = useColorMode();
|
||||||
const toggle = useCallback(
|
return {
|
||||||
(e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
|
value: colorMode,
|
||||||
[setLightTheme, setDarkTheme],
|
onChange: setColorMode,
|
||||||
);
|
disabled: disableSwitch,
|
||||||
return {isDarkTheme, toggle, disabled: disableSwitch};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function useSecondaryMenu({
|
function useSecondaryMenu({
|
||||||
|
@ -173,8 +173,8 @@ function NavbarMobileSidebar({
|
||||||
{!colorModeToggle.disabled && (
|
{!colorModeToggle.disabled && (
|
||||||
<ColorModeToggle
|
<ColorModeToggle
|
||||||
className={styles.navbarSidebarToggle}
|
className={styles.navbarSidebarToggle}
|
||||||
checked={colorModeToggle.isDarkTheme}
|
value={colorModeToggle.value}
|
||||||
onChange={colorModeToggle.toggle}
|
onChange={colorModeToggle.onChange}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
@ -279,8 +279,8 @@ export default function Navbar(): JSX.Element {
|
||||||
{!colorModeToggle.disabled && (
|
{!colorModeToggle.disabled && (
|
||||||
<ColorModeToggle
|
<ColorModeToggle
|
||||||
className={styles.toggle}
|
className={styles.toggle}
|
||||||
checked={colorModeToggle.isDarkTheme}
|
value={colorModeToggle.value}
|
||||||
onChange={colorModeToggle.toggle}
|
onChange={colorModeToggle.onChange}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!hasSearchNavbarItem && <SearchBar />}
|
{!hasSearchNavbarItem && <SearchBar />}
|
||||||
|
|
|
@ -16,12 +16,13 @@ import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function ThemedImage(props: Props): JSX.Element {
|
export default function ThemedImage(props: Props): JSX.Element {
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser();
|
||||||
const {isDarkTheme} = useColorMode();
|
const {colorMode} = useColorMode();
|
||||||
const {sources, className, alt, ...propsRest} = props;
|
const {sources, className, alt, ...propsRest} = props;
|
||||||
|
|
||||||
type SourceName = keyof Props['sources'];
|
type SourceName = keyof Props['sources'];
|
||||||
|
|
||||||
const clientThemes: SourceName[] = isDarkTheme ? ['dark'] : ['light'];
|
const clientThemes: SourceName[] =
|
||||||
|
colorMode === 'dark' ? ['dark'] : ['light'];
|
||||||
|
|
||||||
const renderedSourceNames: SourceName[] = isBrowser
|
const renderedSourceNames: SourceName[] = isBrowser
|
||||||
? clientThemes
|
? clientThemes
|
||||||
|
|
|
@ -11,10 +11,10 @@ import {useThemeConfig} from '../utils/useThemeConfig';
|
||||||
|
|
||||||
export default function usePrismTheme(): typeof defaultTheme {
|
export default function usePrismTheme(): typeof defaultTheme {
|
||||||
const {prism} = useThemeConfig();
|
const {prism} = useThemeConfig();
|
||||||
const {isDarkTheme} = useColorMode();
|
const {colorMode} = useColorMode();
|
||||||
const lightModeTheme = prism.theme || defaultTheme;
|
const lightModeTheme = prism.theme || defaultTheme;
|
||||||
const darkModeTheme = prism.darkTheme || lightModeTheme;
|
const darkModeTheme = prism.darkTheme || lightModeTheme;
|
||||||
const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
|
const prismTheme = colorMode === 'dark' ? darkModeTheme : lightModeTheme;
|
||||||
|
|
||||||
return prismTheme;
|
return prismTheme;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,12 @@ export {
|
||||||
PluginHtmlClassNameProvider,
|
PluginHtmlClassNameProvider,
|
||||||
} from './utils/metadataUtilsTemp';
|
} from './utils/metadataUtilsTemp';
|
||||||
|
|
||||||
export {useColorMode, ColorModeProvider} from './utils/colorModeUtils';
|
export {
|
||||||
|
useColorMode,
|
||||||
|
ColorModeProvider,
|
||||||
|
type ColorMode,
|
||||||
|
} from './utils/colorModeUtils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useTabGroupChoice,
|
useTabGroupChoice,
|
||||||
TabGroupChoiceProvider,
|
TabGroupChoiceProvider,
|
||||||
|
|
|
@ -21,77 +21,80 @@ import {createStorageSlot} from './storageUtils';
|
||||||
import {useThemeConfig} from './useThemeConfig';
|
import {useThemeConfig} from './useThemeConfig';
|
||||||
|
|
||||||
type ColorModeContextValue = {
|
type ColorModeContextValue = {
|
||||||
|
readonly colorMode: ColorMode;
|
||||||
|
readonly setColorMode: (colorMode: ColorMode) => void;
|
||||||
|
|
||||||
|
// TODO legacy APIs kept for retro-compatibility: deprecate them
|
||||||
readonly isDarkTheme: boolean;
|
readonly isDarkTheme: boolean;
|
||||||
readonly setLightTheme: () => void;
|
readonly setLightTheme: () => void;
|
||||||
readonly setDarkTheme: () => void;
|
readonly setDarkTheme: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ThemeStorageKey = 'theme';
|
const ColorModeStorageKey = 'theme';
|
||||||
const ThemeStorage = createStorageSlot(ThemeStorageKey);
|
const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
|
||||||
|
|
||||||
const themes = {
|
const ColorModes = {
|
||||||
light: 'light',
|
light: 'light',
|
||||||
dark: 'dark',
|
dark: 'dark',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
type Themes = typeof themes[keyof typeof themes];
|
export type ColorMode = typeof ColorModes[keyof typeof ColorModes];
|
||||||
|
|
||||||
// Ensure to always return a valid theme even if input is invalid
|
// Ensure to always return a valid colorMode even if input is invalid
|
||||||
const coerceToTheme = (theme?: string | null): Themes =>
|
const coerceToColorMode = (colorMode?: string | null): ColorMode =>
|
||||||
theme === themes.dark ? themes.dark : themes.light;
|
colorMode === ColorModes.dark ? ColorModes.dark : ColorModes.light;
|
||||||
|
|
||||||
const getInitialTheme = (defaultMode: Themes | undefined): Themes => {
|
const getInitialColorMode = (defaultMode: ColorMode | undefined): ColorMode => {
|
||||||
if (!ExecutionEnvironment.canUseDOM) {
|
if (!ExecutionEnvironment.canUseDOM) {
|
||||||
return coerceToTheme(defaultMode);
|
return coerceToColorMode(defaultMode);
|
||||||
}
|
}
|
||||||
return coerceToTheme(document.documentElement.getAttribute('data-theme'));
|
return coerceToColorMode(document.documentElement.getAttribute('data-theme'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const storeTheme = (newTheme: Themes) => {
|
const storeColorMode = (newColorMode: ColorMode) => {
|
||||||
ThemeStorage.set(coerceToTheme(newTheme));
|
ColorModeStorage.set(coerceToColorMode(newColorMode));
|
||||||
};
|
};
|
||||||
|
|
||||||
function useColorModeContextValue(): ColorModeContextValue {
|
function useColorModeContextValue(): ColorModeContextValue {
|
||||||
const {
|
const {
|
||||||
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
const [theme, setTheme] = useState(getInitialTheme(defaultMode));
|
const [colorMode, setColorModeState] = useState(
|
||||||
|
getInitialColorMode(defaultMode),
|
||||||
|
);
|
||||||
|
|
||||||
const setLightTheme = useCallback(() => {
|
const setColorMode = useCallback((newColorMode: ColorMode) => {
|
||||||
setTheme(themes.light);
|
setColorModeState(newColorMode);
|
||||||
storeTheme(themes.light);
|
storeColorMode(newColorMode);
|
||||||
}, []);
|
|
||||||
const setDarkTheme = useCallback(() => {
|
|
||||||
setTheme(themes.dark);
|
|
||||||
storeTheme(themes.dark);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.documentElement.setAttribute('data-theme', coerceToTheme(theme));
|
document.documentElement.setAttribute(
|
||||||
}, [theme]);
|
'data-theme',
|
||||||
|
coerceToColorMode(colorMode),
|
||||||
|
);
|
||||||
|
}, [colorMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disableSwitch) {
|
if (disableSwitch) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const onChange = (e: StorageEvent) => {
|
const onChange = (e: StorageEvent) => {
|
||||||
if (e.key !== ThemeStorageKey) {
|
if (e.key !== ColorModeStorageKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const storedTheme = ThemeStorage.get();
|
const storedColorMode = ColorModeStorage.get();
|
||||||
if (storedTheme !== null) {
|
if (storedColorMode !== null) {
|
||||||
setTheme(coerceToTheme(storedTheme));
|
setColorMode(coerceToColorMode(storedColorMode));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener('storage', onChange);
|
window.addEventListener('storage', onChange);
|
||||||
return () => {
|
return () => window.removeEventListener('storage', onChange);
|
||||||
window.removeEventListener('storage', onChange);
|
}, [disableSwitch, setColorMode]);
|
||||||
};
|
|
||||||
}, [disableSwitch, setTheme]);
|
|
||||||
|
|
||||||
// PCS is coerced to light mode when printing, which causes the color mode to
|
// PCS is coerced to light mode when printing, which causes the color mode to
|
||||||
// be reset to dark when exiting print mode, disregarding user settings. When
|
// be reset to dark when exiting print mode, disregarding user settings. When
|
||||||
|
@ -109,19 +112,45 @@ function useColorModeContextValue(): ColorModeContextValue {
|
||||||
previousMediaIsPrint.current = window.matchMedia('print').matches;
|
previousMediaIsPrint.current = window.matchMedia('print').matches;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTheme(matches ? themes.dark : themes.light);
|
setColorMode(matches ? ColorModes.dark : ColorModes.light);
|
||||||
};
|
};
|
||||||
mql.addListener(onChange);
|
mql.addListener(onChange);
|
||||||
return () => {
|
return () => mql.removeListener(onChange);
|
||||||
mql.removeListener(onChange);
|
}, [setColorMode, disableSwitch, respectPrefersColorScheme]);
|
||||||
};
|
|
||||||
}, [disableSwitch, respectPrefersColorScheme]);
|
|
||||||
|
|
||||||
return {
|
return useMemo(
|
||||||
isDarkTheme: theme === themes.dark,
|
() => ({
|
||||||
setLightTheme,
|
colorMode,
|
||||||
setDarkTheme,
|
setColorMode,
|
||||||
};
|
get isDarkTheme() {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.error(
|
||||||
|
'`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return colorMode === ColorModes.dark;
|
||||||
|
},
|
||||||
|
setLightTheme() {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.error(
|
||||||
|
'`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setColorMode(ColorModes.light);
|
||||||
|
storeColorMode(ColorModes.light);
|
||||||
|
},
|
||||||
|
setDarkTheme() {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.error(
|
||||||
|
'`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setColorMode(ColorModes.dark);
|
||||||
|
storeColorMode(ColorModes.dark);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[colorMode, setColorMode],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColorModeContext = React.createContext<ColorModeContextValue | undefined>(
|
const ColorModeContext = React.createContext<ColorModeContextValue | undefined>(
|
||||||
|
@ -133,11 +162,7 @@ export function ColorModeProvider({
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorModeContextValue();
|
const contextValue = useColorModeContextValue();
|
||||||
const contextValue = useMemo(
|
|
||||||
() => ({isDarkTheme, setLightTheme, setDarkTheme}),
|
|
||||||
[isDarkTheme, setLightTheme, setDarkTheme],
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<ColorModeContext.Provider value={contextValue}>
|
<ColorModeContext.Provider value={contextValue}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -901,9 +901,9 @@ import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
const Example = () => {
|
const Example = () => {
|
||||||
// highlight-next-line
|
// highlight-next-line
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
|
const {colorMode, setColorMode} = useColorMode();
|
||||||
|
|
||||||
return <h1>Dark mode is now {isDarkTheme ? 'on' : 'off'}</h1>;
|
return <h1>Dark mode is now {colorMode === 'dark' ? 'on' : 'off'}</h1>;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,10 @@ function wcagContrast(foreground: string, background: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ColorGenerator(): JSX.Element {
|
export default function ColorGenerator(): JSX.Element {
|
||||||
const {isDarkTheme, setDarkTheme, setLightTheme} = useColorMode();
|
const {colorMode, setColorMode} = useColorMode();
|
||||||
|
|
||||||
|
const isDarkTheme = colorMode === 'dark';
|
||||||
|
|
||||||
const DEFAULT_PRIMARY_COLOR = isDarkTheme
|
const DEFAULT_PRIMARY_COLOR = isDarkTheme
|
||||||
? DARK_PRIMARY_COLOR
|
? DARK_PRIMARY_COLOR
|
||||||
: LIGHT_PRIMARY_COLOR;
|
: LIGHT_PRIMARY_COLOR;
|
||||||
|
@ -131,13 +134,7 @@ export default function ColorGenerator(): JSX.Element {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="clean-btn button button--primary margin-left--md"
|
className="clean-btn button button--primary margin-left--md"
|
||||||
onClick={() => {
|
onClick={() => setColorMode(isDarkTheme ? 'light' : 'dark')}>
|
||||||
if (isDarkTheme) {
|
|
||||||
setLightTheme();
|
|
||||||
} else {
|
|
||||||
setDarkTheme();
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Translate
|
<Translate
|
||||||
id="colorGenerator.inputs.modeToggle.label"
|
id="colorGenerator.inputs.modeToggle.label"
|
||||||
values={{
|
values={{
|
||||||
|
|
|
@ -15,11 +15,13 @@ export default function Zoom({
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const {isDarkTheme} = useColorMode();
|
const {colorMode} = useColorMode();
|
||||||
return (
|
return (
|
||||||
<BasicZoom
|
<BasicZoom
|
||||||
overlayBgColorEnd={
|
overlayBgColorEnd={
|
||||||
isDarkTheme ? 'rgba(0, 0, 0, 0.95)' : 'rgba(255, 255, 255, 0.95)'
|
colorMode === 'dark'
|
||||||
|
? 'rgba(0, 0, 0, 0.95)'
|
||||||
|
: 'rgba(255, 255, 255, 0.95)'
|
||||||
}>
|
}>
|
||||||
{children}
|
{children}
|
||||||
</BasicZoom>
|
</BasicZoom>
|
||||||
|
|
|
@ -28,9 +28,9 @@ export default function ColorModeToggle(props: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<OriginalToggle
|
<OriginalToggle
|
||||||
{...props}
|
{...props}
|
||||||
onChange={(e) => {
|
onChange={(colorMode) => {
|
||||||
props.onChange(e);
|
props.onChange(colorMode);
|
||||||
const isDarkMode = e.target.checked;
|
const isDarkMode = colorMode === 'dark';
|
||||||
const storage = isDarkMode ? darkStorage : lightStorage;
|
const storage = isDarkMode ? darkStorage : lightStorage;
|
||||||
const colorState: ColorState = JSON.parse(storage.get() ?? 'null') ?? {
|
const colorState: ColorState = JSON.parse(storage.get() ?? 'null') ?? {
|
||||||
baseColor: isDarkMode ? DARK_PRIMARY_COLOR : LIGHT_PRIMARY_COLOR,
|
baseColor: isDarkMode ? DARK_PRIMARY_COLOR : LIGHT_PRIMARY_COLOR,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue