refactor(theme-classic): replace color mode toggle with button; remove switchConfig (#6771)

Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
Joshua Chen 2022-03-02 22:57:17 +08:00 committed by GitHub
parent b1492135c2
commit 7ec44bb32c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 282 additions and 356 deletions

View file

@ -509,16 +509,17 @@ describe('themeConfig', () => {
const withDefaultValues = (colorMode) => const withDefaultValues = (colorMode) =>
_.merge({}, DEFAULT_CONFIG.colorMode, colorMode); _.merge({}, DEFAULT_CONFIG.colorMode, colorMode);
test('minimal config', () => { test('switch config', () => {
const colorMode = { const colorMode = {
switchConfig: { switchConfig: {
darkIcon: '🌙', darkIcon: '🌙',
}, },
}; };
expect(testValidateThemeConfig({colorMode})).toEqual({ expect(() =>
...DEFAULT_CONFIG, testValidateThemeConfig({colorMode}),
colorMode: withDefaultValues(colorMode), ).toThrowErrorMatchingInlineSnapshot(
}); `"colorMode.switchConfig is deprecated. If you want to customize the icons for light and dark mode, swizzle IconLightMode, IconDarkMode, or ColorModeToggle instead."`,
);
}); });
test('max config', () => { test('max config', () => {
@ -526,17 +527,6 @@ describe('themeConfig', () => {
defaultMode: 'dark', defaultMode: 'dark',
disableSwitch: false, disableSwitch: false,
respectPrefersColorScheme: true, respectPrefersColorScheme: true,
switchConfig: {
darkIcon: '🌙',
darkIconStyle: {
marginTop: '1px',
marginLeft: '2px',
},
lightIcon: '☀️',
lightIconStyle: {
marginLeft: '1px',
},
},
}; };
expect(testValidateThemeConfig({colorMode})).toEqual({ expect(testValidateThemeConfig({colorMode})).toEqual({
...DEFAULT_CONFIG, ...DEFAULT_CONFIG,
@ -562,16 +552,6 @@ describe('themeConfig', () => {
}, },
}); });
}); });
test('empty switch config', () => {
const colorMode = {
switchConfig: {},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});
}); });
}); });

View file

@ -7,95 +7,117 @@
import type {SwizzleConfig} from '@docusaurus/types'; import type {SwizzleConfig} from '@docusaurus/types';
/* eslint sort-keys: "error" */
export default function getSwizzleConfig(): SwizzleConfig { export default function getSwizzleConfig(): SwizzleConfig {
return { return {
components: { components: {
CodeBlock: { CodeBlock: {
actions: { actions: {
wrap: 'safe',
eject: 'safe', eject: 'safe',
wrap: 'safe',
}, },
description: description:
'The component used to render multi-line code blocks, generally used in Markdown files.', 'The component used to render multi-line code blocks, generally used in Markdown files.',
}, },
ColorModeToggle: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description:
'The color mode toggle to switch between light and dark mode.',
},
DocSidebar: { DocSidebar: {
actions: { actions: {
wrap: 'safe',
eject: 'unsafe', // too much technical code in sidebar, not very safe atm eject: 'unsafe', // too much technical code in sidebar, not very safe atm
wrap: 'safe',
}, },
description: 'The sidebar component on docs pages', description: 'The sidebar component on docs pages',
}, },
Footer: { Footer: {
actions: { actions: {
wrap: 'safe',
eject: 'unsafe', // TODO split footer into smaller parts eject: 'unsafe', // TODO split footer into smaller parts
wrap: 'safe',
}, },
description: "The footer component of you site's layout", description: "The footer component of you site's layout",
}, },
IconArrow: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The arrow icon component',
},
IconDarkMode: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The dark mode icon component.',
},
IconEdit: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The edit icon component',
},
IconLightMode: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The light mode icon component.',
},
IconMenu: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description: 'The menu icon component',
},
MDXComponents: {
actions: {
eject: 'safe',
wrap: 'forbidden', /// TODO allow wrapping objects???
},
description:
'The MDX components to use for rendering MDX files. Meant to be ejected.',
},
// TODO should probably not even appear here
'NavbarItem/utils': {
actions: {
eject: 'forbidden',
wrap: 'forbidden',
},
},
NotFound: { NotFound: {
actions: { actions: {
wrap: 'safe',
eject: 'safe', eject: 'safe',
wrap: 'safe',
}, },
description: description:
'The global 404 page of your site, meant to be ejected and customized', 'The global 404 page of your site, meant to be ejected and customized',
}, },
SearchBar: { SearchBar: {
actions: { actions: {
wrap: 'safe',
eject: 'safe', eject: 'safe',
wrap: 'safe',
}, },
// TODO how to describe this one properly? // TODO how to describe this one properly?
// By default it's an empty placeholder for the user to fill // By default it's an empty placeholder for the user to fill
description: description:
'The search bar component of your site, appearing in the navbar.', 'The search bar component of your site, appearing in the navbar.',
}, },
IconArrow: {
actions: {
wrap: 'safe',
eject: 'safe',
},
description: 'The arrow icon component',
},
IconEdit: {
actions: {
wrap: 'safe',
eject: 'safe',
},
description: 'The edit icon component',
},
IconMenu: {
actions: {
wrap: 'safe',
eject: 'safe',
},
description: 'The menu icon component',
},
'prism-include-languages': { 'prism-include-languages': {
actions: { actions: {
wrap: 'forbidden', // not a component!
eject: 'safe', eject: 'safe',
wrap: 'forbidden', // not a component!
}, },
description: description:
'The Prism languages to include for code block syntax highlighting. Meant to be ejected.', 'The Prism languages to include for code block syntax highlighting. Meant to be ejected.',
}, },
MDXComponents: {
actions: {
wrap: 'forbidden', /// TODO allow wrapping objects???
eject: 'safe',
},
description:
'The MDX components to use for rendering MDX files. Meant to be ejected.',
},
// TODO should probably not even appear here
'NavbarItem/utils': {
actions: {
wrap: 'forbidden',
eject: 'forbidden',
},
},
}, },
}; };
} }

View file

@ -632,7 +632,7 @@ declare module '@theme/TOCCollapsible' {
export default function TOCCollapsible(props: Props): JSX.Element; export default function TOCCollapsible(props: Props): JSX.Element;
} }
declare module '@theme/Toggle' { declare module '@theme/ColorModeToggle' {
import type {SyntheticEvent} from 'react'; import type {SyntheticEvent} from 'react';
export interface Props { export interface Props {
@ -663,6 +663,14 @@ declare module '@theme/IconArrow' {
export default function IconArrow(props: Props): JSX.Element; export default function IconArrow(props: Props): JSX.Element;
} }
declare module '@theme/IconDarkMode' {
import type {ComponentProps} from 'react';
export interface Props extends ComponentProps<'svg'> {}
export default function IconDarkMode(props: Props): JSX.Element;
}
declare module '@theme/IconEdit' { declare module '@theme/IconEdit' {
import type {ComponentProps} from 'react'; import type {ComponentProps} from 'react';
@ -671,6 +679,14 @@ declare module '@theme/IconEdit' {
export default function IconEdit(props: Props): JSX.Element; export default function IconEdit(props: Props): JSX.Element;
} }
declare module '@theme/IconLightMode' {
import type {ComponentProps} from 'react';
export interface Props extends ComponentProps<'svg'> {}
export default function IconLightMode(props: Props): JSX.Element;
}
declare module '@theme/IconMenu' { declare module '@theme/IconMenu' {
import type {ComponentProps} from 'react'; import type {ComponentProps} from 'react';

View file

@ -0,0 +1,92 @@
/**
* 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 React, {useState, useRef, useEffect} from 'react';
import type {Props} from '@theme/ColorModeToggle';
import useIsBrowser from '@docusaurus/useIsBrowser';
import {translate} from '@docusaurus/Translate';
import IconLightMode from '@theme/IconLightMode';
import IconDarkMode from '@theme/IconDarkMode';
import clsx from 'clsx';
import styles from './styles.module.css';
function ColorModeToggle({
className,
checked: defaultChecked,
onChange,
}: Props): JSX.Element {
const isBrowser = useIsBrowser();
const [checked, setChecked] = useState(defaultChecked);
const [focused, setFocused] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
setChecked(defaultChecked);
}, [defaultChecked]);
return (
<div
className={clsx(styles.toggle, className, {
[styles.toggleChecked]: checked,
[styles.toggleFocused]: focused,
[styles.toggleDisabled]: !isBrowser,
})}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
className={styles.toggleButton}
role="button"
tabIndex={-1}
onClick={() => inputRef.current?.click()}>
<IconLightMode
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
/>
<IconDarkMode
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
/>
</div>
<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>
);
}
export default React.memo(ColorModeToggle);

View file

@ -0,0 +1,51 @@
/**
* 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.
*/
.toggle {
position: relative;
width: 32px;
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 {
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
align-items: center;
display: flex;
justify-content: center;
width: 100%;
height: 100%;
border-radius: 50%;
}
.toggleButton:hover {
background-color: #00000010;
}
[data-theme='dark'] .toggleButton:hover {
background-color: #ffffff20;
}
[data-theme='light'] .darkToggleIcon,
[data-theme='dark'] .lightToggleIcon {
display: none;
}

View file

@ -0,0 +1,20 @@
/**
* 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 React from 'react';
import type {Props} from '@theme/IconDarkMode';
export default function IconDarkMode(props: Props): JSX.Element {
return (
<svg viewBox="0 0 24 24" width={24} height={24} {...props}>
<path
fill="currentColor"
d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"
/>
</svg>
);
}

View file

@ -0,0 +1,20 @@
/**
* 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 React from 'react';
import type {Props} from '@theme/IconLightMode';
export default function IconLightMode(props: Props): JSX.Element {
return (
<svg viewBox="0 0 24 24" width={24} height={24} {...props}>
<path
fill="currentColor"
d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"
/>
</svg>
);
}

View file

@ -9,7 +9,7 @@ import React, {useCallback, useState, useEffect} from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import Translate from '@docusaurus/Translate'; import Translate from '@docusaurus/Translate';
import SearchBar from '@theme/SearchBar'; import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle'; import ColorModeToggle from '@theme/ColorModeToggle';
import { import {
useThemeConfig, useThemeConfig,
useMobileSecondaryMenuRenderer, useMobileSecondaryMenuRenderer,
@ -171,7 +171,7 @@ function NavbarMobileSidebar({
titleClassName="navbar__title" titleClassName="navbar__title"
/> />
{!colorModeToggle.disabled && ( {!colorModeToggle.disabled && (
<Toggle <ColorModeToggle
className={styles.navbarSidebarToggle} className={styles.navbarSidebarToggle}
checked={colorModeToggle.isDarkTheme} checked={colorModeToggle.isDarkTheme}
onChange={colorModeToggle.toggle} onChange={colorModeToggle.toggle}
@ -271,7 +271,7 @@ export default function Navbar(): JSX.Element {
<NavbarItem {...item} key={i} /> <NavbarItem {...item} key={i} />
))} ))}
{!colorModeToggle.disabled && ( {!colorModeToggle.disabled && (
<Toggle <ColorModeToggle
className={styles.toggle} className={styles.toggle}
checked={colorModeToggle.isDarkTheme} checked={colorModeToggle.isDarkTheme}
onChange={colorModeToggle.toggle} onChange={colorModeToggle.toggle}

View file

@ -1,117 +0,0 @@
/**
* 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 React, {useState, useRef, useEffect, memo} from 'react';
import type {Props} from '@theme/Toggle';
import {useThemeConfig, type ColorModeConfig} from '@docusaurus/theme-common';
import useIsBrowser from '@docusaurus/useIsBrowser';
import {translate} from '@docusaurus/Translate';
import clsx from 'clsx';
import styles from './styles.module.css';
// Based on react-toggle (https://github.com/aaronshaf/react-toggle/).
const ToggleComponent = memo(
({
className,
switchConfig,
checked: defaultChecked,
disabled,
onChange,
}: Props & {
switchConfig: ColorModeConfig['switchConfig'];
disabled: boolean;
}): JSX.Element => {
const {darkIcon, darkIconStyle, lightIcon, lightIconStyle} = switchConfig;
const [checked, setChecked] = useState(defaultChecked);
const [focused, setFocused] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
setChecked(defaultChecked);
}, [defaultChecked]);
return (
<div
className={clsx(styles.toggle, className, {
[styles.toggleChecked]: checked,
[styles.toggleFocused]: focused,
[styles.toggleDisabled]: disabled,
})}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
className={styles.toggleTrack}
role="button"
tabIndex={-1}
onClick={() => inputRef.current?.click()}>
<div className={styles.toggleTrackCheck}>
<span className={styles.toggleIcon} style={darkIconStyle}>
{darkIcon}
</span>
</div>
<div className={styles.toggleTrackX}>
<span className={styles.toggleIcon} style={lightIconStyle}>
{lightIcon}
</span>
</div>
<div className={styles.toggleTrackThumb} />
</div>
<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>
);
},
);
export default function Toggle(props: Props): JSX.Element {
const {
colorMode: {switchConfig},
} = useThemeConfig();
const isBrowser = useIsBrowser();
return (
<ToggleComponent
switchConfig={switchConfig}
disabled={!isBrowser}
{...props}
/>
);
}

View file

@ -1,106 +0,0 @@
/**
* 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.
*/
.toggle {
touch-action: pan-x;
position: relative;
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
.toggleScreenReader {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.toggleDisabled {
cursor: not-allowed;
}
.toggleTrack {
width: 50px;
height: 24px;
border-radius: 30px;
background-color: #4d4d4d;
transition: all 0.2s ease;
}
.toggleTrackCheck {
position: absolute;
width: 14px;
height: 10px;
top: 0;
bottom: 0;
margin: auto 0;
left: 8px;
opacity: 0;
transition: opacity 0.25s ease;
}
.toggleChecked .toggleTrackCheck,
[data-theme='dark'] .toggle .toggleTrackCheck {
opacity: 1;
transition: opacity 0.25s ease;
}
.toggleTrackX {
position: absolute;
width: 10px;
height: 10px;
top: 0;
bottom: 0;
margin: auto 0;
right: 10px;
opacity: 1;
transition: opacity 0.25s ease;
}
.toggleChecked .toggleTrackX,
[data-theme='dark'] .toggle .toggleTrackX {
opacity: 0;
}
.toggleTrackThumb {
position: absolute;
top: 1px;
left: 1px;
width: 22px;
height: 22px;
border: 1px solid #4d4d4d;
border-radius: 50%;
background-color: #fafafa;
transition: all 0.25s ease;
}
.toggleFocused .toggleTrackThumb,
.toggle:hover .toggleTrackThumb {
box-shadow: 0 0 2px 3px var(--ifm-color-primary);
}
/* stylelint-disable-next-line no-descending-specificity */
.toggleChecked .toggleTrackThumb,
[data-theme='dark'] .toggle .toggleTrackThumb {
left: 27px;
}
.toggle:active:not(.toggleDisabled) .toggleTrackThumb {
box-shadow: 0 0 5px 5px var(--ifm-color-primary);
}
.toggleIcon {
align-items: center;
display: flex;
height: 10px;
justify-content: center;
width: 10px;
}

View file

@ -21,12 +21,6 @@ const DEFAULT_COLOR_MODE_CONFIG = {
defaultMode: 'light', defaultMode: 'light',
disableSwitch: false, disableSwitch: false,
respectPrefersColorScheme: false, respectPrefersColorScheme: false,
switchConfig: {
darkIcon: '🌜',
darkIconStyle: {},
lightIcon: '🌞',
lightIconStyle: {},
},
}; };
export const DEFAULT_CONFIG = { export const DEFAULT_CONFIG = {
@ -220,20 +214,10 @@ const ColorModeSchema = Joi.object({
respectPrefersColorScheme: Joi.bool().default( respectPrefersColorScheme: Joi.bool().default(
DEFAULT_COLOR_MODE_CONFIG.respectPrefersColorScheme, DEFAULT_COLOR_MODE_CONFIG.respectPrefersColorScheme,
), ),
switchConfig: Joi.object({ switchConfig: Joi.any().forbidden().messages({
darkIcon: Joi.string().default( 'any.unknown':
DEFAULT_COLOR_MODE_CONFIG.switchConfig.darkIcon, 'colorMode.switchConfig is deprecated. If you want to customize the icons for light and dark mode, swizzle IconLightMode, IconDarkMode, or ColorModeToggle instead.',
), }),
darkIconStyle: Joi.object().default(
DEFAULT_COLOR_MODE_CONFIG.switchConfig.darkIconStyle,
),
lightIcon: Joi.string().default(
DEFAULT_COLOR_MODE_CONFIG.switchConfig.lightIcon,
),
lightIconStyle: Joi.object().default(
DEFAULT_COLOR_MODE_CONFIG.switchConfig.lightIconStyle,
),
}).default(DEFAULT_COLOR_MODE_CONFIG.switchConfig),
}).default(DEFAULT_COLOR_MODE_CONFIG); }).default(DEFAULT_COLOR_MODE_CONFIG);
// schema can probably be improved // schema can probably be improved

View file

@ -7,7 +7,6 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import type {PrismTheme} from 'prism-react-renderer'; import type {PrismTheme} from 'prism-react-renderer';
import type {CSSProperties} from 'react';
import type {DeepPartial} from 'utility-types'; import type {DeepPartial} from 'utility-types';
export type DocsVersionPersistence = 'localStorage' | 'none'; export type DocsVersionPersistence = 'localStorage' | 'none';
@ -43,12 +42,6 @@ export type ColorModeConfig = {
defaultMode: 'light' | 'dark'; defaultMode: 'light' | 'dark';
disableSwitch: boolean; disableSwitch: boolean;
respectPrefersColorScheme: boolean; respectPrefersColorScheme: boolean;
switchConfig: {
darkIcon: string;
darkIconStyle: CSSProperties;
lightIcon: string;
lightIconStyle: CSSProperties;
};
}; };
export type AnnouncementBarConfig = { export type AnnouncementBarConfig = {

View file

@ -284,18 +284,6 @@ module.exports = {
defaultMode: 'light', defaultMode: 'light',
disableSwitch: false, disableSwitch: false,
respectPrefersColorScheme: true, respectPrefersColorScheme: true,
switchConfig: {
darkIcon: '🌙',
lightIcon: '\u2600',
// React inline style object
// see https://reactjs.org/docs/dom-elements.html#style
darkIconStyle: {
marginLeft: '2px',
},
lightIconStyle: {
marginLeft: '1px',
},
},
}, },
navbar: { navbar: {
title: 'Site Title', title: 'Site Title',

View file

@ -28,11 +28,6 @@ Accepted fields:
| `defaultMode` | <code>'light' \| 'dark'</code> | `'light'` | The color mode when user first visits the site. | | `defaultMode` | <code>'light' \| 'dark'</code> | `'light'` | The color mode when user first visits the site. |
| `disableSwitch` | `boolean` | `false` | Hides the switch in the navbar. Useful if you want to support a single color mode. | | `disableSwitch` | `boolean` | `false` | Hides the switch in the navbar. Useful if you want to support a single color mode. |
| `respectPrefersColorScheme` | `boolean` | `false` | Whether to use the `prefers-color-scheme` media-query, using user system preferences, instead of the hardcoded `defaultMode`. | | `respectPrefersColorScheme` | `boolean` | `false` | Whether to use the `prefers-color-scheme` media-query, using user system preferences, instead of the hardcoded `defaultMode`. |
| `switchConfig` | _See below_ | _See below_ | Dark/light switch icon options. |
| `switchConfig.darkIcon` | `string` | `'🌜'` | Icon for the switch while in dark mode. |
| `switchConfig.darkIconStyle` | JSX style object (see [documentation](https://reactjs.org/docs/dom-elements.html#style)) | `{}` | CSS to apply to dark icon. |
| `switchConfig.lightIcon` | `string` | `'🌞'` | Icon for the switch while in light mode. |
| `switchConfig.lightIconStyle` | JSX style object | `{}` | CSS to apply to light icon. |
</APITable> </APITable>
@ -46,18 +41,6 @@ module.exports = {
defaultMode: 'light', defaultMode: 'light',
disableSwitch: false, disableSwitch: false,
respectPrefersColorScheme: false, respectPrefersColorScheme: false,
switchConfig: {
darkIcon: '🌙',
darkIconStyle: {
marginLeft: '2px',
},
// Unicode icons such as '\u2600' will work
// Unicode with 5 chars require brackets: '\u{1F602}'
lightIcon: '\u{1F602}',
lightIconStyle: {
marginLeft: '1px',
},
},
}, },
// highlight-end // highlight-end
}, },

View file

@ -6,8 +6,8 @@
*/ */
import React from 'react'; import React from 'react';
import OriginalToggle from '@theme-original/Toggle'; import OriginalToggle from '@theme-original/ColorModeToggle';
import type {Props} from '@theme/Toggle'; import type {Props} from '@theme/ColorModeToggle';
import { import {
lightStorage, lightStorage,
darkStorage, darkStorage,
@ -24,7 +24,7 @@ import {
// session storage, and we need to apply the same style when toggling modes even // session storage, and we need to apply the same style when toggling modes even
// when we are not on the styling-layout page. The only way to do this so far is // when we are not on the styling-layout page. The only way to do this so far is
// by hooking into the Toggle component. // by hooking into the Toggle component.
export default function Toggle(props: Props): JSX.Element { export default function ColorModeToggle(props: Props): JSX.Element {
return ( return (
<OriginalToggle <OriginalToggle
{...props} {...props}