mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-01 10:22:30 +02:00
feat(theme): Allow resetting colorMode to System/OS value (#10987)
* make it work * fix * Try to fix accessibility issues * add translations * rename 'auto' to 'system' * refactor: apply lint autofix * rename 'auto' to 'system' * remove title prop * typo * use shorter title * refactor: apply lint autofix * document useColorMode tradeoffs + data-attribute variables --------- Co-authored-by: slorber <749374+slorber@users.noreply.github.com> Co-authored-by: nasso Co-authored-by: OzakIOne
This commit is contained in:
parent
fd51384cab
commit
7cf94c03a4
43 changed files with 394 additions and 146 deletions
|
@ -30,43 +30,22 @@ export function getThemeInlineScript({
|
||||||
return `(function() {
|
return `(function() {
|
||||||
var defaultMode = '${defaultMode}';
|
var defaultMode = '${defaultMode}';
|
||||||
var respectPrefersColorScheme = ${respectPrefersColorScheme};
|
var respectPrefersColorScheme = ${respectPrefersColorScheme};
|
||||||
|
function getSystemColorMode() {
|
||||||
function setDataThemeAttribute(theme) {
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
document.documentElement.setAttribute('data-theme', theme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getQueryStringTheme() {
|
function getQueryStringTheme() {
|
||||||
try {
|
try {
|
||||||
return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
|
return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStoredTheme() {
|
function getStoredTheme() {
|
||||||
try {
|
try {
|
||||||
return window['${siteStorage.type}'].getItem('${themeStorageKey}');
|
return window['${siteStorage.type}'].getItem('${themeStorageKey}');
|
||||||
} catch (err) {
|
} catch (err) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var initialTheme = getQueryStringTheme() || getStoredTheme();
|
var initialTheme = getQueryStringTheme() || getStoredTheme();
|
||||||
if (initialTheme !== null) {
|
document.documentElement.setAttribute('data-theme', initialTheme || (respectPrefersColorScheme ? getSystemColorMode() : defaultMode));
|
||||||
setDataThemeAttribute(initialTheme);
|
document.documentElement.setAttribute('data-theme-choice', initialTheme || (respectPrefersColorScheme ? 'system' : defaultMode));
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
respectPrefersColorScheme &&
|
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
) {
|
|
||||||
setDataThemeAttribute('dark');
|
|
||||||
} else if (
|
|
||||||
respectPrefersColorScheme &&
|
|
||||||
window.matchMedia('(prefers-color-scheme: light)').matches
|
|
||||||
) {
|
|
||||||
setDataThemeAttribute('light');
|
|
||||||
} else {
|
|
||||||
setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();`;
|
})();`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1555,12 +1555,13 @@ declare module '@theme/ColorModeToggle' {
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
readonly buttonClassName?: string;
|
readonly buttonClassName?: string;
|
||||||
readonly value: ColorMode;
|
readonly respectPrefersColorScheme: boolean;
|
||||||
|
readonly value: ColorMode | null;
|
||||||
/**
|
/**
|
||||||
* The parameter represents the "to-be" value. For example, if currently in
|
* The parameter represents the "to-be" value. For example, if currently in
|
||||||
* dark mode, clicking the button should call `onChange("light")`
|
* light mode, clicking the button should call `onChange("dark")`
|
||||||
*/
|
*/
|
||||||
readonly onChange: (colorMode: ColorMode) => void;
|
readonly onChange: (colorMode: ColorMode | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ColorModeToggle(props: Props): ReactNode;
|
export default function ColorModeToggle(props: Props): ReactNode;
|
||||||
|
@ -1617,6 +1618,14 @@ declare module '@theme/Icon/LightMode' {
|
||||||
export default function IconLightMode(props: Props): ReactNode;
|
export default function IconLightMode(props: Props): ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@theme/Icon/SystemColorMode' {
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
|
||||||
|
export interface Props extends ComponentProps<'svg'> {}
|
||||||
|
|
||||||
|
export default function IconSystemColorMode(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
declare module '@theme/Icon/Menu' {
|
declare module '@theme/Icon/Menu' {
|
||||||
import type {ComponentProps, ReactNode} from 'react';
|
import type {ComponentProps, ReactNode} from 'react';
|
||||||
|
|
||||||
|
|
|
@ -11,40 +11,105 @@ import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
import IconLightMode from '@theme/Icon/LightMode';
|
import IconLightMode from '@theme/Icon/LightMode';
|
||||||
import IconDarkMode from '@theme/Icon/DarkMode';
|
import IconDarkMode from '@theme/Icon/DarkMode';
|
||||||
|
import IconSystemColorMode from '@theme/Icon/SystemColorMode';
|
||||||
import type {Props} from '@theme/ColorModeToggle';
|
import type {Props} from '@theme/ColorModeToggle';
|
||||||
|
import type {ColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
// The order of color modes is defined here, and can be customized with swizzle
|
||||||
|
function getNextColorMode(
|
||||||
|
colorMode: ColorMode | null,
|
||||||
|
respectPrefersColorScheme: boolean,
|
||||||
|
) {
|
||||||
|
// 2-value transition
|
||||||
|
if (!respectPrefersColorScheme) {
|
||||||
|
return colorMode === 'dark' ? 'light' : 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3-value transition
|
||||||
|
switch (colorMode) {
|
||||||
|
case null:
|
||||||
|
return 'light';
|
||||||
|
case 'light':
|
||||||
|
return 'dark';
|
||||||
|
case 'dark':
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
throw new Error(`unexpected color mode ${colorMode}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorModeLabel(colorMode: ColorMode | null): string {
|
||||||
|
switch (colorMode) {
|
||||||
|
case null:
|
||||||
|
return translate({
|
||||||
|
message: 'system mode',
|
||||||
|
id: 'theme.colorToggle.ariaLabel.mode.system',
|
||||||
|
description: 'The name for the system color mode',
|
||||||
|
});
|
||||||
|
case 'light':
|
||||||
|
return translate({
|
||||||
|
message: 'light mode',
|
||||||
|
id: 'theme.colorToggle.ariaLabel.mode.light',
|
||||||
|
description: 'The name for the light color mode',
|
||||||
|
});
|
||||||
|
case 'dark':
|
||||||
|
return translate({
|
||||||
|
message: 'dark mode',
|
||||||
|
id: 'theme.colorToggle.ariaLabel.mode.dark',
|
||||||
|
description: 'The name for the dark color mode',
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
throw new Error(`unexpected color mode ${colorMode}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorModeAriaLabel(colorMode: ColorMode | null) {
|
||||||
|
return translate(
|
||||||
|
{
|
||||||
|
message: 'Switch between dark and light mode (currently {mode})',
|
||||||
|
id: 'theme.colorToggle.ariaLabel',
|
||||||
|
description: 'The ARIA label for the color mode toggle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode: getColorModeLabel(colorMode),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CurrentColorModeIcon(): ReactNode {
|
||||||
|
// 3 icons are always rendered for technical reasons
|
||||||
|
// We use "data-theme-choice" to render the correct one
|
||||||
|
// This must work even before React hydrates
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconLightMode
|
||||||
|
// a18y is handled at the button level,
|
||||||
|
// not relying on button content (svg icons)
|
||||||
|
aria-hidden
|
||||||
|
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
|
||||||
|
/>
|
||||||
|
<IconDarkMode
|
||||||
|
aria-hidden
|
||||||
|
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
|
||||||
|
/>
|
||||||
|
<IconSystemColorMode
|
||||||
|
aria-hidden
|
||||||
|
className={clsx(styles.toggleIcon, styles.systemToggleIcon)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ColorModeToggle({
|
function ColorModeToggle({
|
||||||
className,
|
className,
|
||||||
buttonClassName,
|
buttonClassName,
|
||||||
|
respectPrefersColorScheme,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
}: Props): ReactNode {
|
}: Props): ReactNode {
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser();
|
||||||
|
|
||||||
const title = 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:
|
|
||||||
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 className={clsx(styles.toggle, className)}>
|
<div className={clsx(styles.toggle, className)}>
|
||||||
<button
|
<button
|
||||||
|
@ -55,18 +120,23 @@ function ColorModeToggle({
|
||||||
buttonClassName,
|
buttonClassName,
|
||||||
)}
|
)}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
|
onClick={() =>
|
||||||
|
onChange(getNextColorMode(value, respectPrefersColorScheme))
|
||||||
|
}
|
||||||
disabled={!isBrowser}
|
disabled={!isBrowser}
|
||||||
title={title}
|
title={getColorModeLabel(value)}
|
||||||
aria-label={title}
|
aria-label={getColorModeAriaLabel(value)}
|
||||||
aria-live="polite"
|
|
||||||
aria-pressed={value === 'dark' ? 'true' : 'false'}>
|
// For accessibility decisions
|
||||||
<IconLightMode
|
// See https://github.com/facebook/docusaurus/issues/7667#issuecomment-2724401796
|
||||||
className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
|
|
||||||
/>
|
// aria-live disabled on purpose - This is annoying because:
|
||||||
<IconDarkMode
|
// - without this attribute, VoiceOver doesn't announce on button enter
|
||||||
className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
|
// - with this attribute, VoiceOver announces twice on ctrl+opt+space
|
||||||
/>
|
// - with this attribute, NVDA announces many times
|
||||||
|
// aria-live="polite"
|
||||||
|
>
|
||||||
|
<CurrentColorModeIcon />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,11 +25,16 @@
|
||||||
background: var(--ifm-color-emphasis-200);
|
background: var(--ifm-color-emphasis-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='light'] .darkToggleIcon,
|
.toggleIcon {
|
||||||
[data-theme='dark'] .lightToggleIcon {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-theme-choice='system'] .systemToggleIcon,
|
||||||
|
[data-theme-choice='light'] .lightToggleIcon,
|
||||||
|
[data-theme-choice='dark'] .darkToggleIcon {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
.toggleButtonDisabled {
|
.toggleButtonDisabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 type {ReactNode} from 'react';
|
||||||
|
import type {Props} from '@theme/Icon/SystemColorMode';
|
||||||
|
|
||||||
|
export default function IconSystemColorMode(props: Props): ReactNode {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 24 24" width={24} height={24} {...props}>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,10 +13,10 @@ import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function NavbarColorModeToggle({className}: Props): ReactNode {
|
export default function NavbarColorModeToggle({className}: Props): ReactNode {
|
||||||
const navbarStyle = useThemeConfig().navbar.style;
|
const navbarStyle = useThemeConfig().navbar.style;
|
||||||
const disabled = useThemeConfig().colorMode.disableSwitch;
|
const {disableSwitch, respectPrefersColorScheme} = useThemeConfig().colorMode;
|
||||||
const {colorMode, setColorMode} = useColorMode();
|
const {colorModeChoice, setColorMode} = useColorMode();
|
||||||
|
|
||||||
if (disabled) {
|
if (disableSwitch) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ export default function NavbarColorModeToggle({className}: Props): ReactNode {
|
||||||
buttonClassName={
|
buttonClassName={
|
||||||
navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
|
navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
|
||||||
}
|
}
|
||||||
value={colorMode}
|
respectPrefersColorScheme={respectPrefersColorScheme}
|
||||||
|
value={colorModeChoice}
|
||||||
onChange={setColorMode}
|
onChange={setColorMode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,19 +11,49 @@ import React, {
|
||||||
useEffect,
|
useEffect,
|
||||||
useContext,
|
useContext,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
|
||||||
import {ReactContextError} from '../utils/reactUtils';
|
import {ReactContextError} from '../utils/reactUtils';
|
||||||
import {createStorageSlot} from '../utils/storageUtils';
|
import {createStorageSlot} from '../utils/storageUtils';
|
||||||
import {useThemeConfig} from '../utils/useThemeConfig';
|
import {useThemeConfig} from '../utils/useThemeConfig';
|
||||||
|
|
||||||
|
// The "effective" color mode
|
||||||
|
export type ColorMode = 'light' | 'dark';
|
||||||
|
|
||||||
|
// The color mode explicitly chosen by the user
|
||||||
|
// null => no choice has been made, or the choice has been reverted to OS value
|
||||||
|
export type ColorModeChoice = ColorMode | null;
|
||||||
|
|
||||||
|
function getSystemColorMode(): ColorMode {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
? 'dark'
|
||||||
|
: 'light';
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeToMedia(
|
||||||
|
query: string,
|
||||||
|
listener: (event: MediaQueryListEvent) => void,
|
||||||
|
): () => void {
|
||||||
|
const mql = window.matchMedia(query);
|
||||||
|
mql.addEventListener('change', listener);
|
||||||
|
return () => mql.removeEventListener('change', listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeToSystemColorModeChange(
|
||||||
|
onChange: (newSystemColorMode: ColorMode) => void,
|
||||||
|
): () => void {
|
||||||
|
return subscribeToMedia('(prefers-color-scheme: dark)', () =>
|
||||||
|
onChange(getSystemColorMode()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
type ContextValue = {
|
type ContextValue = {
|
||||||
/** Current color mode. */
|
/** The effective color mode. */
|
||||||
readonly colorMode: ColorMode;
|
readonly colorMode: ColorMode;
|
||||||
|
/** The explicitly chosen color mode */
|
||||||
|
readonly colorModeChoice: ColorModeChoice;
|
||||||
/** Set new color mode. */
|
/** Set new color mode. */
|
||||||
readonly setColorMode: (colorMode: ColorMode) => void;
|
readonly setColorMode: (colorMode: ColorModeChoice) => void;
|
||||||
|
|
||||||
// TODO Docusaurus v4
|
// TODO Docusaurus v4
|
||||||
// legacy APIs kept for retro-compatibility: deprecate them
|
// legacy APIs kept for retro-compatibility: deprecate them
|
||||||
|
@ -37,16 +67,17 @@ const Context = React.createContext<ContextValue | undefined>(undefined);
|
||||||
const ColorModeStorageKey = 'theme';
|
const ColorModeStorageKey = 'theme';
|
||||||
const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
|
const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
|
||||||
|
|
||||||
const ColorModes = {
|
// We use data-theme-choice="system", not an absent attribute
|
||||||
light: 'light',
|
// This is easier to handle for users with CSS
|
||||||
dark: 'dark',
|
const SystemAttribute = 'system';
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type ColorMode = (typeof ColorModes)[keyof typeof ColorModes];
|
|
||||||
|
|
||||||
// Ensure to always return a valid colorMode even if input is invalid
|
// Ensure to always return a valid colorMode even if input is invalid
|
||||||
const coerceToColorMode = (colorMode?: string | null): ColorMode =>
|
const coerceToColorMode = (colorMode: string | null): ColorMode =>
|
||||||
colorMode === ColorModes.dark ? ColorModes.dark : ColorModes.light;
|
colorMode === 'dark' ? 'dark' : 'light';
|
||||||
|
const coerceToColorModeChoice = (colorMode: string | null): ColorModeChoice =>
|
||||||
|
colorMode === null || colorMode === SystemAttribute
|
||||||
|
? null
|
||||||
|
: coerceToColorMode(colorMode);
|
||||||
|
|
||||||
const ColorModeAttribute = {
|
const ColorModeAttribute = {
|
||||||
get: () => {
|
get: () => {
|
||||||
|
@ -62,15 +93,26 @@ const ColorModeAttribute = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const readInitialColorMode = (): ColorMode => {
|
const ColorModeChoiceAttribute = {
|
||||||
if (!ExecutionEnvironment.canUseDOM) {
|
get: () => {
|
||||||
throw new Error("Can't read initial color mode on the server");
|
return coerceToColorModeChoice(
|
||||||
}
|
document.documentElement.getAttribute('data-theme-choice'),
|
||||||
return ColorModeAttribute.get();
|
);
|
||||||
|
},
|
||||||
|
set: (colorMode: ColorModeChoice) => {
|
||||||
|
document.documentElement.setAttribute(
|
||||||
|
'data-theme-choice',
|
||||||
|
coerceToColorModeChoice(colorMode) ?? SystemAttribute,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const storeColorMode = (newColorMode: ColorMode) => {
|
const persistColorModeChoice = (newColorMode: ColorModeChoice) => {
|
||||||
ColorModeStorage.set(coerceToColorMode(newColorMode));
|
if (newColorMode === null) {
|
||||||
|
ColorModeStorage.del();
|
||||||
|
} else {
|
||||||
|
ColorModeStorage.set(coerceToColorMode(newColorMode));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The color mode state is initialized in useEffect on purpose
|
// The color mode state is initialized in useEffect on purpose
|
||||||
|
@ -83,20 +125,33 @@ function useColorModeState() {
|
||||||
colorMode: {defaultMode},
|
colorMode: {defaultMode},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
|
|
||||||
const [colorMode, setColorModeState] = useState(defaultMode);
|
const [colorMode, setColorModeState] = useState<ColorMode>(defaultMode);
|
||||||
|
const [colorModeChoice, setColorModeChoiceState] =
|
||||||
|
useState<ColorModeChoice>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setColorModeState(readInitialColorMode());
|
setColorModeState(ColorModeAttribute.get());
|
||||||
|
setColorModeChoiceState(ColorModeChoiceAttribute.get());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return [colorMode, setColorModeState] as const;
|
return {
|
||||||
|
colorMode,
|
||||||
|
setColorModeState,
|
||||||
|
colorModeChoice,
|
||||||
|
setColorModeChoiceState,
|
||||||
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useContextValue(): ContextValue {
|
function useContextValue(): ContextValue {
|
||||||
const {
|
const {
|
||||||
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
const [colorMode, setColorModeState] = useColorModeState();
|
const {
|
||||||
|
colorMode,
|
||||||
|
setColorModeState,
|
||||||
|
colorModeChoice,
|
||||||
|
setColorModeChoiceState,
|
||||||
|
} = useColorModeState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// A site is deployed without disableSwitch
|
// A site is deployed without disableSwitch
|
||||||
|
@ -109,67 +164,70 @@ function useContextValue(): ContextValue {
|
||||||
}, [disableSwitch]);
|
}, [disableSwitch]);
|
||||||
|
|
||||||
const setColorMode = useCallback(
|
const setColorMode = useCallback(
|
||||||
(newColorMode: ColorMode | null, options: {persist?: boolean} = {}) => {
|
(
|
||||||
|
newColorModeChoice: ColorModeChoice,
|
||||||
|
options: {persist?: boolean} = {},
|
||||||
|
) => {
|
||||||
const {persist = true} = options;
|
const {persist = true} = options;
|
||||||
|
|
||||||
if (newColorMode) {
|
// Reset to system/default color mode
|
||||||
|
if (newColorModeChoice === null) {
|
||||||
|
// Set the effective color
|
||||||
|
const newColorMode = respectPrefersColorScheme
|
||||||
|
? getSystemColorMode()
|
||||||
|
: defaultMode;
|
||||||
ColorModeAttribute.set(newColorMode);
|
ColorModeAttribute.set(newColorMode);
|
||||||
setColorModeState(newColorMode);
|
setColorModeState(newColorMode);
|
||||||
if (persist) {
|
// Set the chosen color
|
||||||
storeColorMode(newColorMode);
|
ColorModeChoiceAttribute.set(null);
|
||||||
}
|
setColorModeChoiceState(null);
|
||||||
} else {
|
}
|
||||||
if (respectPrefersColorScheme) {
|
// Happy case, when an explicit color is provided
|
||||||
const osColorMode = window.matchMedia('(prefers-color-scheme: dark)')
|
else {
|
||||||
.matches
|
ColorModeAttribute.set(newColorModeChoice);
|
||||||
? ColorModes.dark
|
ColorModeChoiceAttribute.set(newColorModeChoice);
|
||||||
: ColorModes.light;
|
setColorModeState(newColorModeChoice);
|
||||||
ColorModeAttribute.set(osColorMode);
|
setColorModeChoiceState(newColorModeChoice);
|
||||||
setColorModeState(osColorMode);
|
}
|
||||||
} else {
|
|
||||||
ColorModeAttribute.set(defaultMode);
|
if (persist) {
|
||||||
setColorModeState(defaultMode);
|
persistColorModeChoice(newColorModeChoice);
|
||||||
}
|
|
||||||
ColorModeStorage.del();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setColorModeState, respectPrefersColorScheme, defaultMode],
|
[
|
||||||
|
setColorModeState,
|
||||||
|
setColorModeChoiceState,
|
||||||
|
respectPrefersColorScheme,
|
||||||
|
defaultMode,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Synchronize theme color/choice mode with browser storage
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disableSwitch) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return ColorModeStorage.listen((e) => {
|
return ColorModeStorage.listen((e) => {
|
||||||
setColorMode(coerceToColorMode(e.newValue));
|
setColorMode(coerceToColorModeChoice(e.newValue));
|
||||||
});
|
});
|
||||||
}, [disableSwitch, setColorMode]);
|
}, [setColorMode]);
|
||||||
|
|
||||||
// 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
|
|
||||||
// the listener fires only because of a print/screen switch, we don't change
|
|
||||||
// color mode. See https://github.com/facebook/docusaurus/pull/6490
|
|
||||||
const previousMediaIsPrint = useRef(false);
|
|
||||||
|
|
||||||
|
// Synchronize theme color with system color
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disableSwitch && !respectPrefersColorScheme) {
|
if (colorModeChoice !== null || !respectPrefersColorScheme) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
return subscribeToSystemColorModeChange((newSystemColorMode) => {
|
||||||
const onChange = () => {
|
// Note: we don't use "setColorMode" on purpose
|
||||||
if (window.matchMedia('print').matches || previousMediaIsPrint.current) {
|
// The system changes should never be considered an explicit theme choice
|
||||||
previousMediaIsPrint.current = window.matchMedia('print').matches;
|
// They only affect the "effective" color, and should never be persisted
|
||||||
return;
|
// Note: this listener also fire when printing, see https://github.com/facebook/docusaurus/pull/6490
|
||||||
}
|
setColorModeState(newSystemColorMode);
|
||||||
setColorMode(null);
|
ColorModeAttribute.set(newSystemColorMode);
|
||||||
};
|
});
|
||||||
mql.addListener(onChange);
|
}, [respectPrefersColorScheme, colorModeChoice, setColorModeState]);
|
||||||
return () => mql.removeListener(onChange);
|
|
||||||
}, [setColorMode, disableSwitch, respectPrefersColorScheme]);
|
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
colorMode,
|
colorMode,
|
||||||
|
colorModeChoice,
|
||||||
setColorMode,
|
setColorMode,
|
||||||
get isDarkTheme() {
|
get isDarkTheme() {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
@ -177,7 +235,7 @@ function useContextValue(): ContextValue {
|
||||||
'`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.',
|
'`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return colorMode === ColorModes.dark;
|
return colorMode === 'dark';
|
||||||
},
|
},
|
||||||
setLightTheme() {
|
setLightTheme() {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
@ -185,7 +243,7 @@ function useContextValue(): ContextValue {
|
||||||
'`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.',
|
'`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setColorMode(ColorModes.light);
|
setColorMode('light');
|
||||||
},
|
},
|
||||||
setDarkTheme() {
|
setDarkTheme() {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
@ -193,10 +251,10 @@ function useContextValue(): ContextValue {
|
||||||
'`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.',
|
'`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setColorMode(ColorModes.dark);
|
setColorMode('dark');
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[colorMode, setColorMode],
|
[colorMode, colorModeChoice, setColorMode],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "التبديل بين الوضع الداكن والفاتح (الحالي {mode})",
|
"theme.colorToggle.ariaLabel": "التبديل بين الوضع الداكن والفاتح (الحالي {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "الوضع الداكن",
|
"theme.colorToggle.ariaLabel.mode.dark": "الوضع الداكن",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "الوضع الفاتح",
|
"theme.colorToggle.ariaLabel.mode.light": "الوضع الفاتح",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "تعديل هذه الصفحة",
|
"theme.common.editThisPage": "تعديل هذه الصفحة",
|
||||||
"theme.common.headingLinkTitle": "ارتباط مباشر بالعنوان {heading}",
|
"theme.common.headingLinkTitle": "ارتباط مباشر بالعنوان {heading}",
|
||||||
"theme.common.skipToMainContent": "انتقل إلى المحتوى الرئيسي",
|
"theme.common.skipToMainContent": "انتقل إلى المحتوى الرئيسي",
|
||||||
|
|
|
@ -78,11 +78,13 @@
|
||||||
"theme.blog.tagTitle": "{nPosts} tagged with \"{tagName}\"",
|
"theme.blog.tagTitle": "{nPosts} tagged with \"{tagName}\"",
|
||||||
"theme.blog.tagTitle___DESCRIPTION": "The title of the page for a blog tag",
|
"theme.blog.tagTitle___DESCRIPTION": "The title of the page for a blog tag",
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel___DESCRIPTION": "The ARIA label for the navbar color mode toggle",
|
"theme.colorToggle.ariaLabel___DESCRIPTION": "The ARIA label for the color mode toggle",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark___DESCRIPTION": "The name for the dark color mode",
|
"theme.colorToggle.ariaLabel.mode.dark___DESCRIPTION": "The name for the dark color mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light___DESCRIPTION": "The name for the light color mode",
|
"theme.colorToggle.ariaLabel.mode.light___DESCRIPTION": "The name for the light color mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system___DESCRIPTION": "The name for the system color mode",
|
||||||
"theme.common.editThisPage": "Edit this page",
|
"theme.common.editThisPage": "Edit this page",
|
||||||
"theme.common.editThisPage___DESCRIPTION": "The link label to edit the current page",
|
"theme.common.editThisPage___DESCRIPTION": "The link label to edit the current page",
|
||||||
"theme.common.headingLinkTitle": "Direct link to {heading}",
|
"theme.common.headingLinkTitle": "Direct link to {heading}",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Превключване между тъмен и светъл режим (В момента {mode})",
|
"theme.colorToggle.ariaLabel": "Превключване между тъмен и светъл режим (В момента {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "тъмен режим",
|
"theme.colorToggle.ariaLabel.mode.dark": "тъмен режим",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "светъл режим",
|
"theme.colorToggle.ariaLabel.mode.light": "светъл режим",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Редактирай тази страница",
|
"theme.common.editThisPage": "Редактирай тази страница",
|
||||||
"theme.common.headingLinkTitle": "Директна връзка към {heading}",
|
"theme.common.headingLinkTitle": "Директна връзка към {heading}",
|
||||||
"theme.common.skipToMainContent": "Преминете към основното съдържание",
|
"theme.common.skipToMainContent": "Преминете към основното съдържание",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "এই পেজটি এডিট করুন",
|
"theme.common.editThisPage": "এই পেজটি এডিট করুন",
|
||||||
"theme.common.headingLinkTitle": "{heading} এর সঙ্গে সরাসরি লিংকড",
|
"theme.common.headingLinkTitle": "{heading} এর সঙ্গে সরাসরি লিংকড",
|
||||||
"theme.common.skipToMainContent": "স্কিপ করে মূল কন্টেন্ট এ যান",
|
"theme.common.skipToMainContent": "স্কিপ করে মূল কন্টেন্ট এ যান",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Upravit tuto stránku",
|
"theme.common.editThisPage": "Upravit tuto stránku",
|
||||||
"theme.common.headingLinkTitle": "Přímý odkaz na {heading}",
|
"theme.common.headingLinkTitle": "Přímý odkaz na {heading}",
|
||||||
"theme.common.skipToMainContent": "Přeskočit na hlavní obsah",
|
"theme.common.skipToMainContent": "Přeskočit na hlavní obsah",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Rediger denne side",
|
"theme.common.editThisPage": "Rediger denne side",
|
||||||
"theme.common.headingLinkTitle": "Direkte link til {heading}",
|
"theme.common.headingLinkTitle": "Direkte link til {heading}",
|
||||||
"theme.common.skipToMainContent": "Hop til hovedindhold",
|
"theme.common.skipToMainContent": "Hop til hovedindhold",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Umschalten zwischen dunkler und heller Ansicht (momentan {mode})",
|
"theme.colorToggle.ariaLabel": "Umschalten zwischen dunkler und heller Ansicht (momentan {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dunkler Modus",
|
"theme.colorToggle.ariaLabel.mode.dark": "dunkler Modus",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "heller Modus",
|
"theme.colorToggle.ariaLabel.mode.light": "heller Modus",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Diese Seite bearbeiten",
|
"theme.common.editThisPage": "Diese Seite bearbeiten",
|
||||||
"theme.common.headingLinkTitle": "Direkter Link zur {heading}",
|
"theme.common.headingLinkTitle": "Direkter Link zur {heading}",
|
||||||
"theme.common.skipToMainContent": "Zum Hauptinhalt springen",
|
"theme.common.skipToMainContent": "Zum Hauptinhalt springen",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Cambiar entre modo oscuro y claro (actualmente {mode})",
|
"theme.colorToggle.ariaLabel": "Cambiar entre modo oscuro y claro (actualmente {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "modo oscuro",
|
"theme.colorToggle.ariaLabel.mode.dark": "modo oscuro",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "modo claro",
|
"theme.colorToggle.ariaLabel.mode.light": "modo claro",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Editar esta página",
|
"theme.common.editThisPage": "Editar esta página",
|
||||||
"theme.common.headingLinkTitle": "Enlace directo al {heading}",
|
"theme.common.headingLinkTitle": "Enlace directo al {heading}",
|
||||||
"theme.common.skipToMainContent": "Saltar al contenido principal",
|
"theme.common.skipToMainContent": "Saltar al contenido principal",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Vaheta heleda ja tumeda teema vahel (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Vaheta heleda ja tumeda teema vahel (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "tume teema",
|
"theme.colorToggle.ariaLabel.mode.dark": "tume teema",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "hele teema",
|
"theme.colorToggle.ariaLabel.mode.light": "hele teema",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Redigeeri seda lehte",
|
"theme.common.editThisPage": "Redigeeri seda lehte",
|
||||||
"theme.common.headingLinkTitle": "Link {heading}",
|
"theme.common.headingLinkTitle": "Link {heading}",
|
||||||
"theme.common.skipToMainContent": "Liigu peamise sisu juurde",
|
"theme.common.skipToMainContent": "Liigu peamise sisu juurde",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "بین حالت تاریک و روشن سوئیچ کنید (الان {mode})",
|
"theme.colorToggle.ariaLabel": "بین حالت تاریک و روشن سوئیچ کنید (الان {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "حالت تیره",
|
"theme.colorToggle.ariaLabel.mode.dark": "حالت تیره",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "حالت روشن",
|
"theme.colorToggle.ariaLabel.mode.light": "حالت روشن",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "ویرایش مطالب این صفحه",
|
"theme.common.editThisPage": "ویرایش مطالب این صفحه",
|
||||||
"theme.common.headingLinkTitle": "لینک مستقیم به {heading}",
|
"theme.common.headingLinkTitle": "لینک مستقیم به {heading}",
|
||||||
"theme.common.skipToMainContent": "پرش به مطلب اصلی",
|
"theme.common.skipToMainContent": "پرش به مطلب اصلی",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "I-edit ang page",
|
"theme.common.editThisPage": "I-edit ang page",
|
||||||
"theme.common.headingLinkTitle": "Direktang link patungo sa {heading}",
|
"theme.common.headingLinkTitle": "Direktang link patungo sa {heading}",
|
||||||
"theme.common.skipToMainContent": "Lumaktaw patungo sa pangunahing content",
|
"theme.common.skipToMainContent": "Lumaktaw patungo sa pangunahing content",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Basculer entre le mode sombre et clair (actuellement {mode})",
|
"theme.colorToggle.ariaLabel": "Basculer entre le mode sombre et clair (actuellement {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "mode sombre",
|
"theme.colorToggle.ariaLabel.mode.dark": "mode sombre",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "mode clair",
|
"theme.colorToggle.ariaLabel.mode.light": "mode clair",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Éditer cette page",
|
"theme.common.editThisPage": "Éditer cette page",
|
||||||
"theme.common.headingLinkTitle": "Lien direct vers {heading}",
|
"theme.common.headingLinkTitle": "Lien direct vers {heading}",
|
||||||
"theme.common.skipToMainContent": "Aller au contenu principal",
|
"theme.common.skipToMainContent": "Aller au contenu principal",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "ערוך דף זה",
|
"theme.common.editThisPage": "ערוך דף זה",
|
||||||
"theme.common.headingLinkTitle": "קישור ישיר אל {heading}",
|
"theme.common.headingLinkTitle": "קישור ישיר אל {heading}",
|
||||||
"theme.common.skipToMainContent": "דלג לתוכן הראשי",
|
"theme.common.skipToMainContent": "דלג לתוכן הראשי",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "इस पेज को बदलें",
|
"theme.common.editThisPage": "इस पेज को बदलें",
|
||||||
"theme.common.headingLinkTitle": "{heading} का सीधा लिंक",
|
"theme.common.headingLinkTitle": "{heading} का सीधा लिंक",
|
||||||
"theme.common.skipToMainContent": "मुख्य कंटेंट तक स्किप करें",
|
"theme.common.skipToMainContent": "मुख्य कंटेंट तक स्किप करें",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Váltás a sötét és világos mód között (jelenleg {mode} van beállítva)",
|
"theme.colorToggle.ariaLabel": "Váltás a sötét és világos mód között (jelenleg {mode} van beállítva)",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Sötét mód",
|
"theme.colorToggle.ariaLabel.mode.dark": "Sötét mód",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "Világos mód",
|
"theme.colorToggle.ariaLabel.mode.light": "Világos mód",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Szerkesztés GitHub-on",
|
"theme.common.editThisPage": "Szerkesztés GitHub-on",
|
||||||
"theme.common.headingLinkTitle": "Közvetlen hivatkozás erre: {heading}",
|
"theme.common.headingLinkTitle": "Közvetlen hivatkozás erre: {heading}",
|
||||||
"theme.common.skipToMainContent": "Ugrás a fő tartalomhoz",
|
"theme.common.skipToMainContent": "Ugrás a fő tartalomhoz",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Ubah antara modus gelap dan modus terang (saat ini {mode})",
|
"theme.colorToggle.ariaLabel": "Ubah antara modus gelap dan modus terang (saat ini {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "modus gelap",
|
"theme.colorToggle.ariaLabel.mode.dark": "modus gelap",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "modus terang",
|
"theme.colorToggle.ariaLabel.mode.light": "modus terang",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Sunting halaman ini",
|
"theme.common.editThisPage": "Sunting halaman ini",
|
||||||
"theme.common.headingLinkTitle": "Taut langsung ke {heading}",
|
"theme.common.headingLinkTitle": "Taut langsung ke {heading}",
|
||||||
"theme.common.skipToMainContent": "Lewati ke konten utama",
|
"theme.common.skipToMainContent": "Lewati ke konten utama",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Skiptu á milli rökkur stillingar og bjartar stillingar (núna {mode})",
|
"theme.colorToggle.ariaLabel": "Skiptu á milli rökkur stillingar og bjartar stillingar (núna {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "rökkur stilling",
|
"theme.colorToggle.ariaLabel.mode.dark": "rökkur stilling",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "björt stilling",
|
"theme.colorToggle.ariaLabel.mode.light": "björt stilling",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Breyttu þessari síðu",
|
"theme.common.editThisPage": "Breyttu þessari síðu",
|
||||||
"theme.common.headingLinkTitle": "Beinn hlekkur að {heading}",
|
"theme.common.headingLinkTitle": "Beinn hlekkur að {heading}",
|
||||||
"theme.common.skipToMainContent": "Hoppa yfir á aðal efni",
|
"theme.common.skipToMainContent": "Hoppa yfir á aðal efni",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Passa dalla modalità scura a quella chiara (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Passa dalla modalità scura a quella chiara (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Modalità scura",
|
"theme.colorToggle.ariaLabel.mode.dark": "Modalità scura",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "modalità luce",
|
"theme.colorToggle.ariaLabel.mode.light": "modalità luce",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Modifica questa pagina",
|
"theme.common.editThisPage": "Modifica questa pagina",
|
||||||
"theme.common.headingLinkTitle": "Link diretto a {heading}",
|
"theme.common.headingLinkTitle": "Link diretto a {heading}",
|
||||||
"theme.common.skipToMainContent": "Passa al contenuto principale",
|
"theme.common.skipToMainContent": "Passa al contenuto principale",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "ダークモードを切り替える(現在は{mode})",
|
"theme.colorToggle.ariaLabel": "ダークモードを切り替える(現在は{mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "ダークモード",
|
"theme.colorToggle.ariaLabel.mode.dark": "ダークモード",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "ライトモード",
|
"theme.colorToggle.ariaLabel.mode.light": "ライトモード",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "このページを編集",
|
"theme.common.editThisPage": "このページを編集",
|
||||||
"theme.common.headingLinkTitle": "{heading} への直接リンク",
|
"theme.common.headingLinkTitle": "{heading} への直接リンク",
|
||||||
"theme.common.skipToMainContent": "メインコンテンツまでスキップ",
|
"theme.common.skipToMainContent": "メインコンテンツまでスキップ",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "어두운 모드와 밝은 모드 전환하기 (현재 {mode})",
|
"theme.colorToggle.ariaLabel": "어두운 모드와 밝은 모드 전환하기 (현재 {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "어두운 모드",
|
"theme.colorToggle.ariaLabel.mode.dark": "어두운 모드",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "밝은 모드",
|
"theme.colorToggle.ariaLabel.mode.light": "밝은 모드",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "페이지 편집",
|
"theme.common.editThisPage": "페이지 편집",
|
||||||
"theme.common.headingLinkTitle": "{heading}에 대한 직접 링크",
|
"theme.common.headingLinkTitle": "{heading}에 대한 직접 링크",
|
||||||
"theme.common.skipToMainContent": "본문으로 건너뛰기",
|
"theme.common.skipToMainContent": "본문으로 건너뛰기",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Bytt mellom mørk og lys utseende (nå {mode})",
|
"theme.colorToggle.ariaLabel": "Bytt mellom mørk og lys utseende (nå {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "mørk utseende",
|
"theme.colorToggle.ariaLabel.mode.dark": "mørk utseende",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "lys utseende",
|
"theme.colorToggle.ariaLabel.mode.light": "lys utseende",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Rediger denne siden",
|
"theme.common.editThisPage": "Rediger denne siden",
|
||||||
"theme.common.headingLinkTitle": "Direkte lenke til {heading}",
|
"theme.common.headingLinkTitle": "Direkte lenke til {heading}",
|
||||||
"theme.common.skipToMainContent": "Gå til hovedinnhold",
|
"theme.common.skipToMainContent": "Gå til hovedinnhold",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Schakel tussen donkere en lichte modus (momenteel {mode})",
|
"theme.colorToggle.ariaLabel": "Schakel tussen donkere en lichte modus (momenteel {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "donkere modus",
|
"theme.colorToggle.ariaLabel.mode.dark": "donkere modus",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "lichte modus",
|
"theme.colorToggle.ariaLabel.mode.light": "lichte modus",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Bewerk deze pagina",
|
"theme.common.editThisPage": "Bewerk deze pagina",
|
||||||
"theme.common.headingLinkTitle": "Direct link naar {heading}",
|
"theme.common.headingLinkTitle": "Direct link naar {heading}",
|
||||||
"theme.common.skipToMainContent": "Ga naar hoofdinhoud",
|
"theme.common.skipToMainContent": "Ga naar hoofdinhoud",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Przełącz pomiędzy ciemnym a jasnym motywem (aktualnie ustawiony {mode})",
|
"theme.colorToggle.ariaLabel": "Przełącz pomiędzy ciemnym a jasnym motywem (aktualnie ustawiony {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "ciemny motyw",
|
"theme.colorToggle.ariaLabel.mode.dark": "ciemny motyw",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "jasny motyw",
|
"theme.colorToggle.ariaLabel.mode.light": "jasny motyw",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Edytuj tę stronę",
|
"theme.common.editThisPage": "Edytuj tę stronę",
|
||||||
"theme.common.headingLinkTitle": "Bezpośredni link do {heading}",
|
"theme.common.headingLinkTitle": "Bezpośredni link do {heading}",
|
||||||
"theme.common.skipToMainContent": "Przejdź do głównej zawartości",
|
"theme.common.skipToMainContent": "Przejdź do głównej zawartości",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Alterar entre os modos claro e escuro (modo {mode} ativado)",
|
"theme.colorToggle.ariaLabel": "Alterar entre os modos claro e escuro (modo {mode} ativado)",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "modo escuro",
|
"theme.colorToggle.ariaLabel.mode.dark": "modo escuro",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "modo claro",
|
"theme.colorToggle.ariaLabel.mode.light": "modo claro",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Editar essa página",
|
"theme.common.editThisPage": "Editar essa página",
|
||||||
"theme.common.headingLinkTitle": "Link direto para {heading}",
|
"theme.common.headingLinkTitle": "Link direto para {heading}",
|
||||||
"theme.common.skipToMainContent": "Pular para o conteúdo principal",
|
"theme.common.skipToMainContent": "Pular para o conteúdo principal",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Editar esta página",
|
"theme.common.editThisPage": "Editar esta página",
|
||||||
"theme.common.headingLinkTitle": "Link direto para {heading}",
|
"theme.common.headingLinkTitle": "Link direto para {heading}",
|
||||||
"theme.common.skipToMainContent": "Saltar para o conteúdo principal",
|
"theme.common.skipToMainContent": "Saltar para o conteúdo principal",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Переключение между темным и светлым режимом (сейчас используется {mode})",
|
"theme.colorToggle.ariaLabel": "Переключение между темным и светлым режимом (сейчас используется {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Тёмный режим",
|
"theme.colorToggle.ariaLabel.mode.dark": "Тёмный режим",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "Светлый режим",
|
"theme.colorToggle.ariaLabel.mode.light": "Светлый режим",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Отредактировать эту страницу",
|
"theme.common.editThisPage": "Отредактировать эту страницу",
|
||||||
"theme.common.headingLinkTitle": "Прямая ссылка на {heading}",
|
"theme.common.headingLinkTitle": "Прямая ссылка на {heading}",
|
||||||
"theme.common.skipToMainContent": "Перейти к основному содержимому",
|
"theme.common.skipToMainContent": "Перейти к основному содержимому",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Preklopi med temnim in svetlim načinom (trenutno {mode})",
|
"theme.colorToggle.ariaLabel": "Preklopi med temnim in svetlim načinom (trenutno {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "temni način",
|
"theme.colorToggle.ariaLabel.mode.dark": "temni način",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "svetli način",
|
"theme.colorToggle.ariaLabel.mode.light": "svetli način",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Uredi to stran",
|
"theme.common.editThisPage": "Uredi to stran",
|
||||||
"theme.common.headingLinkTitle": "Direktna povezava na {heading}",
|
"theme.common.headingLinkTitle": "Direktna povezava na {heading}",
|
||||||
"theme.common.skipToMainContent": "Preskoči na vsebino",
|
"theme.common.skipToMainContent": "Preskoči na vsebino",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
"theme.colorToggle.ariaLabel.mode.dark": "dark mode",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
"theme.colorToggle.ariaLabel.mode.light": "light mode",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Уреди ову страницу",
|
"theme.common.editThisPage": "Уреди ову страницу",
|
||||||
"theme.common.headingLinkTitle": "Веза до {heading}",
|
"theme.common.headingLinkTitle": "Веза до {heading}",
|
||||||
"theme.common.skipToMainContent": "Пређи на главни садржај",
|
"theme.common.skipToMainContent": "Пређи на главни садржај",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Växla mellan mörkt och ljust utseende (currently {mode})",
|
"theme.colorToggle.ariaLabel": "Växla mellan mörkt och ljust utseende (currently {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "mörkt utseende",
|
"theme.colorToggle.ariaLabel.mode.dark": "mörkt utseende",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "ljust utseende",
|
"theme.colorToggle.ariaLabel.mode.light": "ljust utseende",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Redigera denna sida",
|
"theme.common.editThisPage": "Redigera denna sida",
|
||||||
"theme.common.headingLinkTitle": "Direktlänk till {heading}",
|
"theme.common.headingLinkTitle": "Direktlänk till {heading}",
|
||||||
"theme.common.skipToMainContent": "Hoppa till huvudinnehåll",
|
"theme.common.skipToMainContent": "Hoppa till huvudinnehåll",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Gijeki ýa-da gündizki temany saýlamak (häzirki wagtda {mode} ulanylýar)",
|
"theme.colorToggle.ariaLabel": "Gijeki ýa-da gündizki temany saýlamak (häzirki wagtda {mode} ulanylýar)",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Gijeki tema",
|
"theme.colorToggle.ariaLabel.mode.dark": "Gijeki tema",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "Gündizki tema",
|
"theme.colorToggle.ariaLabel.mode.light": "Gündizki tema",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Bu sahypany üýtgetmek",
|
"theme.common.editThisPage": "Bu sahypany üýtgetmek",
|
||||||
"theme.common.headingLinkTitle": "{heading} sahypa göni geçiň",
|
"theme.common.headingLinkTitle": "{heading} sahypa göni geçiň",
|
||||||
"theme.common.skipToMainContent": "Esasy mazmuna geç",
|
"theme.common.skipToMainContent": "Esasy mazmuna geç",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Karanlık ve aydınlık mod arasında geçiş yapın (şu anda {mode})",
|
"theme.colorToggle.ariaLabel": "Karanlık ve aydınlık mod arasında geçiş yapın (şu anda {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Karanlık mod",
|
"theme.colorToggle.ariaLabel.mode.dark": "Karanlık mod",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "Aydınlık mod",
|
"theme.colorToggle.ariaLabel.mode.light": "Aydınlık mod",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Bu sayfayı düzenle",
|
"theme.common.editThisPage": "Bu sayfayı düzenle",
|
||||||
"theme.common.headingLinkTitle": "{heading} doğrudan bağlantı",
|
"theme.common.headingLinkTitle": "{heading} doğrudan bağlantı",
|
||||||
"theme.common.skipToMainContent": "Ana içeriğe geç",
|
"theme.common.skipToMainContent": "Ana içeriğe geç",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Перемикання між темним та світлим режимом (зараз використовується {mode})",
|
"theme.colorToggle.ariaLabel": "Перемикання між темним та світлим режимом (зараз використовується {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "Темний режим",
|
"theme.colorToggle.ariaLabel.mode.dark": "Темний режим",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "Світлий режим",
|
"theme.colorToggle.ariaLabel.mode.light": "Світлий режим",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Відредагувати цю сторінку",
|
"theme.common.editThisPage": "Відредагувати цю сторінку",
|
||||||
"theme.common.headingLinkTitle": "Пряме посилання на {heading}",
|
"theme.common.headingLinkTitle": "Пряме посилання на {heading}",
|
||||||
"theme.common.skipToMainContent": "Перейти до основного вмісту",
|
"theme.common.skipToMainContent": "Перейти до основного вмісту",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "Chuyển đổi chế độ sáng và tối (hiện tại là {mode})",
|
"theme.colorToggle.ariaLabel": "Chuyển đổi chế độ sáng và tối (hiện tại là {mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "chế độ tối",
|
"theme.colorToggle.ariaLabel.mode.dark": "chế độ tối",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "chế độ sáng",
|
"theme.colorToggle.ariaLabel.mode.light": "chế độ sáng",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "Sửa trang này",
|
"theme.common.editThisPage": "Sửa trang này",
|
||||||
"theme.common.headingLinkTitle": "Đường dẫn trực tiếp đến {heading}",
|
"theme.common.headingLinkTitle": "Đường dẫn trực tiếp đến {heading}",
|
||||||
"theme.common.skipToMainContent": "Chuyển tới nội dung chính",
|
"theme.common.skipToMainContent": "Chuyển tới nội dung chính",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "切换浅色/暗黑模式(当前为{mode})",
|
"theme.colorToggle.ariaLabel": "切换浅色/暗黑模式(当前为{mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "暗黑模式",
|
"theme.colorToggle.ariaLabel.mode.dark": "暗黑模式",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "浅色模式",
|
"theme.colorToggle.ariaLabel.mode.light": "浅色模式",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "编辑此页",
|
"theme.common.editThisPage": "编辑此页",
|
||||||
"theme.common.headingLinkTitle": "{heading}的直接链接",
|
"theme.common.headingLinkTitle": "{heading}的直接链接",
|
||||||
"theme.common.skipToMainContent": "跳到主要内容",
|
"theme.common.skipToMainContent": "跳到主要内容",
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"theme.colorToggle.ariaLabel": "切換淺色/深色模式(當前為{mode})",
|
"theme.colorToggle.ariaLabel": "切換淺色/深色模式(當前為{mode})",
|
||||||
"theme.colorToggle.ariaLabel.mode.dark": "深色模式",
|
"theme.colorToggle.ariaLabel.mode.dark": "深色模式",
|
||||||
"theme.colorToggle.ariaLabel.mode.light": "淺色模式",
|
"theme.colorToggle.ariaLabel.mode.light": "淺色模式",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.system": "system mode",
|
||||||
"theme.common.editThisPage": "編輯此頁",
|
"theme.common.editThisPage": "編輯此頁",
|
||||||
"theme.common.headingLinkTitle": "{heading}的直接連結",
|
"theme.common.headingLinkTitle": "{heading}的直接連結",
|
||||||
"theme.common.skipToMainContent": "跳至主要内容",
|
"theme.common.skipToMainContent": "跳至主要内容",
|
||||||
|
|
|
@ -1114,23 +1114,93 @@ export default {
|
||||||
|
|
||||||
### `useColorMode` {#use-color-mode}
|
### `useColorMode` {#use-color-mode}
|
||||||
|
|
||||||
A React hook to access the color context. This context contains functions for setting light and dark mode and exposes boolean variable, indicating which mode is currently in use.
|
A React hook to access the color context. This context contains functions for selecting light/dark/system mode and exposes the current color mode and the choice from the user. The color mode values **should not be used for dynamic content rendering** (see below).
|
||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import React from 'react';
|
|
||||||
// highlight-next-line
|
// highlight-next-line
|
||||||
import {useColorMode} from '@docusaurus/theme-common';
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
const Example = () => {
|
const MyColorModeButton = () => {
|
||||||
// highlight-next-line
|
// highlight-start
|
||||||
const {colorMode, setColorMode} = useColorMode();
|
const {
|
||||||
|
colorMode, // the "effective" color mode, never null
|
||||||
|
colorModeChoice, // the color mode chosen by the user, can be null
|
||||||
|
setColorMode, // set the color mode chosen by the user
|
||||||
|
} = useColorMode();
|
||||||
|
// highlight-end
|
||||||
|
|
||||||
return <h1>Dark mode is now {colorMode === 'dark' ? 'on' : 'off'}</h1>;
|
return (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
const nextColorMode = colorModeChoice === 'dark' ? 'light' : 'dark';
|
||||||
|
setColorMode(nextColorMode);
|
||||||
|
}}>
|
||||||
|
Toggle color mode
|
||||||
|
</button>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
|
||||||
|
- `colorMode: 'light' | 'dark'`: The effective color mode currently applied to the UI. It cannot be `null`.
|
||||||
|
- `colorModeChoice: 'light' | 'dark' | null`: The color mode explicitly chosen by the user. It can be `null` if user has not made any choice yet, or if they reset their choice to the system/default value.
|
||||||
|
- `setColorMode(colorModeChoice: 'light' | 'dark' | null, options: {persist: boolean}): void`: A function to call when the user explicitly chose a color mode. `null` permits to reset the choice to the system/default value. By default, the choice is persisted in `localStorage` and restored on page reload, but you can opt out with `{persist: false}`.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
Don't use `colorMode` and `colorModeChoice` while rendering React components. Doing so is likely to produce [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content), layout shifts and [React hydration](https://18.react.dev/reference/react-dom/client/hydrateRoot) mismatches if you use them to render JSX content dynamically.
|
||||||
|
|
||||||
|
However, these values are safe to use **after React hydration**, in `useEffect` and event listeners, like in the `MyColorModeButton` example above.
|
||||||
|
|
||||||
|
If you need to render content dynamically depending on the current theme, the only way to avoid FOUC, layout shifts and hydration mismatch is to rely on CSS selectors to render content dynamically, based on the `html` data attributes that we set before the page displays anything:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<html data-theme="<light | dark>" data-theme-choice="<light | dark | system>">
|
||||||
|
<!-- content -->
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
[data-theme='light']
|
||||||
|
[data-theme='dark']
|
||||||
|
|
||||||
|
[data-theme-choice='light']
|
||||||
|
[data-theme-choice='dark']
|
||||||
|
[data-theme-choice='system']
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Why are `colorMode` and `colorModeChoice` unsafe when rendering?</summary>
|
||||||
|
|
||||||
|
To understand the problem, you need to understand how [React hydration](https://18.react.dev/reference/react-dom/client/hydrateRoot) works.
|
||||||
|
|
||||||
|
During the static site generation phase, Docusaurus doesn't know what the user color mode choice is, and `useColorMode()` returns the following static values:
|
||||||
|
|
||||||
|
- `colorMode = themeConfig.colorMode.defaultMode`
|
||||||
|
- `colorModeChoice = null`
|
||||||
|
|
||||||
|
During the very first React client-side render (the hydration), React must produce the exact same HTML markup, and will also use these static values.
|
||||||
|
|
||||||
|
The correct `colorMode` and `colorModeChoice` values will only be provided in the second React render.
|
||||||
|
|
||||||
|
Typically, the following component will lead to **React hydration mismatches**. The label may switch from `light` to `dark` while React hydrates, leading to a confusing user experience.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
|
const DisplayCurrentColorMode = () => {
|
||||||
|
const {colorMode} = useColorMode();
|
||||||
|
return <span>{colorMode}</span>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
The component calling `useColorMode` must be a child of the `Layout` component.
|
The component calling `useColorMode` must be a child of the `Layout` component.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue