@docusaurus/theme-classic 0.0.0-4298 → 0.0.0-4307
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/theme-classic.d.ts +13 -4
- package/lib/translations.js +13 -4
- package/lib/validateThemeConfig.js +5 -3
- package/lib-next/theme/DocPaginator/index.js +4 -28
- package/lib-next/theme/DocPaginatorNavLink/index.js +36 -0
- package/lib-next/theme/Footer/index.js +73 -35
- package/package.json +13 -13
- package/src/theme/DocPaginator/index.tsx +6 -30
- package/src/theme/DocPaginatorNavLink/index.tsx +38 -0
- package/src/theme/Footer/index.tsx +83 -37
- package/src/theme-classic.d.ts +13 -4
- package/src/translations.ts +34 -14
- package/src/validateThemeConfig.ts +9 -4
package/lib/theme-classic.d.ts
CHANGED
|
@@ -123,13 +123,22 @@ declare module '@theme/CodeBlock' {
|
|
|
123
123
|
declare module '@theme/DocPaginator' {
|
|
124
124
|
import type {PropNavigation} from '@docusaurus/plugin-content-docs';
|
|
125
125
|
|
|
126
|
-
type PageInfo = {readonly permalink: string; readonly title: string};
|
|
127
|
-
|
|
128
126
|
// May be simpler to provide a {navigation: PropNavigation} prop?
|
|
129
127
|
export interface Props extends PropNavigation {}
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
export default function DocPaginator(props: Props): JSX.Element;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
declare module '@theme/DocPaginatorNavLink' {
|
|
133
|
+
import type {PropNavigationLink} from '@docusaurus/plugin-content-docs';
|
|
134
|
+
|
|
135
|
+
// May be simpler to provide a {navigation: PropNavigation} prop?
|
|
136
|
+
export interface Props {
|
|
137
|
+
navLink: PropNavigationLink;
|
|
138
|
+
next?: boolean;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default function DocPaginatorNavLink(props: Props): JSX.Element;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
declare module '@theme/DocSidebar' {
|
package/lib/translations.js
CHANGED
|
@@ -68,13 +68,16 @@ function translateNavbar(navbar, navbarTranslations) {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function isMultiColumnFooterLinks(links) {
|
|
72
|
+
return links.length > 0 && 'title' in links[0];
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
function getFooterTranslationFile(footer) {
|
|
72
|
-
|
|
73
|
-
const footerLinkTitles = (0, _lodash.chain)(footer.links.filter(link => !!link.title)).keyBy(link => `link.title.${link.title}`).mapValues(link => ({
|
|
76
|
+
const footerLinkTitles = (0, _lodash.chain)(isMultiColumnFooterLinks(footer.links) ? footer.links.filter(link => !!link.title) : []).keyBy(link => `link.title.${link.title}`).mapValues(link => ({
|
|
74
77
|
message: link.title,
|
|
75
78
|
description: `The title of the footer links column with title=${link.title} in the footer`
|
|
76
79
|
})).value();
|
|
77
|
-
const footerLinkLabels = (0, _lodash.chain)(footer.links.flatMap(link => link.items).filter(link => !!link.label)).keyBy(linkItem => `link.item.label.${linkItem.label}`).mapValues(linkItem => {
|
|
80
|
+
const footerLinkLabels = (0, _lodash.chain)(isMultiColumnFooterLinks(footer.links) ? footer.links.flatMap(link => link.items).filter(link => !!link.label) : footer.links.filter(link => !!link.label)).keyBy(linkItem => `link.item.label.${linkItem.label}`).mapValues(linkItem => {
|
|
78
81
|
var _linkItem$to;
|
|
79
82
|
|
|
80
83
|
return {
|
|
@@ -94,7 +97,7 @@ function getFooterTranslationFile(footer) {
|
|
|
94
97
|
function translateFooter(footer, footerTranslations) {
|
|
95
98
|
var _footerTranslations$c, _footerTranslations$c2;
|
|
96
99
|
|
|
97
|
-
const links = footer.links.map(link => {
|
|
100
|
+
const links = isMultiColumnFooterLinks(footer.links) ? footer.links.map(link => {
|
|
98
101
|
var _footerTranslations$$, _footerTranslations$;
|
|
99
102
|
|
|
100
103
|
return { ...link,
|
|
@@ -107,6 +110,12 @@ function translateFooter(footer, footerTranslations) {
|
|
|
107
110
|
};
|
|
108
111
|
})
|
|
109
112
|
};
|
|
113
|
+
}) : footer.links.map(link => {
|
|
114
|
+
var _footerTranslations$$3, _footerTranslations$3;
|
|
115
|
+
|
|
116
|
+
return { ...link,
|
|
117
|
+
label: (_footerTranslations$$3 = (_footerTranslations$3 = footerTranslations[`link.item.label.${link.label}`]) === null || _footerTranslations$3 === void 0 ? void 0 : _footerTranslations$3.message) !== null && _footerTranslations$$3 !== void 0 ? _footerTranslations$$3 : link.label
|
|
118
|
+
};
|
|
110
119
|
});
|
|
111
120
|
const copyright = (_footerTranslations$c = (_footerTranslations$c2 = footerTranslations.copyright) === null || _footerTranslations$c2 === void 0 ? void 0 : _footerTranslations$c2.message) !== null && _footerTranslations$c !== void 0 ? _footerTranslations$c : footer.copyright;
|
|
112
121
|
return { ...footer,
|
|
@@ -260,10 +260,12 @@ const ThemeConfigSchema = _utilsValidation.Joi.object({
|
|
|
260
260
|
href: _utilsValidation.Joi.string()
|
|
261
261
|
}),
|
|
262
262
|
copyright: _utilsValidation.Joi.string(),
|
|
263
|
-
links: _utilsValidation.Joi.array().items(_utilsValidation.Joi.object({
|
|
264
|
-
title: _utilsValidation.Joi.string().allow(null),
|
|
263
|
+
links: _utilsValidation.Joi.alternatives(_utilsValidation.Joi.array().items(_utilsValidation.Joi.object({
|
|
264
|
+
title: _utilsValidation.Joi.string().allow(null).default(null),
|
|
265
265
|
items: _utilsValidation.Joi.array().items(FooterLinkItemSchema).default([])
|
|
266
|
-
})).
|
|
266
|
+
})), _utilsValidation.Joi.array().items(FooterLinkItemSchema)).messages({
|
|
267
|
+
'alternatives.match': `The footer must be either simple or multi-column, and not a mix of the two. See: https://docusaurus.io/docs/api/themes/configuration#footer-links`
|
|
268
|
+
}).default([])
|
|
267
269
|
}).optional(),
|
|
268
270
|
prism: _utilsValidation.Joi.object({
|
|
269
271
|
theme: _utilsValidation.Joi.object({
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import {translate} from '@docusaurus/Translate';
|
|
9
|
+
import DocPaginatorNavLink from '@theme/DocPaginatorNavLink';
|
|
10
10
|
|
|
11
11
|
function DocPaginator(props) {
|
|
12
12
|
const {previous, next} = props;
|
|
@@ -19,34 +19,10 @@ function DocPaginator(props) {
|
|
|
19
19
|
description: 'The ARIA label for the docs pagination',
|
|
20
20
|
})}>
|
|
21
21
|
<div className="pagination-nav__item">
|
|
22
|
-
{previous &&
|
|
23
|
-
<Link className="pagination-nav__link" to={previous.permalink}>
|
|
24
|
-
<div className="pagination-nav__sublabel">
|
|
25
|
-
<Translate
|
|
26
|
-
id="theme.docs.paginator.previous"
|
|
27
|
-
description="The label used to navigate to the previous doc">
|
|
28
|
-
Previous
|
|
29
|
-
</Translate>
|
|
30
|
-
</div>
|
|
31
|
-
<div className="pagination-nav__label">
|
|
32
|
-
« {previous.title}
|
|
33
|
-
</div>
|
|
34
|
-
</Link>
|
|
35
|
-
)}
|
|
22
|
+
{previous && <DocPaginatorNavLink navLink={previous} />}
|
|
36
23
|
</div>
|
|
37
24
|
<div className="pagination-nav__item pagination-nav__item--next">
|
|
38
|
-
{next &&
|
|
39
|
-
<Link className="pagination-nav__link" to={next.permalink}>
|
|
40
|
-
<div className="pagination-nav__sublabel">
|
|
41
|
-
<Translate
|
|
42
|
-
id="theme.docs.paginator.next"
|
|
43
|
-
description="The label used to navigate to the next doc">
|
|
44
|
-
Next
|
|
45
|
-
</Translate>
|
|
46
|
-
</div>
|
|
47
|
-
<div className="pagination-nav__label">{next.title} »</div>
|
|
48
|
-
</Link>
|
|
49
|
-
)}
|
|
25
|
+
{next && <DocPaginatorNavLink navLink={next} next />}
|
|
50
26
|
</div>
|
|
51
27
|
</nav>
|
|
52
28
|
);
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
import clsx from 'clsx';
|
|
9
|
+
import Link from '@docusaurus/Link';
|
|
10
|
+
import Translate from '@docusaurus/Translate';
|
|
11
|
+
|
|
12
|
+
function DocPaginatorNavLink(props) {
|
|
13
|
+
const {navLink, next} = props;
|
|
14
|
+
return (
|
|
15
|
+
<Link className={clsx('pagination-nav__link')} to={navLink.permalink}>
|
|
16
|
+
<div className="pagination-nav__sublabel">
|
|
17
|
+
{next ? (
|
|
18
|
+
<Translate
|
|
19
|
+
id="theme.docs.paginator.next"
|
|
20
|
+
description="The label used to navigate to the next doc">
|
|
21
|
+
Next
|
|
22
|
+
</Translate>
|
|
23
|
+
) : (
|
|
24
|
+
<Translate
|
|
25
|
+
id="theme.docs.paginator.previous"
|
|
26
|
+
description="The label used to navigate to the previous doc">
|
|
27
|
+
Previous
|
|
28
|
+
</Translate>
|
|
29
|
+
)}
|
|
30
|
+
</div>
|
|
31
|
+
<div className="pagination-nav__label">{navLink.title}</div>
|
|
32
|
+
</Link>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default DocPaginatorNavLink;
|
|
@@ -54,6 +54,66 @@ function FooterLogo({sources, alt, width, height}) {
|
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function MultiColumnLinks({links}) {
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
{links.map((linkItem, i) => (
|
|
61
|
+
<div key={i} className="col footer__col">
|
|
62
|
+
<div className="footer__title">{linkItem.title}</div>
|
|
63
|
+
<ul className="footer__items">
|
|
64
|
+
{linkItem.items.map((item, key) =>
|
|
65
|
+
item.html ? (
|
|
66
|
+
<li
|
|
67
|
+
key={key}
|
|
68
|
+
className="footer__item" // Developer provided the HTML, so assume it's safe.
|
|
69
|
+
// eslint-disable-next-line react/no-danger
|
|
70
|
+
dangerouslySetInnerHTML={{
|
|
71
|
+
__html: item.html,
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
) : (
|
|
75
|
+
<li key={item.href || item.to} className="footer__item">
|
|
76
|
+
<FooterLink {...item} />
|
|
77
|
+
</li>
|
|
78
|
+
),
|
|
79
|
+
)}
|
|
80
|
+
</ul>
|
|
81
|
+
</div>
|
|
82
|
+
))}
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function SimpleLinks({links}) {
|
|
88
|
+
return (
|
|
89
|
+
<div className="footer__links">
|
|
90
|
+
{links.map((item, key) => (
|
|
91
|
+
<>
|
|
92
|
+
{item.html ? (
|
|
93
|
+
<span
|
|
94
|
+
key={key}
|
|
95
|
+
className="footer__link-item" // Developer provided the HTML, so assume it's safe.
|
|
96
|
+
// eslint-disable-next-line react/no-danger
|
|
97
|
+
dangerouslySetInnerHTML={{
|
|
98
|
+
__html: item.html,
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
) : (
|
|
102
|
+
<FooterLink {...item} />
|
|
103
|
+
)}
|
|
104
|
+
{links.length !== key + 1 && (
|
|
105
|
+
<span className="footer__link-separator">·</span>
|
|
106
|
+
)}
|
|
107
|
+
</>
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isMultiColumnFooterLinks(links) {
|
|
114
|
+
return 'title' in links[0];
|
|
115
|
+
}
|
|
116
|
+
|
|
57
117
|
function Footer() {
|
|
58
118
|
const {footer} = useThemeConfig();
|
|
59
119
|
const {copyright, links = [], logo = {}} = footer || {};
|
|
@@ -71,40 +131,18 @@ function Footer() {
|
|
|
71
131
|
className={clsx('footer', {
|
|
72
132
|
'footer--dark': footer.style === 'dark',
|
|
73
133
|
})}>
|
|
74
|
-
<div className="container">
|
|
75
|
-
{links &&
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
{linkItem.items.map((item, key) =>
|
|
87
|
-
item.html ? (
|
|
88
|
-
<li
|
|
89
|
-
key={key}
|
|
90
|
-
className="footer__item" // Developer provided the HTML, so assume it's safe.
|
|
91
|
-
// eslint-disable-next-line react/no-danger
|
|
92
|
-
dangerouslySetInnerHTML={{
|
|
93
|
-
__html: item.html,
|
|
94
|
-
}}
|
|
95
|
-
/>
|
|
96
|
-
) : (
|
|
97
|
-
<li key={item.href || item.to} className="footer__item">
|
|
98
|
-
<FooterLink {...item} />
|
|
99
|
-
</li>
|
|
100
|
-
),
|
|
101
|
-
)}
|
|
102
|
-
</ul>
|
|
103
|
-
) : null}
|
|
104
|
-
</div>
|
|
105
|
-
))}
|
|
106
|
-
</div>
|
|
107
|
-
)}
|
|
134
|
+
<div className="container container-fluid">
|
|
135
|
+
{links &&
|
|
136
|
+
links.length > 0 &&
|
|
137
|
+
(isMultiColumnFooterLinks(links) ? (
|
|
138
|
+
<div className="row footer__links">
|
|
139
|
+
<MultiColumnLinks links={links} />
|
|
140
|
+
</div>
|
|
141
|
+
) : (
|
|
142
|
+
<div className="footer__links text--center">
|
|
143
|
+
<SimpleLinks links={links} />
|
|
144
|
+
</div>
|
|
145
|
+
))}
|
|
108
146
|
{(logo || copyright) && (
|
|
109
147
|
<div className="footer__bottom text--center">
|
|
110
148
|
{logo && (logo.src || logo.srcDark) && (
|
|
@@ -139,4 +177,4 @@ function Footer() {
|
|
|
139
177
|
);
|
|
140
178
|
}
|
|
141
179
|
|
|
142
|
-
export default Footer;
|
|
180
|
+
export default React.memo(Footer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/theme-classic",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-4307",
|
|
4
4
|
"description": "Classic theme for Docusaurus",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/theme-classic.d.ts",
|
|
@@ -23,20 +23,20 @@
|
|
|
23
23
|
"update-code-translations": "node -e 'require(\"./update-code-translations.js\").run()'"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@docusaurus/core": "0.0.0-
|
|
27
|
-
"@docusaurus/plugin-content-blog": "0.0.0-
|
|
28
|
-
"@docusaurus/plugin-content-docs": "0.0.0-
|
|
29
|
-
"@docusaurus/plugin-content-pages": "0.0.0-
|
|
30
|
-
"@docusaurus/theme-common": "0.0.0-
|
|
31
|
-
"@docusaurus/theme-translations": "0.0.0-
|
|
32
|
-
"@docusaurus/utils": "0.0.0-
|
|
33
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
26
|
+
"@docusaurus/core": "0.0.0-4307",
|
|
27
|
+
"@docusaurus/plugin-content-blog": "0.0.0-4307",
|
|
28
|
+
"@docusaurus/plugin-content-docs": "0.0.0-4307",
|
|
29
|
+
"@docusaurus/plugin-content-pages": "0.0.0-4307",
|
|
30
|
+
"@docusaurus/theme-common": "0.0.0-4307",
|
|
31
|
+
"@docusaurus/theme-translations": "0.0.0-4307",
|
|
32
|
+
"@docusaurus/utils": "0.0.0-4307",
|
|
33
|
+
"@docusaurus/utils-validation": "0.0.0-4307",
|
|
34
34
|
"@mdx-js/mdx": "^1.6.21",
|
|
35
35
|
"@mdx-js/react": "^1.6.21",
|
|
36
36
|
"clsx": "^1.1.1",
|
|
37
37
|
"copy-text-to-clipboard": "^3.0.1",
|
|
38
38
|
"globby": "^11.0.2",
|
|
39
|
-
"infima": "0.2.0-alpha.
|
|
39
|
+
"infima": "0.2.0-alpha.37",
|
|
40
40
|
"lodash": "^4.17.20",
|
|
41
41
|
"postcss": "^8.3.7",
|
|
42
42
|
"prism-react-renderer": "^1.2.1",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"rtlcss": "^3.3.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@docusaurus/module-type-aliases": "0.0.0-
|
|
49
|
-
"@docusaurus/types": "0.0.0-
|
|
48
|
+
"@docusaurus/module-type-aliases": "0.0.0-4307",
|
|
49
|
+
"@docusaurus/types": "0.0.0-4307",
|
|
50
50
|
"@types/mdx-js__react": "^1.5.4",
|
|
51
51
|
"@types/parse-numeric-range": "^0.0.1",
|
|
52
52
|
"@types/rtlcss": "^3.1.1",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=14"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "d7b9a0f0eb96f5f853500c3810f7f4df4054b910"
|
|
65
65
|
}
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import type {
|
|
9
|
+
import {translate} from '@docusaurus/Translate';
|
|
10
|
+
import DocPaginatorNavLink from '@theme/DocPaginatorNavLink';
|
|
11
|
+
import type {Props} from '@theme/DocPaginator';
|
|
12
12
|
|
|
13
|
-
function DocPaginator(props:
|
|
13
|
+
function DocPaginator(props: Props): JSX.Element {
|
|
14
14
|
const {previous, next} = props;
|
|
15
15
|
|
|
16
16
|
return (
|
|
@@ -22,34 +22,10 @@ function DocPaginator(props: PropNavigation): JSX.Element {
|
|
|
22
22
|
description: 'The ARIA label for the docs pagination',
|
|
23
23
|
})}>
|
|
24
24
|
<div className="pagination-nav__item">
|
|
25
|
-
{previous &&
|
|
26
|
-
<Link className="pagination-nav__link" to={previous.permalink}>
|
|
27
|
-
<div className="pagination-nav__sublabel">
|
|
28
|
-
<Translate
|
|
29
|
-
id="theme.docs.paginator.previous"
|
|
30
|
-
description="The label used to navigate to the previous doc">
|
|
31
|
-
Previous
|
|
32
|
-
</Translate>
|
|
33
|
-
</div>
|
|
34
|
-
<div className="pagination-nav__label">
|
|
35
|
-
« {previous.title}
|
|
36
|
-
</div>
|
|
37
|
-
</Link>
|
|
38
|
-
)}
|
|
25
|
+
{previous && <DocPaginatorNavLink navLink={previous} />}
|
|
39
26
|
</div>
|
|
40
27
|
<div className="pagination-nav__item pagination-nav__item--next">
|
|
41
|
-
{next &&
|
|
42
|
-
<Link className="pagination-nav__link" to={next.permalink}>
|
|
43
|
-
<div className="pagination-nav__sublabel">
|
|
44
|
-
<Translate
|
|
45
|
-
id="theme.docs.paginator.next"
|
|
46
|
-
description="The label used to navigate to the next doc">
|
|
47
|
-
Next
|
|
48
|
-
</Translate>
|
|
49
|
-
</div>
|
|
50
|
-
<div className="pagination-nav__label">{next.title} »</div>
|
|
51
|
-
</Link>
|
|
52
|
-
)}
|
|
28
|
+
{next && <DocPaginatorNavLink navLink={next} next />}
|
|
53
29
|
</div>
|
|
54
30
|
</nav>
|
|
55
31
|
);
|
|
@@ -0,0 +1,38 @@
|
|
|
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 clsx from 'clsx';
|
|
10
|
+
import Link from '@docusaurus/Link';
|
|
11
|
+
import Translate from '@docusaurus/Translate';
|
|
12
|
+
import type {Props} from '@theme/DocPaginatorNavLink';
|
|
13
|
+
|
|
14
|
+
function DocPaginatorNavLink(props: Props): JSX.Element {
|
|
15
|
+
const {navLink, next} = props;
|
|
16
|
+
return (
|
|
17
|
+
<Link className={clsx('pagination-nav__link')} to={navLink.permalink}>
|
|
18
|
+
<div className="pagination-nav__sublabel">
|
|
19
|
+
{next ? (
|
|
20
|
+
<Translate
|
|
21
|
+
id="theme.docs.paginator.next"
|
|
22
|
+
description="The label used to navigate to the next doc">
|
|
23
|
+
Next
|
|
24
|
+
</Translate>
|
|
25
|
+
) : (
|
|
26
|
+
<Translate
|
|
27
|
+
id="theme.docs.paginator.previous"
|
|
28
|
+
description="The label used to navigate to the previous doc">
|
|
29
|
+
Previous
|
|
30
|
+
</Translate>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
<div className="pagination-nav__label">{navLink.title}</div>
|
|
34
|
+
</Link>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default DocPaginatorNavLink;
|
|
@@ -9,7 +9,12 @@ import React from 'react';
|
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
|
|
11
11
|
import Link from '@docusaurus/Link';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
FooterLinkItem,
|
|
14
|
+
useThemeConfig,
|
|
15
|
+
MultiColumnFooter,
|
|
16
|
+
SimpleFooter,
|
|
17
|
+
} from '@docusaurus/theme-common';
|
|
13
18
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
14
19
|
import isInternalUrl from '@docusaurus/isInternalUrl';
|
|
15
20
|
import styles from './styles.module.css';
|
|
@@ -66,6 +71,70 @@ function FooterLogo({
|
|
|
66
71
|
);
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
function MultiColumnLinks({links}: {links: MultiColumnFooter['links']}) {
|
|
75
|
+
return (
|
|
76
|
+
<>
|
|
77
|
+
{links.map((linkItem, i) => (
|
|
78
|
+
<div key={i} className="col footer__col">
|
|
79
|
+
<div className="footer__title">{linkItem.title}</div>
|
|
80
|
+
<ul className="footer__items">
|
|
81
|
+
{linkItem.items.map((item, key) =>
|
|
82
|
+
item.html ? (
|
|
83
|
+
<li
|
|
84
|
+
key={key}
|
|
85
|
+
className="footer__item"
|
|
86
|
+
// Developer provided the HTML, so assume it's safe.
|
|
87
|
+
// eslint-disable-next-line react/no-danger
|
|
88
|
+
dangerouslySetInnerHTML={{
|
|
89
|
+
__html: item.html,
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
) : (
|
|
93
|
+
<li key={item.href || item.to} className="footer__item">
|
|
94
|
+
<FooterLink {...item} />
|
|
95
|
+
</li>
|
|
96
|
+
),
|
|
97
|
+
)}
|
|
98
|
+
</ul>
|
|
99
|
+
</div>
|
|
100
|
+
))}
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function SimpleLinks({links}: {links: SimpleFooter['links']}) {
|
|
106
|
+
return (
|
|
107
|
+
<div className="footer__links">
|
|
108
|
+
{links.map((item, key) => (
|
|
109
|
+
<>
|
|
110
|
+
{item.html ? (
|
|
111
|
+
<span
|
|
112
|
+
key={key}
|
|
113
|
+
className="footer__link-item"
|
|
114
|
+
// Developer provided the HTML, so assume it's safe.
|
|
115
|
+
// eslint-disable-next-line react/no-danger
|
|
116
|
+
dangerouslySetInnerHTML={{
|
|
117
|
+
__html: item.html,
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
) : (
|
|
121
|
+
<FooterLink {...item} />
|
|
122
|
+
)}
|
|
123
|
+
{links.length !== key + 1 && (
|
|
124
|
+
<span className="footer__link-separator">·</span>
|
|
125
|
+
)}
|
|
126
|
+
</>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isMultiColumnFooterLinks(
|
|
133
|
+
links: MultiColumnFooter['links'] | SimpleFooter['links'],
|
|
134
|
+
): links is MultiColumnFooter['links'] {
|
|
135
|
+
return 'title' in links[0];
|
|
136
|
+
}
|
|
137
|
+
|
|
69
138
|
function Footer(): JSX.Element | null {
|
|
70
139
|
const {footer} = useThemeConfig();
|
|
71
140
|
|
|
@@ -84,41 +153,18 @@ function Footer(): JSX.Element | null {
|
|
|
84
153
|
className={clsx('footer', {
|
|
85
154
|
'footer--dark': footer.style === 'dark',
|
|
86
155
|
})}>
|
|
87
|
-
<div className="container">
|
|
88
|
-
{links &&
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{linkItem.items.map((item, key) =>
|
|
100
|
-
item.html ? (
|
|
101
|
-
<li
|
|
102
|
-
key={key}
|
|
103
|
-
className="footer__item"
|
|
104
|
-
// Developer provided the HTML, so assume it's safe.
|
|
105
|
-
// eslint-disable-next-line react/no-danger
|
|
106
|
-
dangerouslySetInnerHTML={{
|
|
107
|
-
__html: item.html,
|
|
108
|
-
}}
|
|
109
|
-
/>
|
|
110
|
-
) : (
|
|
111
|
-
<li key={item.href || item.to} className="footer__item">
|
|
112
|
-
<FooterLink {...item} />
|
|
113
|
-
</li>
|
|
114
|
-
),
|
|
115
|
-
)}
|
|
116
|
-
</ul>
|
|
117
|
-
) : null}
|
|
118
|
-
</div>
|
|
119
|
-
))}
|
|
120
|
-
</div>
|
|
121
|
-
)}
|
|
156
|
+
<div className="container container-fluid">
|
|
157
|
+
{links &&
|
|
158
|
+
links.length > 0 &&
|
|
159
|
+
(isMultiColumnFooterLinks(links) ? (
|
|
160
|
+
<div className="row footer__links">
|
|
161
|
+
<MultiColumnLinks links={links} />
|
|
162
|
+
</div>
|
|
163
|
+
) : (
|
|
164
|
+
<div className="footer__links text--center">
|
|
165
|
+
<SimpleLinks links={links} />
|
|
166
|
+
</div>
|
|
167
|
+
))}
|
|
122
168
|
{(logo || copyright) && (
|
|
123
169
|
<div className="footer__bottom text--center">
|
|
124
170
|
{logo && (logo.src || logo.srcDark) && (
|
|
@@ -154,4 +200,4 @@ function Footer(): JSX.Element | null {
|
|
|
154
200
|
);
|
|
155
201
|
}
|
|
156
202
|
|
|
157
|
-
export default Footer;
|
|
203
|
+
export default React.memo(Footer);
|
package/src/theme-classic.d.ts
CHANGED
|
@@ -123,13 +123,22 @@ declare module '@theme/CodeBlock' {
|
|
|
123
123
|
declare module '@theme/DocPaginator' {
|
|
124
124
|
import type {PropNavigation} from '@docusaurus/plugin-content-docs';
|
|
125
125
|
|
|
126
|
-
type PageInfo = {readonly permalink: string; readonly title: string};
|
|
127
|
-
|
|
128
126
|
// May be simpler to provide a {navigation: PropNavigation} prop?
|
|
129
127
|
export interface Props extends PropNavigation {}
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
export default function DocPaginator(props: Props): JSX.Element;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
declare module '@theme/DocPaginatorNavLink' {
|
|
133
|
+
import type {PropNavigationLink} from '@docusaurus/plugin-content-docs';
|
|
134
|
+
|
|
135
|
+
// May be simpler to provide a {navigation: PropNavigation} prop?
|
|
136
|
+
export interface Props {
|
|
137
|
+
navLink: PropNavigationLink;
|
|
138
|
+
next?: boolean;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default function DocPaginatorNavLink(props: Props): JSX.Element;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
declare module '@theme/DocSidebar' {
|
package/src/translations.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
Navbar,
|
|
12
12
|
NavbarItem,
|
|
13
13
|
Footer,
|
|
14
|
+
MultiColumnFooter,
|
|
15
|
+
SimpleFooter,
|
|
14
16
|
} from '@docusaurus/theme-common';
|
|
15
17
|
|
|
16
18
|
import {keyBy, chain} from 'lodash';
|
|
@@ -69,10 +71,17 @@ function translateNavbar(
|
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
function isMultiColumnFooterLinks(
|
|
75
|
+
links: MultiColumnFooter['links'] | SimpleFooter['links'],
|
|
76
|
+
): links is MultiColumnFooter['links'] {
|
|
77
|
+
return links.length > 0 && 'title' in links[0];
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
function getFooterTranslationFile(footer: Footer): TranslationFileContent {
|
|
73
|
-
// TODO POC code
|
|
74
81
|
const footerLinkTitles: TranslationFileContent = chain(
|
|
75
|
-
footer.links
|
|
82
|
+
isMultiColumnFooterLinks(footer.links)
|
|
83
|
+
? footer.links.filter((link) => !!link.title)
|
|
84
|
+
: [],
|
|
76
85
|
)
|
|
77
86
|
.keyBy((link) => `link.title.${link.title}`)
|
|
78
87
|
.mapValues((link) => ({
|
|
@@ -82,7 +91,11 @@ function getFooterTranslationFile(footer: Footer): TranslationFileContent {
|
|
|
82
91
|
.value();
|
|
83
92
|
|
|
84
93
|
const footerLinkLabels: TranslationFileContent = chain(
|
|
85
|
-
footer.links
|
|
94
|
+
isMultiColumnFooterLinks(footer.links)
|
|
95
|
+
? footer.links
|
|
96
|
+
.flatMap((link) => link.items)
|
|
97
|
+
.filter((link) => !!link.label)
|
|
98
|
+
: footer.links.filter((link) => !!link.label),
|
|
86
99
|
)
|
|
87
100
|
.keyBy((linkItem) => `link.item.label.${linkItem.label}`)
|
|
88
101
|
.mapValues((linkItem) => ({
|
|
@@ -108,17 +121,24 @@ function translateFooter(
|
|
|
108
121
|
footer: Footer,
|
|
109
122
|
footerTranslations: TranslationFileContent,
|
|
110
123
|
): Footer {
|
|
111
|
-
const links = footer.links
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
const links = isMultiColumnFooterLinks(footer.links)
|
|
125
|
+
? footer.links.map((link) => ({
|
|
126
|
+
...link,
|
|
127
|
+
title:
|
|
128
|
+
footerTranslations[`link.title.${link.title}`]?.message ?? link.title,
|
|
129
|
+
items: link.items.map((linkItem) => ({
|
|
130
|
+
...linkItem,
|
|
131
|
+
label:
|
|
132
|
+
footerTranslations[`link.item.label.${linkItem.label}`]?.message ??
|
|
133
|
+
linkItem.label,
|
|
134
|
+
})),
|
|
135
|
+
}))
|
|
136
|
+
: footer.links.map((link) => ({
|
|
137
|
+
...link,
|
|
138
|
+
label:
|
|
139
|
+
footerTranslations[`link.item.label.${link.label}`]?.message ??
|
|
140
|
+
link.label,
|
|
141
|
+
}));
|
|
122
142
|
|
|
123
143
|
const copyright = footerTranslations.copyright?.message ?? footer.copyright;
|
|
124
144
|
|
|
@@ -311,13 +311,18 @@ const ThemeConfigSchema = Joi.object({
|
|
|
311
311
|
href: Joi.string(),
|
|
312
312
|
}),
|
|
313
313
|
copyright: Joi.string(),
|
|
314
|
-
links: Joi.
|
|
315
|
-
.items(
|
|
314
|
+
links: Joi.alternatives(
|
|
315
|
+
Joi.array().items(
|
|
316
316
|
Joi.object({
|
|
317
|
-
title: Joi.string().allow(null),
|
|
317
|
+
title: Joi.string().allow(null).default(null),
|
|
318
318
|
items: Joi.array().items(FooterLinkItemSchema).default([]),
|
|
319
319
|
}),
|
|
320
|
-
)
|
|
320
|
+
),
|
|
321
|
+
Joi.array().items(FooterLinkItemSchema),
|
|
322
|
+
)
|
|
323
|
+
.messages({
|
|
324
|
+
'alternatives.match': `The footer must be either simple or multi-column, and not a mix of the two. See: https://docusaurus.io/docs/api/themes/configuration#footer-links`,
|
|
325
|
+
})
|
|
321
326
|
.default([]),
|
|
322
327
|
}).optional(),
|
|
323
328
|
prism: Joi.object({
|