diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index 004594b5e74b..61fb0a05826f 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -509,16 +509,17 @@ describe('themeConfig', () => { const withDefaultValues = (colorMode) => _.merge({}, DEFAULT_CONFIG.colorMode, colorMode); - test('minimal config', () => { + test('switch config', () => { const colorMode = { switchConfig: { darkIcon: '🌙', }, }; - expect(testValidateThemeConfig({colorMode})).toEqual({ - ...DEFAULT_CONFIG, - colorMode: withDefaultValues(colorMode), - }); + expect(() => + testValidateThemeConfig({colorMode}), + ).toThrowErrorMatchingInlineSnapshot( + `"colorMode.switchConfig is deprecated. If you want to customize the icons for light and dark mode, swizzle IconLightMode, IconDarkMode, or Toggle instead."`, + ); }); test('max config', () => { @@ -526,17 +527,6 @@ describe('themeConfig', () => { defaultMode: 'dark', disableSwitch: false, respectPrefersColorScheme: true, - switchConfig: { - darkIcon: '🌙', - darkIconStyle: { - marginTop: '1px', - marginLeft: '2px', - }, - lightIcon: '☀️', - lightIconStyle: { - marginLeft: '1px', - }, - }, }; expect(testValidateThemeConfig({colorMode})).toEqual({ ...DEFAULT_CONFIG, @@ -562,16 +552,6 @@ describe('themeConfig', () => { }, }); }); - - test('empty switch config', () => { - const colorMode = { - switchConfig: {}, - }; - expect(testValidateThemeConfig({colorMode})).toEqual({ - ...DEFAULT_CONFIG, - colorMode: withDefaultValues(colorMode), - }); - }); }); }); diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 518512b11f6f..2a1e3a3aa0c5 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -663,6 +663,14 @@ declare module '@theme/IconArrow' { 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' { import type {ComponentProps} from 'react'; @@ -671,6 +679,14 @@ declare module '@theme/IconEdit' { 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' { import type {ComponentProps} from 'react'; diff --git a/packages/docusaurus-theme-classic/src/theme/IconDarkMode/index.tsx b/packages/docusaurus-theme-classic/src/theme/IconDarkMode/index.tsx new file mode 100644 index 000000000000..d319096eeab3 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/IconDarkMode/index.tsx @@ -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 ( + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/IconLightMode/index.tsx b/packages/docusaurus-theme-classic/src/theme/IconLightMode/index.tsx new file mode 100644 index 000000000000..9c080c966791 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/IconLightMode/index.tsx @@ -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 ( + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx index 4a554f088bb2..a8de1a49dae6 100644 --- a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx @@ -7,9 +7,10 @@ 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 IconLightMode from '@theme/IconLightMode'; +import IconDarkMode from '@theme/IconDarkMode'; import clsx from 'clsx'; import styles from './styles.module.css'; @@ -18,15 +19,12 @@ import styles from './styles.module.css'; 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(null); @@ -44,21 +42,16 @@ const ToggleComponent = memo( })}> {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
inputRef.current?.click()}> -
- - {darkIcon} - -
-
- - {lightIcon} - -
-
+ +
- ); + return ; } diff --git a/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css b/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css index c293660b85c5..87d53d11045b 100644 --- a/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css @@ -6,11 +6,12 @@ */ .toggle { - touch-action: pan-x; position: relative; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; + width: 32px; + height: 32px; } .toggleScreenReader { @@ -27,80 +28,15 @@ 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 { +.toggleButton { align-items: center; display: flex; - height: 10px; justify-content: center; - width: 10px; + width: 100%; + height: 100%; +} + +[data-theme='light'] .darkToggleIcon, +[data-theme='dark'] .lightToggleIcon { + display: none; } diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts index 4f7a9e3ded5d..d51800463b23 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts @@ -21,12 +21,6 @@ const DEFAULT_COLOR_MODE_CONFIG = { defaultMode: 'light', disableSwitch: false, respectPrefersColorScheme: false, - switchConfig: { - darkIcon: '🌜', - darkIconStyle: {}, - lightIcon: '🌞', - lightIconStyle: {}, - }, }; export const DEFAULT_CONFIG = { @@ -220,20 +214,12 @@ const ColorModeSchema = Joi.object({ respectPrefersColorScheme: Joi.bool().default( DEFAULT_COLOR_MODE_CONFIG.respectPrefersColorScheme, ), - switchConfig: Joi.object({ - darkIcon: Joi.string().default( - DEFAULT_COLOR_MODE_CONFIG.switchConfig.darkIcon, - ), - 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), + switchConfig: Joi.any() + .forbidden() + .messages({ + 'any.unknown': + 'colorMode.switchConfig is deprecated. If you want to customize the icons for light and dark mode, swizzle IconLightMode, IconDarkMode, or Toggle instead.', + }), }).default(DEFAULT_COLOR_MODE_CONFIG); // schema can probably be improved diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index 26975d2563ce..762ed3a14943 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -7,7 +7,6 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import type {PrismTheme} from 'prism-react-renderer'; -import type {CSSProperties} from 'react'; import type {DeepPartial} from 'utility-types'; export type DocsVersionPersistence = 'localStorage' | 'none'; @@ -43,12 +42,6 @@ export type ColorModeConfig = { defaultMode: 'light' | 'dark'; disableSwitch: boolean; respectPrefersColorScheme: boolean; - switchConfig: { - darkIcon: string; - darkIconStyle: CSSProperties; - lightIcon: string; - lightIconStyle: CSSProperties; - }; }; export type AnnouncementBarConfig = { diff --git a/website/docs/api/docusaurus.config.js.md b/website/docs/api/docusaurus.config.js.md index ab50dc53956c..4f064ef619b1 100644 --- a/website/docs/api/docusaurus.config.js.md +++ b/website/docs/api/docusaurus.config.js.md @@ -284,18 +284,6 @@ module.exports = { defaultMode: 'light', disableSwitch: false, 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: { title: 'Site Title', diff --git a/website/docs/api/themes/theme-configuration.md b/website/docs/api/themes/theme-configuration.md index e79cf89614cf..108aa6aa78d3 100644 --- a/website/docs/api/themes/theme-configuration.md +++ b/website/docs/api/themes/theme-configuration.md @@ -28,11 +28,6 @@ Accepted fields: | `defaultMode` | 'light' \| 'dark' | `'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. | | `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. | @@ -46,18 +41,6 @@ module.exports = { defaultMode: 'light', disableSwitch: 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 },