@docusaurus/theme-classic 2.3.1 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +12 -3
- package/lib/theme/CodeBlock/Content/styles.module.css +2 -1
- package/lib/theme/CodeBlock/CopyButton/index.js +4 -6
- package/lib/theme/CodeBlock/CopyButton/styles.module.css +1 -1
- package/lib/theme/CodeBlock/WordWrapButton/index.js +2 -9
- package/lib/theme/ColorModeToggle/index.d.ts +1 -1
- package/lib/theme/ColorModeToggle/index.js +2 -1
- package/lib/theme/DocCard/index.js +13 -10
- package/lib/theme/DocPage/Layout/Sidebar/index.js +6 -1
- package/lib/theme/DocPage/Layout/styles.module.css +1 -0
- package/lib/theme/DocPaginator/index.js +1 -1
- package/lib/theme/ErrorPageContent.js +13 -9
- package/lib/theme/Icon/Copy/index.d.ts +9 -0
- package/lib/theme/Icon/Copy/index.js +17 -0
- package/lib/theme/Icon/Success/index.d.ts +9 -0
- package/lib/theme/Icon/Success/index.js +17 -0
- package/lib/theme/Icon/WordWrap/index.d.ts +9 -0
- package/lib/theme/Icon/WordWrap/index.js +17 -0
- package/lib/theme/Navbar/ColorModeToggle/index.js +5 -0
- package/lib/theme/Navbar/ColorModeToggle/styles.module.css +10 -0
- package/lib/theme/Navbar/Content/index.js +13 -2
- package/lib/theme/NavbarItem/DropdownNavbarItem.js +2 -16
- package/lib/theme/Tabs/index.js +5 -4
- package/lib/translations.js +41 -2
- package/package.json +15 -15
- package/src/index.ts +13 -3
- package/src/theme/CodeBlock/Content/styles.module.css +2 -1
- package/src/theme/CodeBlock/CopyButton/index.tsx +4 -6
- package/src/theme/CodeBlock/CopyButton/styles.module.css +1 -1
- package/src/theme/CodeBlock/WordWrapButton/index.tsx +2 -9
- package/src/theme/ColorModeToggle/index.tsx +7 -1
- package/src/theme/DocCard/index.tsx +13 -10
- package/src/theme/DocPage/Layout/Sidebar/index.tsx +6 -1
- package/src/theme/DocPage/Layout/styles.module.css +1 -0
- package/src/theme/DocPaginator/index.tsx +1 -1
- package/src/theme/ErrorPageContent.tsx +13 -9
- package/src/theme/Icon/Copy/index.tsx +20 -0
- package/src/theme/Icon/Success/index.tsx +20 -0
- package/src/theme/Icon/WordWrap/index.tsx +20 -0
- package/src/theme/Navbar/ColorModeToggle/index.tsx +5 -0
- package/src/theme/Navbar/ColorModeToggle/styles.module.css +10 -0
- package/src/theme/Navbar/Content/index.tsx +13 -2
- package/src/theme/NavbarItem/DropdownNavbarItem.tsx +5 -17
- package/src/theme/Tabs/index.tsx +7 -5
- package/src/theme-classic.d.ts +25 -0
- package/src/translations.ts +46 -2
package/lib/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const ContextReplacementPlugin = requireFromDocusaurusCore('webpack/lib/ContextR
|
|
|
18
18
|
// Need to be inlined to prevent dark mode FOUC
|
|
19
19
|
// Make sure the key is the same as the one in `/theme/hooks/useTheme.js`
|
|
20
20
|
const ThemeStorageKey = 'theme';
|
|
21
|
+
const ThemeQueryStringKey = 'docusaurus-theme';
|
|
21
22
|
const noFlashColorMode = ({ defaultMode, respectPrefersColorScheme, }) =>
|
|
22
23
|
/* language=js */
|
|
23
24
|
`(function() {
|
|
@@ -28,6 +29,14 @@ const noFlashColorMode = ({ defaultMode, respectPrefersColorScheme, }) =>
|
|
|
28
29
|
document.documentElement.setAttribute('data-theme', theme);
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
function getQueryStringTheme() {
|
|
33
|
+
var theme = null;
|
|
34
|
+
try {
|
|
35
|
+
theme = new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
|
|
36
|
+
} catch(e) {}
|
|
37
|
+
return theme;
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
function getStoredTheme() {
|
|
32
41
|
var theme = null;
|
|
33
42
|
try {
|
|
@@ -36,9 +45,9 @@ const noFlashColorMode = ({ defaultMode, respectPrefersColorScheme, }) =>
|
|
|
36
45
|
return theme;
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
var
|
|
40
|
-
if (
|
|
41
|
-
setDataThemeAttribute(
|
|
48
|
+
var initialTheme = getQueryStringTheme() || getStoredTheme();
|
|
49
|
+
if (initialTheme !== null) {
|
|
50
|
+
setDataThemeAttribute(initialTheme);
|
|
42
51
|
} else {
|
|
43
52
|
if (
|
|
44
53
|
respectPrefersColorScheme &&
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
display: flex;
|
|
60
60
|
column-gap: 0.2rem;
|
|
61
61
|
position: absolute;
|
|
62
|
+
/* rtl:ignore */
|
|
62
63
|
right: calc(var(--ifm-pre-padding) / 2);
|
|
63
64
|
top: calc(var(--ifm-pre-padding) / 2);
|
|
64
65
|
}
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
border-radius: var(--ifm-global-radius);
|
|
73
74
|
padding: 0.4rem;
|
|
74
75
|
line-height: 0;
|
|
75
|
-
transition: opacity
|
|
76
|
+
transition: opacity var(--ifm-transition-fast) ease-in-out;
|
|
76
77
|
opacity: 0;
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -9,6 +9,8 @@ import clsx from 'clsx';
|
|
|
9
9
|
// @ts-expect-error: TODO, we need to make theme-classic have type: module
|
|
10
10
|
import copy from 'copy-text-to-clipboard';
|
|
11
11
|
import {translate} from '@docusaurus/Translate';
|
|
12
|
+
import IconCopy from '@theme/Icon/Copy';
|
|
13
|
+
import IconSuccess from '@theme/Icon/Success';
|
|
12
14
|
import styles from './styles.module.css';
|
|
13
15
|
export default function CopyButton({code, className}) {
|
|
14
16
|
const [isCopied, setIsCopied] = useState(false);
|
|
@@ -50,12 +52,8 @@ export default function CopyButton({code, className}) {
|
|
|
50
52
|
)}
|
|
51
53
|
onClick={handleCopyCode}>
|
|
52
54
|
<span className={styles.copyButtonIcons} aria-hidden="true">
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
</svg>
|
|
56
|
-
<svg className={styles.copyButtonSuccessIcon} viewBox="0 0 24 24">
|
|
57
|
-
<path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" />
|
|
58
|
-
</svg>
|
|
55
|
+
<IconCopy className={styles.copyButtonIcon} />
|
|
56
|
+
<IconSuccess className={styles.copyButtonSuccessIcon} />
|
|
59
57
|
</span>
|
|
60
58
|
</button>
|
|
61
59
|
);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
9
|
import {translate} from '@docusaurus/Translate';
|
|
10
|
+
import IconWordWrap from '@theme/Icon/WordWrap';
|
|
10
11
|
import styles from './styles.module.css';
|
|
11
12
|
export default function WordWrapButton({className, onClick, isEnabled}) {
|
|
12
13
|
const title = translate({
|
|
@@ -26,15 +27,7 @@ export default function WordWrapButton({className, onClick, isEnabled}) {
|
|
|
26
27
|
)}
|
|
27
28
|
aria-label={title}
|
|
28
29
|
title={title}>
|
|
29
|
-
<
|
|
30
|
-
className={styles.wordWrapButtonIcon}
|
|
31
|
-
viewBox="0 0 24 24"
|
|
32
|
-
aria-hidden="true">
|
|
33
|
-
<path
|
|
34
|
-
fill="currentColor"
|
|
35
|
-
d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"
|
|
36
|
-
/>
|
|
37
|
-
</svg>
|
|
30
|
+
<IconWordWrap className={styles.wordWrapButtonIcon} aria-hidden="true" />
|
|
38
31
|
</button>
|
|
39
32
|
);
|
|
40
33
|
}
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import type { Props } from '@theme/ColorModeToggle';
|
|
9
|
-
declare function ColorModeToggle({ className, value, onChange }: Props): JSX.Element;
|
|
9
|
+
declare function ColorModeToggle({ className, buttonClassName, value, onChange, }: Props): JSX.Element;
|
|
10
10
|
declare const _default: React.MemoExoticComponent<typeof ColorModeToggle>;
|
|
11
11
|
export default _default;
|
|
@@ -11,7 +11,7 @@ import {translate} from '@docusaurus/Translate';
|
|
|
11
11
|
import IconLightMode from '@theme/Icon/LightMode';
|
|
12
12
|
import IconDarkMode from '@theme/Icon/DarkMode';
|
|
13
13
|
import styles from './styles.module.css';
|
|
14
|
-
function ColorModeToggle({className, value, onChange}) {
|
|
14
|
+
function ColorModeToggle({className, buttonClassName, value, onChange}) {
|
|
15
15
|
const isBrowser = useIsBrowser();
|
|
16
16
|
const title = translate(
|
|
17
17
|
{
|
|
@@ -41,6 +41,7 @@ function ColorModeToggle({className, value, onChange}) {
|
|
|
41
41
|
'clean-btn',
|
|
42
42
|
styles.toggleButton,
|
|
43
43
|
!isBrowser && styles.toggleButtonDisabled,
|
|
44
|
+
buttonClassName,
|
|
44
45
|
)}
|
|
45
46
|
type="button"
|
|
46
47
|
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
|
|
@@ -50,15 +50,18 @@ function CardCategory({item}) {
|
|
|
50
50
|
href={href}
|
|
51
51
|
icon="🗃️"
|
|
52
52
|
title={item.label}
|
|
53
|
-
description={
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
description={
|
|
54
|
+
item.description ??
|
|
55
|
+
translate(
|
|
56
|
+
{
|
|
57
|
+
message: '{count} items',
|
|
58
|
+
id: 'theme.docs.DocCard.categoryDescription',
|
|
59
|
+
description:
|
|
60
|
+
'The default description for a category card in the generated index about how many items this category includes',
|
|
61
|
+
},
|
|
62
|
+
{count: item.items.length},
|
|
63
|
+
)
|
|
64
|
+
}
|
|
62
65
|
/>
|
|
63
66
|
);
|
|
64
67
|
}
|
|
@@ -70,7 +73,7 @@ function CardLink({item}) {
|
|
|
70
73
|
href={item.href}
|
|
71
74
|
icon={icon}
|
|
72
75
|
title={item.label}
|
|
73
|
-
description={doc?.description}
|
|
76
|
+
description={item.description ?? doc?.description}
|
|
74
77
|
/>
|
|
75
78
|
);
|
|
76
79
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React, {useState, useCallback} from 'react';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
|
-
import {ThemeClassNames} from '@docusaurus/theme-common';
|
|
9
|
+
import {prefersReducedMotion, ThemeClassNames} from '@docusaurus/theme-common';
|
|
10
10
|
import {useDocsSidebar} from '@docusaurus/theme-common/internal';
|
|
11
11
|
import {useLocation} from '@docusaurus/router';
|
|
12
12
|
import DocSidebar from '@theme/DocSidebar';
|
|
@@ -34,6 +34,11 @@ export default function DocPageLayoutSidebar({
|
|
|
34
34
|
if (hiddenSidebar) {
|
|
35
35
|
setHiddenSidebar(false);
|
|
36
36
|
}
|
|
37
|
+
// onTransitionEnd won't fire when sidebar animation is disabled
|
|
38
|
+
// fixes https://github.com/facebook/docusaurus/issues/8918
|
|
39
|
+
if (!hiddenSidebar && prefersReducedMotion()) {
|
|
40
|
+
setHiddenSidebar(true);
|
|
41
|
+
}
|
|
37
42
|
setHiddenSidebarContainer((value) => !value);
|
|
38
43
|
}, [setHiddenSidebarContainer, hiddenSidebar]);
|
|
39
44
|
return (
|
|
@@ -14,7 +14,7 @@ export default function DocPaginator(props) {
|
|
|
14
14
|
className="pagination-nav docusaurus-mt-lg"
|
|
15
15
|
aria-label={translate({
|
|
16
16
|
id: 'theme.docs.paginator.navAriaLabel',
|
|
17
|
-
message: 'Docs pages
|
|
17
|
+
message: 'Docs pages',
|
|
18
18
|
description: 'The ARIA label for the docs pagination',
|
|
19
19
|
})}>
|
|
20
20
|
{previous && (
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import Translate from '@docusaurus/Translate';
|
|
9
|
+
import {
|
|
10
|
+
ErrorBoundaryError,
|
|
11
|
+
ErrorBoundaryTryAgainButton,
|
|
12
|
+
} from '@docusaurus/theme-common';
|
|
9
13
|
export default function ErrorPageContent({error, tryAgain}) {
|
|
10
14
|
return (
|
|
11
15
|
<main className="container margin-vert--xl">
|
|
@@ -18,15 +22,15 @@ export default function ErrorPageContent({error, tryAgain}) {
|
|
|
18
22
|
This page crashed.
|
|
19
23
|
</Translate>
|
|
20
24
|
</h1>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
<div className="margin-vert--lg">
|
|
26
|
+
<ErrorBoundaryTryAgainButton
|
|
27
|
+
onClick={tryAgain}
|
|
28
|
+
className="button button--primary shadow--lw"
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
<hr />
|
|
32
|
+
<div className="margin-vert--md">
|
|
33
|
+
<ErrorBoundaryError error={error} />
|
|
30
34
|
</div>
|
|
31
35
|
</div>
|
|
32
36
|
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/// <reference types="react" />
|
|
8
|
+
import type { Props } from '@theme/Icon/Copy';
|
|
9
|
+
export default function IconCopy(props: Props): JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export default function IconCopy(props) {
|
|
9
|
+
return (
|
|
10
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
fill="currentColor"
|
|
13
|
+
d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/// <reference types="react" />
|
|
8
|
+
import type { Props } from '@theme/Icon/Success';
|
|
9
|
+
export default function IconSuccess(props: Props): JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export default function IconSuccess(props) {
|
|
9
|
+
return (
|
|
10
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
fill="currentColor"
|
|
13
|
+
d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/// <reference types="react" />
|
|
8
|
+
import type { Props } from '@theme/Icon/WordWrap';
|
|
9
|
+
export default function IconWordWrap(props: Props): JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export default function IconWordWrap(props) {
|
|
9
|
+
return (
|
|
10
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
fill="currentColor"
|
|
13
|
+
d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
|
|
9
9
|
import ColorModeToggle from '@theme/ColorModeToggle';
|
|
10
|
+
import styles from './styles.module.css';
|
|
10
11
|
export default function NavbarColorModeToggle({className}) {
|
|
12
|
+
const navbarStyle = useThemeConfig().navbar.style;
|
|
11
13
|
const disabled = useThemeConfig().colorMode.disableSwitch;
|
|
12
14
|
const {colorMode, setColorMode} = useColorMode();
|
|
13
15
|
if (disabled) {
|
|
@@ -16,6 +18,9 @@ export default function NavbarColorModeToggle({className}) {
|
|
|
16
18
|
return (
|
|
17
19
|
<ColorModeToggle
|
|
18
20
|
className={className}
|
|
21
|
+
buttonClassName={
|
|
22
|
+
navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
|
|
23
|
+
}
|
|
19
24
|
value={colorMode}
|
|
20
25
|
onChange={setColorMode}
|
|
21
26
|
/>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
.darkNavbarColorModeToggle:hover {
|
|
9
|
+
background: var(--ifm-color-gray-800);
|
|
10
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import {useThemeConfig} from '@docusaurus/theme-common';
|
|
8
|
+
import {useThemeConfig, ErrorCauseBoundary} from '@docusaurus/theme-common';
|
|
9
9
|
import {
|
|
10
10
|
splitNavbarItems,
|
|
11
11
|
useNavbarMobileSidebar,
|
|
@@ -25,7 +25,18 @@ function NavbarItems({items}) {
|
|
|
25
25
|
return (
|
|
26
26
|
<>
|
|
27
27
|
{items.map((item, i) => (
|
|
28
|
-
<
|
|
28
|
+
<ErrorCauseBoundary
|
|
29
|
+
key={i}
|
|
30
|
+
onError={(error) =>
|
|
31
|
+
new Error(
|
|
32
|
+
`A theme navbar item failed to render.
|
|
33
|
+
Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:
|
|
34
|
+
${JSON.stringify(item, null, 2)}`,
|
|
35
|
+
{cause: error},
|
|
36
|
+
)
|
|
37
|
+
}>
|
|
38
|
+
<NavbarItem {...item} />
|
|
39
|
+
</ErrorCauseBoundary>
|
|
29
40
|
))}
|
|
30
41
|
</>
|
|
31
42
|
);
|
|
@@ -47,9 +47,11 @@ function DropdownNavbarItemDesktop({
|
|
|
47
47
|
};
|
|
48
48
|
document.addEventListener('mousedown', handleClickOutside);
|
|
49
49
|
document.addEventListener('touchstart', handleClickOutside);
|
|
50
|
+
document.addEventListener('focusin', handleClickOutside);
|
|
50
51
|
return () => {
|
|
51
52
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
52
53
|
document.removeEventListener('touchstart', handleClickOutside);
|
|
54
|
+
document.removeEventListener('focusin', handleClickOutside);
|
|
53
55
|
};
|
|
54
56
|
}, [dropdownRef]);
|
|
55
57
|
return (
|
|
@@ -79,22 +81,6 @@ function DropdownNavbarItemDesktop({
|
|
|
79
81
|
{items.map((childItemProps, i) => (
|
|
80
82
|
<NavbarItem
|
|
81
83
|
isDropdownItem
|
|
82
|
-
onKeyDown={(e) => {
|
|
83
|
-
if (i === items.length - 1 && e.key === 'Tab') {
|
|
84
|
-
e.preventDefault();
|
|
85
|
-
setShowDropdown(false);
|
|
86
|
-
const nextNavbarItem = dropdownRef.current.nextElementSibling;
|
|
87
|
-
if (nextNavbarItem) {
|
|
88
|
-
const targetItem =
|
|
89
|
-
nextNavbarItem instanceof HTMLAnchorElement
|
|
90
|
-
? nextNavbarItem
|
|
91
|
-
: // Next item is another dropdown; focus on the inner
|
|
92
|
-
// anchor element instead so there's outline
|
|
93
|
-
nextNavbarItem.querySelector('a');
|
|
94
|
-
targetItem.focus();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}}
|
|
98
84
|
activeClassName="dropdown__link--active"
|
|
99
85
|
{...childItemProps}
|
|
100
86
|
key={i}
|
package/lib/theme/Tabs/index.js
CHANGED
|
@@ -79,10 +79,11 @@ function TabList({className, block, selectedValue, selectValue, tabValues}) {
|
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
81
|
function TabContent({lazy, children, selectedValue}) {
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
const childTabs = (Array.isArray(children) ? children : [children]).filter(
|
|
83
|
+
Boolean,
|
|
84
|
+
);
|
|
84
85
|
if (lazy) {
|
|
85
|
-
const selectedTabItem =
|
|
86
|
+
const selectedTabItem = childTabs.find(
|
|
86
87
|
(tabItem) => tabItem.props.value === selectedValue,
|
|
87
88
|
);
|
|
88
89
|
if (!selectedTabItem) {
|
|
@@ -93,7 +94,7 @@ function TabContent({lazy, children, selectedValue}) {
|
|
|
93
94
|
}
|
|
94
95
|
return (
|
|
95
96
|
<div className="margin-top--md">
|
|
96
|
-
{
|
|
97
|
+
{childTabs.map((tabItem, i) =>
|
|
97
98
|
cloneElement(tabItem, {
|
|
98
99
|
key: i,
|
|
99
100
|
hidden: tabItem.props.value !== selectedValue,
|
package/lib/translations.js
CHANGED
|
@@ -32,15 +32,34 @@ function getNavbarTranslationFile(navbar) {
|
|
|
32
32
|
const titleTranslations = navbar.title
|
|
33
33
|
? { title: { message: navbar.title, description: 'The title in the navbar' } }
|
|
34
34
|
: {};
|
|
35
|
-
|
|
35
|
+
const logoAlt = navbar.logo?.alt
|
|
36
|
+
? {
|
|
37
|
+
'logo.alt': {
|
|
38
|
+
message: navbar.logo.alt,
|
|
39
|
+
description: 'The alt text of navbar logo',
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
: {};
|
|
43
|
+
return (0, utils_1.mergeTranslations)([
|
|
44
|
+
titleTranslations,
|
|
45
|
+
logoAlt,
|
|
46
|
+
navbarItemsTranslations,
|
|
47
|
+
]);
|
|
36
48
|
}
|
|
37
49
|
function translateNavbar(navbar, navbarTranslations) {
|
|
38
50
|
if (!navbarTranslations) {
|
|
39
51
|
return navbar;
|
|
40
52
|
}
|
|
53
|
+
const logo = navbar.logo
|
|
54
|
+
? {
|
|
55
|
+
...navbar.logo,
|
|
56
|
+
alt: navbarTranslations[`logo.alt`]?.message ?? navbar.logo?.alt,
|
|
57
|
+
}
|
|
58
|
+
: undefined;
|
|
41
59
|
return {
|
|
42
60
|
...navbar,
|
|
43
61
|
title: navbarTranslations.title?.message ?? navbar.title,
|
|
62
|
+
logo,
|
|
44
63
|
// TODO handle properly all the navbar item types here!
|
|
45
64
|
items: navbar.items.map((item) => {
|
|
46
65
|
const subItems = item.items?.map((subItem) => ({
|
|
@@ -86,7 +105,20 @@ function getFooterTranslationFile(footer) {
|
|
|
86
105
|
},
|
|
87
106
|
}
|
|
88
107
|
: {};
|
|
89
|
-
|
|
108
|
+
const logoAlt = footer.logo?.alt
|
|
109
|
+
? {
|
|
110
|
+
'logo.alt': {
|
|
111
|
+
message: footer.logo.alt,
|
|
112
|
+
description: 'The alt text of footer logo',
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
: {};
|
|
116
|
+
return (0, utils_1.mergeTranslations)([
|
|
117
|
+
footerLinkTitles,
|
|
118
|
+
footerLinkLabels,
|
|
119
|
+
copyright,
|
|
120
|
+
logoAlt,
|
|
121
|
+
]);
|
|
90
122
|
}
|
|
91
123
|
function translateFooter(footer, footerTranslations) {
|
|
92
124
|
if (!footerTranslations) {
|
|
@@ -108,10 +140,17 @@ function translateFooter(footer, footerTranslations) {
|
|
|
108
140
|
link.label,
|
|
109
141
|
}));
|
|
110
142
|
const copyright = footerTranslations.copyright?.message ?? footer.copyright;
|
|
143
|
+
const logo = footer.logo
|
|
144
|
+
? {
|
|
145
|
+
...footer.logo,
|
|
146
|
+
alt: footerTranslations[`logo.alt`]?.message ?? footer.logo?.alt,
|
|
147
|
+
}
|
|
148
|
+
: undefined;
|
|
111
149
|
return {
|
|
112
150
|
...footer,
|
|
113
151
|
links,
|
|
114
152
|
copyright,
|
|
153
|
+
logo,
|
|
115
154
|
};
|
|
116
155
|
}
|
|
117
156
|
function getTranslationFiles({ themeConfig, }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/theme-classic",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Classic theme for Docusaurus",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/theme-classic.d.ts",
|
|
@@ -20,22 +20,22 @@
|
|
|
20
20
|
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@docusaurus/core": "2.
|
|
24
|
-
"@docusaurus/mdx-loader": "2.
|
|
25
|
-
"@docusaurus/module-type-aliases": "2.
|
|
26
|
-
"@docusaurus/plugin-content-blog": "2.
|
|
27
|
-
"@docusaurus/plugin-content-docs": "2.
|
|
28
|
-
"@docusaurus/plugin-content-pages": "2.
|
|
29
|
-
"@docusaurus/theme-common": "2.
|
|
30
|
-
"@docusaurus/theme-translations": "2.
|
|
31
|
-
"@docusaurus/types": "2.
|
|
32
|
-
"@docusaurus/utils": "2.
|
|
33
|
-
"@docusaurus/utils-common": "2.
|
|
34
|
-
"@docusaurus/utils-validation": "2.
|
|
23
|
+
"@docusaurus/core": "2.4.1",
|
|
24
|
+
"@docusaurus/mdx-loader": "2.4.1",
|
|
25
|
+
"@docusaurus/module-type-aliases": "2.4.1",
|
|
26
|
+
"@docusaurus/plugin-content-blog": "2.4.1",
|
|
27
|
+
"@docusaurus/plugin-content-docs": "2.4.1",
|
|
28
|
+
"@docusaurus/plugin-content-pages": "2.4.1",
|
|
29
|
+
"@docusaurus/theme-common": "2.4.1",
|
|
30
|
+
"@docusaurus/theme-translations": "2.4.1",
|
|
31
|
+
"@docusaurus/types": "2.4.1",
|
|
32
|
+
"@docusaurus/utils": "2.4.1",
|
|
33
|
+
"@docusaurus/utils-common": "2.4.1",
|
|
34
|
+
"@docusaurus/utils-validation": "2.4.1",
|
|
35
35
|
"@mdx-js/react": "^1.6.22",
|
|
36
36
|
"clsx": "^1.2.1",
|
|
37
37
|
"copy-text-to-clipboard": "^3.0.1",
|
|
38
|
-
"infima": "0.2.0-alpha.
|
|
38
|
+
"infima": "0.2.0-alpha.43",
|
|
39
39
|
"lodash": "^4.17.21",
|
|
40
40
|
"nprogress": "^0.2.0",
|
|
41
41
|
"postcss": "^8.4.14",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=16.14"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "60e657d8ae5a4a9ed1c2d777f9defd882cc12681"
|
|
66
66
|
}
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,8 @@ const ContextReplacementPlugin = requireFromDocusaurusCore(
|
|
|
26
26
|
// Need to be inlined to prevent dark mode FOUC
|
|
27
27
|
// Make sure the key is the same as the one in `/theme/hooks/useTheme.js`
|
|
28
28
|
const ThemeStorageKey = 'theme';
|
|
29
|
+
const ThemeQueryStringKey = 'docusaurus-theme';
|
|
30
|
+
|
|
29
31
|
const noFlashColorMode = ({
|
|
30
32
|
defaultMode,
|
|
31
33
|
respectPrefersColorScheme,
|
|
@@ -39,6 +41,14 @@ const noFlashColorMode = ({
|
|
|
39
41
|
document.documentElement.setAttribute('data-theme', theme);
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
function getQueryStringTheme() {
|
|
45
|
+
var theme = null;
|
|
46
|
+
try {
|
|
47
|
+
theme = new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
|
|
48
|
+
} catch(e) {}
|
|
49
|
+
return theme;
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
function getStoredTheme() {
|
|
43
53
|
var theme = null;
|
|
44
54
|
try {
|
|
@@ -47,9 +57,9 @@ const noFlashColorMode = ({
|
|
|
47
57
|
return theme;
|
|
48
58
|
}
|
|
49
59
|
|
|
50
|
-
var
|
|
51
|
-
if (
|
|
52
|
-
setDataThemeAttribute(
|
|
60
|
+
var initialTheme = getQueryStringTheme() || getStoredTheme();
|
|
61
|
+
if (initialTheme !== null) {
|
|
62
|
+
setDataThemeAttribute(initialTheme);
|
|
53
63
|
} else {
|
|
54
64
|
if (
|
|
55
65
|
respectPrefersColorScheme &&
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
display: flex;
|
|
60
60
|
column-gap: 0.2rem;
|
|
61
61
|
position: absolute;
|
|
62
|
+
/* rtl:ignore */
|
|
62
63
|
right: calc(var(--ifm-pre-padding) / 2);
|
|
63
64
|
top: calc(var(--ifm-pre-padding) / 2);
|
|
64
65
|
}
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
border-radius: var(--ifm-global-radius);
|
|
73
74
|
padding: 0.4rem;
|
|
74
75
|
line-height: 0;
|
|
75
|
-
transition: opacity
|
|
76
|
+
transition: opacity var(--ifm-transition-fast) ease-in-out;
|
|
76
77
|
opacity: 0;
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -11,6 +11,8 @@ import clsx from 'clsx';
|
|
|
11
11
|
import copy from 'copy-text-to-clipboard';
|
|
12
12
|
import {translate} from '@docusaurus/Translate';
|
|
13
13
|
import type {Props} from '@theme/CodeBlock/CopyButton';
|
|
14
|
+
import IconCopy from '@theme/Icon/Copy';
|
|
15
|
+
import IconSuccess from '@theme/Icon/Success';
|
|
14
16
|
|
|
15
17
|
import styles from './styles.module.css';
|
|
16
18
|
|
|
@@ -56,12 +58,8 @@ export default function CopyButton({code, className}: Props): JSX.Element {
|
|
|
56
58
|
)}
|
|
57
59
|
onClick={handleCopyCode}>
|
|
58
60
|
<span className={styles.copyButtonIcons} aria-hidden="true">
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
</svg>
|
|
62
|
-
<svg className={styles.copyButtonSuccessIcon} viewBox="0 0 24 24">
|
|
63
|
-
<path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" />
|
|
64
|
-
</svg>
|
|
61
|
+
<IconCopy className={styles.copyButtonIcon} />
|
|
62
|
+
<IconSuccess className={styles.copyButtonSuccessIcon} />
|
|
65
63
|
</span>
|
|
66
64
|
</button>
|
|
67
65
|
);
|
|
@@ -9,6 +9,7 @@ import React from 'react';
|
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
import {translate} from '@docusaurus/Translate';
|
|
11
11
|
import type {Props} from '@theme/CodeBlock/WordWrapButton';
|
|
12
|
+
import IconWordWrap from '@theme/Icon/WordWrap';
|
|
12
13
|
|
|
13
14
|
import styles from './styles.module.css';
|
|
14
15
|
|
|
@@ -35,15 +36,7 @@ export default function WordWrapButton({
|
|
|
35
36
|
)}
|
|
36
37
|
aria-label={title}
|
|
37
38
|
title={title}>
|
|
38
|
-
<
|
|
39
|
-
className={styles.wordWrapButtonIcon}
|
|
40
|
-
viewBox="0 0 24 24"
|
|
41
|
-
aria-hidden="true">
|
|
42
|
-
<path
|
|
43
|
-
fill="currentColor"
|
|
44
|
-
d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"
|
|
45
|
-
/>
|
|
46
|
-
</svg>
|
|
39
|
+
<IconWordWrap className={styles.wordWrapButtonIcon} aria-hidden="true" />
|
|
47
40
|
</button>
|
|
48
41
|
);
|
|
49
42
|
}
|
|
@@ -15,7 +15,12 @@ import type {Props} from '@theme/ColorModeToggle';
|
|
|
15
15
|
|
|
16
16
|
import styles from './styles.module.css';
|
|
17
17
|
|
|
18
|
-
function ColorModeToggle({
|
|
18
|
+
function ColorModeToggle({
|
|
19
|
+
className,
|
|
20
|
+
buttonClassName,
|
|
21
|
+
value,
|
|
22
|
+
onChange,
|
|
23
|
+
}: Props): JSX.Element {
|
|
19
24
|
const isBrowser = useIsBrowser();
|
|
20
25
|
|
|
21
26
|
const title = translate(
|
|
@@ -47,6 +52,7 @@ function ColorModeToggle({className, value, onChange}: Props): JSX.Element {
|
|
|
47
52
|
'clean-btn',
|
|
48
53
|
styles.toggleButton,
|
|
49
54
|
!isBrowser && styles.toggleButtonDisabled,
|
|
55
|
+
buttonClassName,
|
|
50
56
|
)}
|
|
51
57
|
type="button"
|
|
52
58
|
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
|
|
@@ -82,15 +82,18 @@ function CardCategory({
|
|
|
82
82
|
href={href}
|
|
83
83
|
icon="🗃️"
|
|
84
84
|
title={item.label}
|
|
85
|
-
description={
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
description={
|
|
86
|
+
item.description ??
|
|
87
|
+
translate(
|
|
88
|
+
{
|
|
89
|
+
message: '{count} items',
|
|
90
|
+
id: 'theme.docs.DocCard.categoryDescription',
|
|
91
|
+
description:
|
|
92
|
+
'The default description for a category card in the generated index about how many items this category includes',
|
|
93
|
+
},
|
|
94
|
+
{count: item.items.length},
|
|
95
|
+
)
|
|
96
|
+
}
|
|
94
97
|
/>
|
|
95
98
|
);
|
|
96
99
|
}
|
|
@@ -103,7 +106,7 @@ function CardLink({item}: {item: PropSidebarItemLink}): JSX.Element {
|
|
|
103
106
|
href={item.href}
|
|
104
107
|
icon={icon}
|
|
105
108
|
title={item.label}
|
|
106
|
-
description={doc?.description}
|
|
109
|
+
description={item.description ?? doc?.description}
|
|
107
110
|
/>
|
|
108
111
|
);
|
|
109
112
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import React, {type ReactNode, useState, useCallback} from 'react';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
|
-
import {ThemeClassNames} from '@docusaurus/theme-common';
|
|
10
|
+
import {prefersReducedMotion, ThemeClassNames} from '@docusaurus/theme-common';
|
|
11
11
|
import {useDocsSidebar} from '@docusaurus/theme-common/internal';
|
|
12
12
|
import {useLocation} from '@docusaurus/router';
|
|
13
13
|
import DocSidebar from '@theme/DocSidebar';
|
|
@@ -40,6 +40,11 @@ export default function DocPageLayoutSidebar({
|
|
|
40
40
|
if (hiddenSidebar) {
|
|
41
41
|
setHiddenSidebar(false);
|
|
42
42
|
}
|
|
43
|
+
// onTransitionEnd won't fire when sidebar animation is disabled
|
|
44
|
+
// fixes https://github.com/facebook/docusaurus/issues/8918
|
|
45
|
+
if (!hiddenSidebar && prefersReducedMotion()) {
|
|
46
|
+
setHiddenSidebar(true);
|
|
47
|
+
}
|
|
43
48
|
setHiddenSidebarContainer((value) => !value);
|
|
44
49
|
}, [setHiddenSidebarContainer, hiddenSidebar]);
|
|
45
50
|
|
|
@@ -17,7 +17,7 @@ export default function DocPaginator(props: Props): JSX.Element {
|
|
|
17
17
|
className="pagination-nav docusaurus-mt-lg"
|
|
18
18
|
aria-label={translate({
|
|
19
19
|
id: 'theme.docs.paginator.navAriaLabel',
|
|
20
|
-
message: 'Docs pages
|
|
20
|
+
message: 'Docs pages',
|
|
21
21
|
description: 'The ARIA label for the docs pagination',
|
|
22
22
|
})}>
|
|
23
23
|
{previous && (
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import Translate from '@docusaurus/Translate';
|
|
10
|
+
import {
|
|
11
|
+
ErrorBoundaryError,
|
|
12
|
+
ErrorBoundaryTryAgainButton,
|
|
13
|
+
} from '@docusaurus/theme-common';
|
|
10
14
|
import type {Props} from '@theme/Error';
|
|
11
15
|
|
|
12
16
|
export default function ErrorPageContent({
|
|
@@ -24,15 +28,15 @@ export default function ErrorPageContent({
|
|
|
24
28
|
This page crashed.
|
|
25
29
|
</Translate>
|
|
26
30
|
</h1>
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
<div className="margin-vert--lg">
|
|
32
|
+
<ErrorBoundaryTryAgainButton
|
|
33
|
+
onClick={tryAgain}
|
|
34
|
+
className="button button--primary shadow--lw"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
<hr />
|
|
38
|
+
<div className="margin-vert--md">
|
|
39
|
+
<ErrorBoundaryError error={error} />
|
|
36
40
|
</div>
|
|
37
41
|
</div>
|
|
38
42
|
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import type {Props} from '@theme/Icon/Copy';
|
|
10
|
+
|
|
11
|
+
export default function IconCopy(props: Props): JSX.Element {
|
|
12
|
+
return (
|
|
13
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
14
|
+
<path
|
|
15
|
+
fill="currentColor"
|
|
16
|
+
d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import type {Props} from '@theme/Icon/Success';
|
|
10
|
+
|
|
11
|
+
export default function IconSuccess(props: Props): JSX.Element {
|
|
12
|
+
return (
|
|
13
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
14
|
+
<path
|
|
15
|
+
fill="currentColor"
|
|
16
|
+
d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import type {Props} from '@theme/Icon/WordWrap';
|
|
10
|
+
|
|
11
|
+
export default function IconWordWrap(props: Props): JSX.Element {
|
|
12
|
+
return (
|
|
13
|
+
<svg viewBox="0 0 24 24" {...props}>
|
|
14
|
+
<path
|
|
15
|
+
fill="currentColor"
|
|
16
|
+
d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -9,10 +9,12 @@ import React from 'react';
|
|
|
9
9
|
import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
|
|
10
10
|
import ColorModeToggle from '@theme/ColorModeToggle';
|
|
11
11
|
import type {Props} from '@theme/Navbar/ColorModeToggle';
|
|
12
|
+
import styles from './styles.module.css';
|
|
12
13
|
|
|
13
14
|
export default function NavbarColorModeToggle({
|
|
14
15
|
className,
|
|
15
16
|
}: Props): JSX.Element | null {
|
|
17
|
+
const navbarStyle = useThemeConfig().navbar.style;
|
|
16
18
|
const disabled = useThemeConfig().colorMode.disableSwitch;
|
|
17
19
|
const {colorMode, setColorMode} = useColorMode();
|
|
18
20
|
|
|
@@ -23,6 +25,9 @@ export default function NavbarColorModeToggle({
|
|
|
23
25
|
return (
|
|
24
26
|
<ColorModeToggle
|
|
25
27
|
className={className}
|
|
28
|
+
buttonClassName={
|
|
29
|
+
navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
|
|
30
|
+
}
|
|
26
31
|
value={colorMode}
|
|
27
32
|
onChange={setColorMode}
|
|
28
33
|
/>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
.darkNavbarColorModeToggle:hover {
|
|
9
|
+
background: var(--ifm-color-gray-800);
|
|
10
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React, {type ReactNode} from 'react';
|
|
9
|
-
import {useThemeConfig} from '@docusaurus/theme-common';
|
|
9
|
+
import {useThemeConfig, ErrorCauseBoundary} from '@docusaurus/theme-common';
|
|
10
10
|
import {
|
|
11
11
|
splitNavbarItems,
|
|
12
12
|
useNavbarMobileSidebar,
|
|
@@ -29,7 +29,18 @@ function NavbarItems({items}: {items: NavbarItemConfig[]}): JSX.Element {
|
|
|
29
29
|
return (
|
|
30
30
|
<>
|
|
31
31
|
{items.map((item, i) => (
|
|
32
|
-
<
|
|
32
|
+
<ErrorCauseBoundary
|
|
33
|
+
key={i}
|
|
34
|
+
onError={(error) =>
|
|
35
|
+
new Error(
|
|
36
|
+
`A theme navbar item failed to render.
|
|
37
|
+
Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:
|
|
38
|
+
${JSON.stringify(item, null, 2)}`,
|
|
39
|
+
{cause: error},
|
|
40
|
+
)
|
|
41
|
+
}>
|
|
42
|
+
<NavbarItem {...item} />
|
|
43
|
+
</ErrorCauseBoundary>
|
|
33
44
|
))}
|
|
34
45
|
</>
|
|
35
46
|
);
|
|
@@ -54,7 +54,9 @@ function DropdownNavbarItemDesktop({
|
|
|
54
54
|
const [showDropdown, setShowDropdown] = useState(false);
|
|
55
55
|
|
|
56
56
|
useEffect(() => {
|
|
57
|
-
const handleClickOutside = (
|
|
57
|
+
const handleClickOutside = (
|
|
58
|
+
event: MouseEvent | TouchEvent | FocusEvent,
|
|
59
|
+
) => {
|
|
58
60
|
if (
|
|
59
61
|
!dropdownRef.current ||
|
|
60
62
|
dropdownRef.current.contains(event.target as Node)
|
|
@@ -66,10 +68,12 @@ function DropdownNavbarItemDesktop({
|
|
|
66
68
|
|
|
67
69
|
document.addEventListener('mousedown', handleClickOutside);
|
|
68
70
|
document.addEventListener('touchstart', handleClickOutside);
|
|
71
|
+
document.addEventListener('focusin', handleClickOutside);
|
|
69
72
|
|
|
70
73
|
return () => {
|
|
71
74
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
72
75
|
document.removeEventListener('touchstart', handleClickOutside);
|
|
76
|
+
document.removeEventListener('focusin', handleClickOutside);
|
|
73
77
|
};
|
|
74
78
|
}, [dropdownRef]);
|
|
75
79
|
|
|
@@ -100,22 +104,6 @@ function DropdownNavbarItemDesktop({
|
|
|
100
104
|
{items.map((childItemProps, i) => (
|
|
101
105
|
<NavbarItem
|
|
102
106
|
isDropdownItem
|
|
103
|
-
onKeyDown={(e) => {
|
|
104
|
-
if (i === items.length - 1 && e.key === 'Tab') {
|
|
105
|
-
e.preventDefault();
|
|
106
|
-
setShowDropdown(false);
|
|
107
|
-
const nextNavbarItem = dropdownRef.current!.nextElementSibling;
|
|
108
|
-
if (nextNavbarItem) {
|
|
109
|
-
const targetItem =
|
|
110
|
-
nextNavbarItem instanceof HTMLAnchorElement
|
|
111
|
-
? nextNavbarItem
|
|
112
|
-
: // Next item is another dropdown; focus on the inner
|
|
113
|
-
// anchor element instead so there's outline
|
|
114
|
-
nextNavbarItem.querySelector('a')!;
|
|
115
|
-
targetItem.focus();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}}
|
|
119
107
|
activeClassName="dropdown__link--active"
|
|
120
108
|
{...childItemProps}
|
|
121
109
|
key={i}
|
package/src/theme/Tabs/index.tsx
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React, {cloneElement} from 'react';
|
|
8
|
+
import React, {cloneElement, type ReactElement} from 'react';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
import {
|
|
11
11
|
useScrollPositionBlocker,
|
|
12
12
|
useTabs,
|
|
13
|
+
type TabItemProps,
|
|
13
14
|
} from '@docusaurus/theme-common/internal';
|
|
14
15
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
|
15
16
|
import type {Props} from '@theme/Tabs';
|
|
@@ -109,10 +110,11 @@ function TabContent({
|
|
|
109
110
|
children,
|
|
110
111
|
selectedValue,
|
|
111
112
|
}: Props & ReturnType<typeof useTabs>) {
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
const childTabs = (Array.isArray(children) ? children : [children]).filter(
|
|
114
|
+
Boolean,
|
|
115
|
+
) as ReactElement<TabItemProps>[];
|
|
114
116
|
if (lazy) {
|
|
115
|
-
const selectedTabItem =
|
|
117
|
+
const selectedTabItem = childTabs.find(
|
|
116
118
|
(tabItem) => tabItem.props.value === selectedValue,
|
|
117
119
|
);
|
|
118
120
|
if (!selectedTabItem) {
|
|
@@ -123,7 +125,7 @@ function TabContent({
|
|
|
123
125
|
}
|
|
124
126
|
return (
|
|
125
127
|
<div className="margin-top--md">
|
|
126
|
-
{
|
|
128
|
+
{childTabs.map((tabItem, i) =>
|
|
127
129
|
cloneElement(tabItem, {
|
|
128
130
|
key: i,
|
|
129
131
|
hidden: tabItem.props.value !== selectedValue,
|
package/src/theme-classic.d.ts
CHANGED
|
@@ -1243,6 +1243,7 @@ declare module '@theme/ColorModeToggle' {
|
|
|
1243
1243
|
|
|
1244
1244
|
export interface Props {
|
|
1245
1245
|
readonly className?: string;
|
|
1246
|
+
readonly buttonClassName?: string;
|
|
1246
1247
|
readonly value: ColorMode;
|
|
1247
1248
|
/**
|
|
1248
1249
|
* The parameter represents the "to-be" value. For example, if currently in
|
|
@@ -1321,6 +1322,14 @@ declare module '@theme/Icon/Close' {
|
|
|
1321
1322
|
export default function IconClose(props: Props): JSX.Element;
|
|
1322
1323
|
}
|
|
1323
1324
|
|
|
1325
|
+
declare module '@theme/Icon/Copy' {
|
|
1326
|
+
import type {ComponentProps} from 'react';
|
|
1327
|
+
|
|
1328
|
+
export interface Props extends ComponentProps<'svg'> {}
|
|
1329
|
+
|
|
1330
|
+
export default function IconCopy(props: Props): JSX.Element;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1324
1333
|
declare module '@theme/Icon/Language' {
|
|
1325
1334
|
import type {ComponentProps} from 'react';
|
|
1326
1335
|
|
|
@@ -1329,6 +1338,14 @@ declare module '@theme/Icon/Language' {
|
|
|
1329
1338
|
export default function IconLanguage(props: Props): JSX.Element;
|
|
1330
1339
|
}
|
|
1331
1340
|
|
|
1341
|
+
declare module '@theme/Icon/Success' {
|
|
1342
|
+
import type {ComponentProps} from 'react';
|
|
1343
|
+
|
|
1344
|
+
export interface Props extends ComponentProps<'svg'> {}
|
|
1345
|
+
|
|
1346
|
+
export default function IconSuccess(props: Props): JSX.Element;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1332
1349
|
declare module '@theme/Icon/ExternalLink' {
|
|
1333
1350
|
import type {ComponentProps} from 'react';
|
|
1334
1351
|
|
|
@@ -1337,6 +1354,14 @@ declare module '@theme/Icon/ExternalLink' {
|
|
|
1337
1354
|
export default function IconExternalLink(props: Props): JSX.Element;
|
|
1338
1355
|
}
|
|
1339
1356
|
|
|
1357
|
+
declare module '@theme/Icon/WordWrap' {
|
|
1358
|
+
import type {ComponentProps} from 'react';
|
|
1359
|
+
|
|
1360
|
+
export interface Props extends ComponentProps<'svg'> {}
|
|
1361
|
+
|
|
1362
|
+
export default function IconWordWrap(props: Props): JSX.Element;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1340
1365
|
declare module '@theme/TagsListByLetter' {
|
|
1341
1366
|
import type {TagsListItem} from '@docusaurus/utils';
|
|
1342
1367
|
|
package/src/translations.ts
CHANGED
|
@@ -45,7 +45,20 @@ function getNavbarTranslationFile(navbar: Navbar): TranslationFileContent {
|
|
|
45
45
|
? {title: {message: navbar.title, description: 'The title in the navbar'}}
|
|
46
46
|
: {};
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const logoAlt: TranslationFileContent = navbar.logo?.alt
|
|
49
|
+
? {
|
|
50
|
+
'logo.alt': {
|
|
51
|
+
message: navbar.logo.alt,
|
|
52
|
+
description: 'The alt text of navbar logo',
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
: {};
|
|
56
|
+
|
|
57
|
+
return mergeTranslations([
|
|
58
|
+
titleTranslations,
|
|
59
|
+
logoAlt,
|
|
60
|
+
navbarItemsTranslations,
|
|
61
|
+
]);
|
|
49
62
|
}
|
|
50
63
|
function translateNavbar(
|
|
51
64
|
navbar: Navbar,
|
|
@@ -54,9 +67,18 @@ function translateNavbar(
|
|
|
54
67
|
if (!navbarTranslations) {
|
|
55
68
|
return navbar;
|
|
56
69
|
}
|
|
70
|
+
|
|
71
|
+
const logo = navbar.logo
|
|
72
|
+
? {
|
|
73
|
+
...navbar.logo,
|
|
74
|
+
alt: navbarTranslations[`logo.alt`]?.message ?? navbar.logo?.alt,
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
|
|
57
78
|
return {
|
|
58
79
|
...navbar,
|
|
59
80
|
title: navbarTranslations.title?.message ?? navbar.title,
|
|
81
|
+
logo,
|
|
60
82
|
// TODO handle properly all the navbar item types here!
|
|
61
83
|
items: navbar.items.map((item) => {
|
|
62
84
|
const subItems = item.items?.map((subItem) => ({
|
|
@@ -119,7 +141,21 @@ function getFooterTranslationFile(footer: Footer): TranslationFileContent {
|
|
|
119
141
|
}
|
|
120
142
|
: {};
|
|
121
143
|
|
|
122
|
-
|
|
144
|
+
const logoAlt: TranslationFileContent = footer.logo?.alt
|
|
145
|
+
? {
|
|
146
|
+
'logo.alt': {
|
|
147
|
+
message: footer.logo.alt,
|
|
148
|
+
description: 'The alt text of footer logo',
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {};
|
|
152
|
+
|
|
153
|
+
return mergeTranslations([
|
|
154
|
+
footerLinkTitles,
|
|
155
|
+
footerLinkLabels,
|
|
156
|
+
copyright,
|
|
157
|
+
logoAlt,
|
|
158
|
+
]);
|
|
123
159
|
}
|
|
124
160
|
function translateFooter(
|
|
125
161
|
footer: Footer,
|
|
@@ -149,10 +185,18 @@ function translateFooter(
|
|
|
149
185
|
|
|
150
186
|
const copyright = footerTranslations.copyright?.message ?? footer.copyright;
|
|
151
187
|
|
|
188
|
+
const logo = footer.logo
|
|
189
|
+
? {
|
|
190
|
+
...footer.logo,
|
|
191
|
+
alt: footerTranslations[`logo.alt`]?.message ?? footer.logo?.alt,
|
|
192
|
+
}
|
|
193
|
+
: undefined;
|
|
194
|
+
|
|
152
195
|
return {
|
|
153
196
|
...footer,
|
|
154
197
|
links,
|
|
155
198
|
copyright,
|
|
199
|
+
logo,
|
|
156
200
|
};
|
|
157
201
|
}
|
|
158
202
|
|