@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.
@@ -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
- const DocPaginator: (props: Props) => JSX.Element;
132
- export default DocPaginator;
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' {
@@ -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
- // TODO POC code
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
- })).default([])
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 Link from '@docusaurus/Link';
9
- import Translate, {translate} from '@docusaurus/Translate';
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
- &laquo; {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} &raquo;</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 && links.length > 0 && (
76
- <div className="row footer__links">
77
- {links.map((linkItem, i) => (
78
- <div key={i} className="col footer__col">
79
- {linkItem.title != null ? (
80
- <div className="footer__title">{linkItem.title}</div>
81
- ) : null}
82
- {linkItem.items != null &&
83
- Array.isArray(linkItem.items) &&
84
- linkItem.items.length > 0 ? (
85
- <ul className="footer__items">
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-4298",
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-4298",
27
- "@docusaurus/plugin-content-blog": "0.0.0-4298",
28
- "@docusaurus/plugin-content-docs": "0.0.0-4298",
29
- "@docusaurus/plugin-content-pages": "0.0.0-4298",
30
- "@docusaurus/theme-common": "0.0.0-4298",
31
- "@docusaurus/theme-translations": "0.0.0-4298",
32
- "@docusaurus/utils": "0.0.0-4298",
33
- "@docusaurus/utils-validation": "0.0.0-4298",
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.36",
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-4298",
49
- "@docusaurus/types": "0.0.0-4298",
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": "ca4920916dff261f4dbffd3b2465a5aac3a66c3f"
64
+ "gitHead": "d7b9a0f0eb96f5f853500c3810f7f4df4054b910"
65
65
  }
@@ -6,11 +6,11 @@
6
6
  */
7
7
 
8
8
  import React from 'react';
9
- import Link from '@docusaurus/Link';
10
- import Translate, {translate} from '@docusaurus/Translate';
11
- import type {PropNavigation} from '@docusaurus/plugin-content-docs';
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: PropNavigation): JSX.Element {
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
- &laquo; {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} &raquo;</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 {FooterLinkItem, useThemeConfig} from '@docusaurus/theme-common';
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 && links.length > 0 && (
89
- <div className="row footer__links">
90
- {links.map((linkItem, i) => (
91
- <div key={i} className="col footer__col">
92
- {linkItem.title != null ? (
93
- <div className="footer__title">{linkItem.title}</div>
94
- ) : null}
95
- {linkItem.items != null &&
96
- Array.isArray(linkItem.items) &&
97
- linkItem.items.length > 0 ? (
98
- <ul className="footer__items">
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);
@@ -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
- const DocPaginator: (props: Props) => JSX.Element;
132
- export default DocPaginator;
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' {
@@ -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.filter((link) => !!link.title),
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.flatMap((link) => link.items).filter((link) => !!link.label),
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.map((link) => ({
112
- ...link,
113
- title:
114
- footerTranslations[`link.title.${link.title}`]?.message ?? link.title,
115
- items: link.items.map((linkItem) => ({
116
- ...linkItem,
117
- label:
118
- footerTranslations[`link.item.label.${linkItem.label}`]?.message ??
119
- linkItem.label,
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.array()
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({