Skip to content

Commit

Permalink
refactor(theme-classic): replace color mode toggle with button; remov…
Browse files Browse the repository at this point in the history
…e switchConfig
  • Loading branch information
Josh-Cena committed Feb 26, 2022
1 parent e101acd commit 2722084
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -509,34 +509,24 @@ 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', () => {
const colorMode = {
defaultMode: 'dark',
disableSwitch: false,
respectPrefersColorScheme: true,
switchConfig: {
darkIcon: '🌙',
darkIconStyle: {
marginTop: '1px',
marginLeft: '2px',
},
lightIcon: '☀️',
lightIconStyle: {
marginLeft: '1px',
},
},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
...DEFAULT_CONFIG,
Expand All @@ -562,16 +552,6 @@ describe('themeConfig', () => {
},
});
});

test('empty switch config', () => {
const colorMode = {
switchConfig: {},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});
});
});

Expand Down
16 changes: 16 additions & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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';

Expand Down
20 changes: 20 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/IconDarkMode/index.tsx
Original file line number Diff line number Diff line change
@@ -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>
);
}
Original file line number Diff line number Diff line change
@@ -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>
);
}
36 changes: 10 additions & 26 deletions packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<HTMLInputElement>(null);
Expand All @@ -44,21 +42,16 @@ const ToggleComponent = memo(
})}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
className={styles.toggleTrack}
className={styles.toggleButton}
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} />
<IconLightMode
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
/>
<IconDarkMode
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
/>
</div>

<input
Expand Down Expand Up @@ -102,16 +95,7 @@ const ToggleComponent = memo(
);

export default function Toggle(props: Props): JSX.Element {
const {
colorMode: {switchConfig},
} = useThemeConfig();
const isBrowser = useIsBrowser();

return (
<ToggleComponent
switchConfig={switchConfig}
disabled={!isBrowser}
{...props}
/>
);
return <ToggleComponent disabled={!isBrowser} {...props} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
26 changes: 6 additions & 20 deletions packages/docusaurus-theme-classic/src/validateThemeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ const DEFAULT_COLOR_MODE_CONFIG = {
defaultMode: 'light',
disableSwitch: false,
respectPrefersColorScheme: false,
switchConfig: {
darkIcon: '🌜',
darkIconStyle: {},
lightIcon: '🌞',
lightIconStyle: {},
},
};

export const DEFAULT_CONFIG = {
Expand Down Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 = {
Expand Down
12 changes: 0 additions & 12 deletions website/docs/api/docusaurus.config.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 2722084

Please sign in to comment.