@docusaurus/theme-classic 2.3.1 → 2.4.0
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/styles.module.css +1 -1
- 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/styles.module.css +1 -0
- package/lib/theme/ErrorPageContent.js +13 -9
- 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/styles.module.css +1 -1
- package/src/theme/ColorModeToggle/index.tsx +7 -1
- package/src/theme/DocCard/index.tsx +13 -10
- package/src/theme/DocPage/Layout/styles.module.css +1 -0
- package/src/theme/ErrorPageContent.tsx +13 -9
- 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 +1 -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
|
|
|
@@ -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,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>
|
|
@@ -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.0",
|
|
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.0",
|
|
24
|
+
"@docusaurus/mdx-loader": "2.4.0",
|
|
25
|
+
"@docusaurus/module-type-aliases": "2.4.0",
|
|
26
|
+
"@docusaurus/plugin-content-blog": "2.4.0",
|
|
27
|
+
"@docusaurus/plugin-content-docs": "2.4.0",
|
|
28
|
+
"@docusaurus/plugin-content-pages": "2.4.0",
|
|
29
|
+
"@docusaurus/theme-common": "2.4.0",
|
|
30
|
+
"@docusaurus/theme-translations": "2.4.0",
|
|
31
|
+
"@docusaurus/types": "2.4.0",
|
|
32
|
+
"@docusaurus/utils": "2.4.0",
|
|
33
|
+
"@docusaurus/utils-common": "2.4.0",
|
|
34
|
+
"@docusaurus/utils-validation": "2.4.0",
|
|
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": "898b85ef134cc43bf3b1209aad0ca8cdcfb214c5"
|
|
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
|
|
|
@@ -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,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>
|
|
@@ -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
|
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
|
|