@redocly/theme 0.6.0 → 0.6.2
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/README.md +1 -1
- package/lib/ColorModeSwitcher/ColorModeSwitcher.js +1 -1
- package/lib/Footer/Footer.d.ts +6 -3
- package/lib/Footer/Footer.js +3 -3
- package/lib/PageNavigation/NextButton.d.ts +2 -0
- package/lib/PageNavigation/{NextPageLink.js → NextButton.js} +7 -7
- package/lib/PageNavigation/PageNavigation.js +5 -5
- package/lib/PageNavigation/PreviousButton.d.ts +2 -0
- package/lib/PageNavigation/{PreviousPageLink.js → PreviousButton.js} +7 -7
- package/lib/PageNavigation/index.d.ts +2 -2
- package/lib/PageNavigation/index.js +2 -2
- package/lib/Sidebar/types/NavItem.d.ts +1 -1
- package/lib/TableOfContent/TableOfContent.js +14 -19
- package/lib/TableOfContent/utils.d.ts +1 -1
- package/lib/TableOfContent/utils.js +2 -2
- package/lib/config.d.ts +342 -72
- package/lib/config.js +61 -17
- package/lib/mocks/hooks/index.js +4 -5
- package/package.json +3 -3
- package/src/ColorModeSwitcher/ColorModeSwitcher.tsx +1 -1
- package/src/Footer/Footer.tsx +8 -5
- package/src/PageNavigation/{NextPageLink.tsx → NextButton.tsx} +4 -4
- package/src/PageNavigation/PageNavigation.tsx +5 -5
- package/src/PageNavigation/{PreviousPageLink.tsx → PreviousButton.tsx} +4 -4
- package/src/PageNavigation/index.ts +2 -2
- package/src/Sidebar/types/NavItem.ts +1 -1
- package/src/TableOfContent/TableOfContent.tsx +24 -32
- package/src/TableOfContent/utils.ts +2 -2
- package/src/config.ts +73 -24
- package/src/mocks/hooks/index.ts +4 -5
- package/src/settings.yaml +2 -2
- package/src/types/portal/src/shared/constants.d.ts +0 -1
- package/src/types/portal/src/shared/types/nav.d.ts +0 -1
- package/lib/PageNavigation/NextPageLink.d.ts +0 -2
- package/lib/PageNavigation/PreviousPageLink.d.ts +0 -2
package/lib/config.js
CHANGED
|
@@ -13,22 +13,67 @@ const LogoConfig = zod_1.z
|
|
|
13
13
|
const HideConfig = zod_1.z.object({
|
|
14
14
|
hide: zod_1.z.boolean().optional(),
|
|
15
15
|
});
|
|
16
|
+
const ScriptConfig = zod_1.z
|
|
17
|
+
.object({
|
|
18
|
+
src: zod_1.z.string(),
|
|
19
|
+
async: zod_1.z.boolean().optional(),
|
|
20
|
+
crossorigin: zod_1.z.string().optional(),
|
|
21
|
+
defer: zod_1.z.boolean().optional(),
|
|
22
|
+
fetchpriority: zod_1.z.string().optional(),
|
|
23
|
+
integrity: zod_1.z.string().optional(),
|
|
24
|
+
module: zod_1.z.boolean().optional(),
|
|
25
|
+
nomodule: zod_1.z.boolean().optional(),
|
|
26
|
+
nonce: zod_1.z.string().optional(),
|
|
27
|
+
referrerpolicy: zod_1.z.string().optional(),
|
|
28
|
+
type: zod_1.z.string().optional(),
|
|
29
|
+
})
|
|
30
|
+
.passthrough();
|
|
31
|
+
const LinksConfig = zod_1.z
|
|
32
|
+
.object({
|
|
33
|
+
href: zod_1.z.string(),
|
|
34
|
+
as: zod_1.z.string().optional(),
|
|
35
|
+
crossorigin: zod_1.z.string().optional(),
|
|
36
|
+
fetchpriority: zod_1.z.string().optional(),
|
|
37
|
+
hreflang: zod_1.z.string().optional(),
|
|
38
|
+
imagesizes: zod_1.z.string().optional(),
|
|
39
|
+
imagesrcset: zod_1.z.string().optional(),
|
|
40
|
+
integrity: zod_1.z.string().optional(),
|
|
41
|
+
media: zod_1.z.string().optional(),
|
|
42
|
+
prefetch: zod_1.z.string().optional(),
|
|
43
|
+
referrerpolicy: zod_1.z.string().optional(),
|
|
44
|
+
rel: zod_1.z.string().optional(),
|
|
45
|
+
sizes: zod_1.z.string().optional(),
|
|
46
|
+
title: zod_1.z.string().optional(),
|
|
47
|
+
type: zod_1.z.string().optional(),
|
|
48
|
+
})
|
|
49
|
+
.passthrough();
|
|
16
50
|
exports.ThemeConfig = zod_1.z
|
|
17
51
|
.object({
|
|
18
52
|
imports: zod_1.z.array(zod_1.z.string()).default([]).optional(),
|
|
19
53
|
logo: LogoConfig.optional(),
|
|
20
|
-
navbar:
|
|
21
|
-
|
|
54
|
+
navbar: zod_1.z
|
|
55
|
+
.object({
|
|
56
|
+
items: zod_1.z.array(zod_1.z.any()).optional(), // todo: think about validation here
|
|
57
|
+
})
|
|
58
|
+
.extend(HideConfig.shape)
|
|
59
|
+
.strict()
|
|
60
|
+
.optional(),
|
|
61
|
+
footer: zod_1.z
|
|
62
|
+
.object({
|
|
63
|
+
items: zod_1.z.array(zod_1.z.any()).optional(),
|
|
64
|
+
copyrightText: zod_1.z.string().optional(),
|
|
65
|
+
})
|
|
66
|
+
.extend(HideConfig.shape)
|
|
67
|
+
.strict()
|
|
68
|
+
.optional(),
|
|
22
69
|
sidebar: HideConfig.strict().optional(),
|
|
23
|
-
navbarItems: zod_1.z.any().optional(),
|
|
24
|
-
footerItems: zod_1.z.any().optional(),
|
|
25
70
|
scripts: zod_1.z
|
|
26
|
-
.
|
|
27
|
-
.optional(),
|
|
28
|
-
|
|
29
|
-
|
|
71
|
+
.object({
|
|
72
|
+
head: zod_1.z.array(ScriptConfig).optional(),
|
|
73
|
+
body: zod_1.z.array(ScriptConfig).optional(),
|
|
74
|
+
})
|
|
30
75
|
.optional(),
|
|
31
|
-
|
|
76
|
+
links: zod_1.z.array(LinksConfig).optional(),
|
|
32
77
|
search: zod_1.z
|
|
33
78
|
.object({
|
|
34
79
|
placement: zod_1.z.string().default('navbar').optional(),
|
|
@@ -39,8 +84,7 @@ exports.ThemeConfig = zod_1.z
|
|
|
39
84
|
.optional(),
|
|
40
85
|
colorMode: zod_1.z
|
|
41
86
|
.object({
|
|
42
|
-
|
|
43
|
-
default: zod_1.z.string().optional(),
|
|
87
|
+
ignoreDetection: zod_1.z.boolean().optional(),
|
|
44
88
|
modes: zod_1.z.array(zod_1.z.string()).default(['light', 'dark']).optional(),
|
|
45
89
|
})
|
|
46
90
|
.extend(HideConfig.shape)
|
|
@@ -49,13 +93,13 @@ exports.ThemeConfig = zod_1.z
|
|
|
49
93
|
.default({}),
|
|
50
94
|
navigation: zod_1.z
|
|
51
95
|
.object({
|
|
52
|
-
|
|
53
|
-
.object({
|
|
96
|
+
nextButton: zod_1.z
|
|
97
|
+
.object({ text: zod_1.z.string().default('Next to {label}') })
|
|
54
98
|
.extend(HideConfig.shape)
|
|
55
99
|
.optional()
|
|
56
100
|
.default({}),
|
|
57
|
-
|
|
58
|
-
.object({
|
|
101
|
+
previousButton: zod_1.z
|
|
102
|
+
.object({ text: zod_1.z.string().default('Back to {label}') })
|
|
59
103
|
.extend(HideConfig.shape)
|
|
60
104
|
.optional()
|
|
61
105
|
.default({}),
|
|
@@ -65,7 +109,7 @@ exports.ThemeConfig = zod_1.z
|
|
|
65
109
|
.default({}),
|
|
66
110
|
markdown: zod_1.z
|
|
67
111
|
.object({
|
|
68
|
-
|
|
112
|
+
frontMatterKeysToResolve: zod_1.z.array(zod_1.z.string()).default(['image', 'links']).optional(),
|
|
69
113
|
lastUpdatedBlock: zod_1.z
|
|
70
114
|
.object({
|
|
71
115
|
format: zod_1.z.enum(['timeago', 'iso', 'long', 'short']).default('timeago').optional(),
|
|
@@ -77,7 +121,7 @@ exports.ThemeConfig = zod_1.z
|
|
|
77
121
|
toc: zod_1.z
|
|
78
122
|
.object({
|
|
79
123
|
header: zod_1.z.string().default('On this page').optional(),
|
|
80
|
-
|
|
124
|
+
depth: zod_1.z.number().default(3).optional(),
|
|
81
125
|
})
|
|
82
126
|
.extend(HideConfig.shape)
|
|
83
127
|
.optional()
|
package/lib/mocks/hooks/index.js
CHANGED
|
@@ -5,7 +5,7 @@ function useThemeConfig() {
|
|
|
5
5
|
return {
|
|
6
6
|
search: { hide: false, placement: 'navbar' },
|
|
7
7
|
markdown: {
|
|
8
|
-
toc: {
|
|
8
|
+
toc: { depth: 3, header: 'Table of contents', hide: false },
|
|
9
9
|
lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
|
|
10
10
|
copyCodeSnippet: {
|
|
11
11
|
hide: false,
|
|
@@ -18,15 +18,14 @@ function useThemeConfig() {
|
|
|
18
18
|
baseUrl: '',
|
|
19
19
|
text: 'Edit this page',
|
|
20
20
|
},
|
|
21
|
-
|
|
21
|
+
frontMatterKeysToResolve: ['image', 'links'],
|
|
22
22
|
},
|
|
23
23
|
navigation: {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
nextButton: { text: 'next page theme config label' },
|
|
25
|
+
previousButton: { text: 'prev page theme config label' },
|
|
26
26
|
},
|
|
27
27
|
colorMode: {
|
|
28
28
|
modes: ['light', 'dark'],
|
|
29
|
-
default: 'light',
|
|
30
29
|
},
|
|
31
30
|
};
|
|
32
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Shared UI components",
|
|
5
5
|
"author": "team@redocly.com",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@storybook/manager-webpack5": "^6.5.9",
|
|
57
57
|
"@storybook/node-logger": "^6.5.9",
|
|
58
58
|
"@storybook/react": "^6.5.9",
|
|
59
|
-
"@storybook/testing-library": "^0.0.
|
|
59
|
+
"@storybook/testing-library": "^0.0.13",
|
|
60
60
|
"@storybook/theming": "^6.5.9",
|
|
61
61
|
"@testing-library/jest-dom": "^5.16.5",
|
|
62
62
|
"@testing-library/react": "^12.1.4",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@types/react": "^17.0.43",
|
|
71
71
|
"@types/react-dom": "^17.0.14",
|
|
72
72
|
"@types/react-router-dom": "^5.3.1",
|
|
73
|
-
"@types/styled-components": "^5.1.
|
|
73
|
+
"@types/styled-components": "^5.1.26",
|
|
74
74
|
"@types/styled-system": "^5.1.13",
|
|
75
75
|
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
|
76
76
|
"@typescript-eslint/parser": "^5.23.0",
|
|
@@ -9,7 +9,7 @@ export function ColorModeSwitcher(): JSX.Element | null {
|
|
|
9
9
|
const colorMode = themeSettings.colorMode;
|
|
10
10
|
const [activeColorMode, setActiveColorMode] = useState('');
|
|
11
11
|
const modes = colorMode?.modes || ['light', 'dark'];
|
|
12
|
-
const defaultColor =
|
|
12
|
+
const defaultColor = modes[0] || 'light';
|
|
13
13
|
|
|
14
14
|
useMount(() => {
|
|
15
15
|
setActiveColorMode(document.documentElement.className || defaultColor);
|
package/src/Footer/Footer.tsx
CHANGED
|
@@ -5,22 +5,25 @@ import { FooterColumns } from '@theme/Footer/FooterColumns';
|
|
|
5
5
|
import { FooterCopyright } from '@theme/Footer/FooterCopyright';
|
|
6
6
|
import { isEmptyArray } from '@theme/utils';
|
|
7
7
|
import { useThemeConfig } from '@theme/hooks';
|
|
8
|
-
import type {
|
|
8
|
+
import type { NavGroup, ResolvedNavItem } from '@theme/types/portal';
|
|
9
9
|
|
|
10
10
|
interface FooterProps {
|
|
11
|
-
data:
|
|
11
|
+
data: {
|
|
12
|
+
items?: NavGroup;
|
|
13
|
+
copyrightText?: string;
|
|
14
|
+
};
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
export function Footer({ data: {
|
|
17
|
+
export function Footer({ data: { items, copyrightText } }: FooterProps): JSX.Element | null {
|
|
15
18
|
const { footer } = useThemeConfig();
|
|
16
19
|
|
|
17
|
-
if (isEmptyArray(
|
|
20
|
+
if (isEmptyArray(items) || !copyrightText || footer?.hide) {
|
|
18
21
|
return null;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
return (
|
|
22
25
|
<FooterContainer data-component-name="Footer/Footer">
|
|
23
|
-
<FooterColumns columns={
|
|
26
|
+
<FooterColumns columns={items as ResolvedNavItem[]} />
|
|
24
27
|
<FooterCopyright copyrightText={copyrightText} />
|
|
25
28
|
</FooterContainer>
|
|
26
29
|
);
|
|
@@ -10,15 +10,15 @@ interface NextPageType {
|
|
|
10
10
|
nextPage?: ResolvedNavItemWithLink | null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function
|
|
13
|
+
export function NextButton(): JSX.Element {
|
|
14
14
|
const { nextPage }: NextPageType = useSidebarSiblingsData() || {};
|
|
15
15
|
const { navigation } = useThemeConfig();
|
|
16
16
|
|
|
17
|
-
if (!nextPage || navigation?.
|
|
17
|
+
if (!nextPage || navigation?.nextButton?.hide) {
|
|
18
18
|
return <div> </div>;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const text = (navigation?.nextButton?.text || 'Next to {label}').replace(
|
|
22
22
|
'{label}',
|
|
23
23
|
nextPage.label || nextPage.routeSlug || '',
|
|
24
24
|
);
|
|
@@ -30,7 +30,7 @@ export function NextPageLink(): JSX.Element {
|
|
|
30
30
|
to={nextPage.link}
|
|
31
31
|
data-component-name="PageNavigation/NextPageLink"
|
|
32
32
|
>
|
|
33
|
-
{
|
|
33
|
+
{text}
|
|
34
34
|
</StyledButton>
|
|
35
35
|
);
|
|
36
36
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { PreviousButton } from '@theme/PageNavigation/PreviousButton';
|
|
5
|
+
import { NextButton } from '@theme/PageNavigation/NextButton';
|
|
6
6
|
import { useThemeConfig } from '@theme/hooks/useThemeConfig';
|
|
7
7
|
|
|
8
8
|
export function PageNavigation(): JSX.Element | null {
|
|
9
9
|
const { navigation } = useThemeConfig();
|
|
10
10
|
|
|
11
|
-
if (navigation?.
|
|
11
|
+
if (navigation?.previousButton?.hide && navigation?.nextButton?.hide) {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<PageNavigationWrapper data-component-name="PageNavigation/PageNavigation">
|
|
17
|
-
<
|
|
18
|
-
<
|
|
17
|
+
<PreviousButton />
|
|
18
|
+
<NextButton />
|
|
19
19
|
</PageNavigationWrapper>
|
|
20
20
|
);
|
|
21
21
|
}
|
|
@@ -10,15 +10,15 @@ interface PreviousPageType {
|
|
|
10
10
|
prevPage?: ResolvedNavItemWithLink | null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function
|
|
13
|
+
export function PreviousButton(): JSX.Element {
|
|
14
14
|
const { prevPage }: PreviousPageType = useSidebarSiblingsData() || {};
|
|
15
15
|
const { navigation } = useThemeConfig();
|
|
16
16
|
|
|
17
|
-
if (!prevPage || navigation?.
|
|
17
|
+
if (!prevPage || navigation?.previousButton?.hide) {
|
|
18
18
|
return <div> </div>;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const text = (navigation?.previousButton?.text || 'Back to {label}').replace(
|
|
22
22
|
'{label}',
|
|
23
23
|
prevPage.label || prevPage.routeSlug || '',
|
|
24
24
|
);
|
|
@@ -30,7 +30,7 @@ export function PreviousPageLink(): JSX.Element {
|
|
|
30
30
|
to={prevPage.link}
|
|
31
31
|
data-component-name="PageNavigation/PreviousPageLink"
|
|
32
32
|
>
|
|
33
|
-
{
|
|
33
|
+
{text}
|
|
34
34
|
</StyledButton>
|
|
35
35
|
);
|
|
36
36
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from '@theme/PageNavigation/
|
|
1
|
+
export * from '@theme/PageNavigation/NextButton';
|
|
2
2
|
export * from '@theme/PageNavigation/PageNavigation';
|
|
3
|
-
export * from '@theme/PageNavigation/
|
|
3
|
+
export * from '@theme/PageNavigation/PreviousButton';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
|
|
4
4
|
import { useFullHeight } from '@theme/hooks/useFullHeight';
|
|
@@ -16,11 +16,11 @@ interface TableOfContentProps {
|
|
|
16
16
|
export function TableOfContent(props: TableOfContentProps): JSX.Element | null {
|
|
17
17
|
const { headings, contentWrapper } = props;
|
|
18
18
|
|
|
19
|
-
const sidebar = useRef<HTMLDivElement | null>(null);
|
|
19
|
+
const sidebar = React.useRef<HTMLDivElement | null>(null);
|
|
20
20
|
useFullHeight(sidebar);
|
|
21
21
|
const { markdown: { toc = {} } = {} } = useThemeConfig();
|
|
22
22
|
|
|
23
|
-
const displayedHeadings = getDisplayedHeadings(headings, toc.
|
|
23
|
+
const displayedHeadings = getDisplayedHeadings(headings, toc.depth || 3);
|
|
24
24
|
const leastDepth = getLeastDepth(displayedHeadings);
|
|
25
25
|
|
|
26
26
|
const activeHeadingId = useActiveHeading(
|
|
@@ -31,38 +31,30 @@ export function TableOfContent(props: TableOfContentProps): JSX.Element | null {
|
|
|
31
31
|
if (toc?.hide) {
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
|
-
if (headings && headings.length === 1 && (!headings[0] || headings[0].depth === 1)) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
if (!headings?.length) {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
34
|
|
|
41
35
|
return (
|
|
42
36
|
<>
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
</TableOfContentMenu>
|
|
65
|
-
)}
|
|
37
|
+
<TableOfContentMenu data-component-name="TableOfContent/TableOfContent">
|
|
38
|
+
<TableOfContentItems ref={sidebar}>
|
|
39
|
+
{displayedHeadings.length ? <TocHeader>{toc.header || 'On this page'}</TocHeader> : null}
|
|
40
|
+
{displayedHeadings.map((heading: MdHeading | null, idx: number) => {
|
|
41
|
+
if (!heading) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const href = '#' + heading.id;
|
|
45
|
+
return (
|
|
46
|
+
<MenuItem
|
|
47
|
+
key={href + idx}
|
|
48
|
+
href={href}
|
|
49
|
+
depth={heading.depth - leastDepth + 1 || 0}
|
|
50
|
+
className={activeHeadingId === heading.id ? 'active' : ''}
|
|
51
|
+
dangerouslySetInnerHTML={{ __html: heading.value || '' }}
|
|
52
|
+
data-cy={`toc-${heading.value}`}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
})}
|
|
56
|
+
</TableOfContentItems>
|
|
57
|
+
</TableOfContentMenu>
|
|
66
58
|
</>
|
|
67
59
|
);
|
|
68
60
|
}
|
|
@@ -2,7 +2,7 @@ import type { MdHeading } from '@theme/types/portal';
|
|
|
2
2
|
|
|
3
3
|
export function getDisplayedHeadings(
|
|
4
4
|
headings: Array<MdHeading | null> | null | undefined,
|
|
5
|
-
|
|
5
|
+
tocDepth: number,
|
|
6
6
|
): Array<MdHeading | null> {
|
|
7
7
|
if (!headings) {
|
|
8
8
|
return [];
|
|
@@ -14,7 +14,7 @@ export function getDisplayedHeadings(
|
|
|
14
14
|
if (idx === 0 && heading.depth === 1) {
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
-
return !(heading.depth && heading.depth >
|
|
17
|
+
return !(heading.depth && heading.depth > tocDepth);
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
|
package/src/config.ts
CHANGED
|
@@ -13,24 +13,73 @@ const HideConfig = z.object({
|
|
|
13
13
|
hide: z.boolean().optional(),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
const ScriptConfig = z
|
|
17
|
+
.object({
|
|
18
|
+
src: z.string(),
|
|
19
|
+
async: z.boolean().optional(),
|
|
20
|
+
crossorigin: z.string().optional(),
|
|
21
|
+
defer: z.boolean().optional(),
|
|
22
|
+
fetchpriority: z.string().optional(),
|
|
23
|
+
integrity: z.string().optional(),
|
|
24
|
+
module: z.boolean().optional(),
|
|
25
|
+
nomodule: z.boolean().optional(),
|
|
26
|
+
nonce: z.string().optional(),
|
|
27
|
+
referrerpolicy: z.string().optional(),
|
|
28
|
+
type: z.string().optional(),
|
|
29
|
+
})
|
|
30
|
+
.passthrough();
|
|
31
|
+
|
|
32
|
+
const LinksConfig = z
|
|
33
|
+
.object({
|
|
34
|
+
href: z.string(),
|
|
35
|
+
|
|
36
|
+
as: z.string().optional(),
|
|
37
|
+
crossorigin: z.string().optional(),
|
|
38
|
+
fetchpriority: z.string().optional(),
|
|
39
|
+
hreflang: z.string().optional(),
|
|
40
|
+
imagesizes: z.string().optional(),
|
|
41
|
+
imagesrcset: z.string().optional(),
|
|
42
|
+
integrity: z.string().optional(),
|
|
43
|
+
media: z.string().optional(),
|
|
44
|
+
prefetch: z.string().optional(),
|
|
45
|
+
referrerpolicy: z.string().optional(),
|
|
46
|
+
rel: z.string().optional(),
|
|
47
|
+
sizes: z.string().optional(),
|
|
48
|
+
title: z.string().optional(),
|
|
49
|
+
type: z.string().optional(),
|
|
50
|
+
})
|
|
51
|
+
.passthrough();
|
|
52
|
+
|
|
16
53
|
export const ThemeConfig = z
|
|
17
54
|
.object({
|
|
18
55
|
imports: z.array(z.string()).default([]).optional(),
|
|
19
56
|
|
|
20
57
|
logo: LogoConfig.optional(),
|
|
21
|
-
navbar:
|
|
22
|
-
|
|
58
|
+
navbar: z
|
|
59
|
+
.object({
|
|
60
|
+
items: z.array(z.any()).optional(), // todo: think about validation here
|
|
61
|
+
})
|
|
62
|
+
.extend(HideConfig.shape)
|
|
63
|
+
.strict()
|
|
64
|
+
.optional(),
|
|
65
|
+
|
|
66
|
+
footer: z
|
|
67
|
+
.object({
|
|
68
|
+
items: z.array(z.any()).optional(), // todo: think about validation here
|
|
69
|
+
copyrightText: z.string().optional(),
|
|
70
|
+
})
|
|
71
|
+
.extend(HideConfig.shape)
|
|
72
|
+
.strict()
|
|
73
|
+
.optional(),
|
|
23
74
|
sidebar: HideConfig.strict().optional(),
|
|
24
|
-
navbarItems: z.any().optional(), // todo: think about validation here
|
|
25
|
-
footerItems: z.any().optional(), // todo: think about validation here
|
|
26
75
|
|
|
27
76
|
scripts: z
|
|
28
|
-
.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
77
|
+
.object({
|
|
78
|
+
head: z.array(ScriptConfig).optional(),
|
|
79
|
+
body: z.array(ScriptConfig).optional(),
|
|
80
|
+
})
|
|
32
81
|
.optional(),
|
|
33
|
-
|
|
82
|
+
links: z.array(LinksConfig).optional(),
|
|
34
83
|
|
|
35
84
|
search: z
|
|
36
85
|
.object({
|
|
@@ -43,8 +92,7 @@ export const ThemeConfig = z
|
|
|
43
92
|
|
|
44
93
|
colorMode: z
|
|
45
94
|
.object({
|
|
46
|
-
|
|
47
|
-
default: z.string().optional(),
|
|
95
|
+
ignoreDetection: z.boolean().optional(),
|
|
48
96
|
modes: z.array(z.string()).default(['light', 'dark']).optional(),
|
|
49
97
|
})
|
|
50
98
|
.extend(HideConfig.shape)
|
|
@@ -53,13 +101,13 @@ export const ThemeConfig = z
|
|
|
53
101
|
.default({}),
|
|
54
102
|
navigation: z
|
|
55
103
|
.object({
|
|
56
|
-
|
|
57
|
-
.object({
|
|
104
|
+
nextButton: z
|
|
105
|
+
.object({ text: z.string().default('Next to {label}') })
|
|
58
106
|
.extend(HideConfig.shape)
|
|
59
107
|
.optional()
|
|
60
108
|
.default({}),
|
|
61
|
-
|
|
62
|
-
.object({
|
|
109
|
+
previousButton: z
|
|
110
|
+
.object({ text: z.string().default('Back to {label}') })
|
|
63
111
|
.extend(HideConfig.shape)
|
|
64
112
|
.optional()
|
|
65
113
|
.default({}),
|
|
@@ -69,7 +117,7 @@ export const ThemeConfig = z
|
|
|
69
117
|
.default({}),
|
|
70
118
|
markdown: z
|
|
71
119
|
.object({
|
|
72
|
-
|
|
120
|
+
frontMatterKeysToResolve: z.array(z.string()).default(['image', 'links']).optional(),
|
|
73
121
|
lastUpdatedBlock: z
|
|
74
122
|
.object({
|
|
75
123
|
format: z.enum(['timeago', 'iso', 'long', 'short']).default('timeago').optional(),
|
|
@@ -81,7 +129,7 @@ export const ThemeConfig = z
|
|
|
81
129
|
toc: z
|
|
82
130
|
.object({
|
|
83
131
|
header: z.string().default('On this page').optional(),
|
|
84
|
-
|
|
132
|
+
depth: z.number().default(3).optional(),
|
|
85
133
|
})
|
|
86
134
|
.extend(HideConfig.shape)
|
|
87
135
|
.optional()
|
|
@@ -116,15 +164,16 @@ export const ThemeConfig = z
|
|
|
116
164
|
.default({});
|
|
117
165
|
|
|
118
166
|
export type ThemeConfig = z.infer<typeof ThemeConfig>;
|
|
119
|
-
export type ThemeUIConfig = Omit<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
> & {
|
|
123
|
-
navbarItems?: any; // TODO
|
|
124
|
-
footerItems?: any; // TODO
|
|
167
|
+
export type ThemeUIConfig = Omit<ThemeConfig, 'navbar' | 'footer' | 'links' | 'scripts'> & {
|
|
168
|
+
navbar?: any; // TODO
|
|
169
|
+
footer?: any; // TODO
|
|
125
170
|
auth?: {
|
|
126
171
|
// used by portal dev login emulator
|
|
127
|
-
|
|
172
|
+
idpsInfo?: {
|
|
173
|
+
idpId: string;
|
|
174
|
+
type: string; // AuthProviderType
|
|
175
|
+
title: string | undefined;
|
|
176
|
+
}[];
|
|
128
177
|
devLogin?: boolean;
|
|
129
178
|
};
|
|
130
179
|
};
|
package/src/mocks/hooks/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export function useThemeConfig<T extends Record<string, unknown>>(): T & ThemeUI
|
|
|
10
10
|
return {
|
|
11
11
|
search: { hide: false, placement: 'navbar' },
|
|
12
12
|
markdown: {
|
|
13
|
-
toc: {
|
|
13
|
+
toc: { depth: 3, header: 'Table of contents', hide: false },
|
|
14
14
|
lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
|
|
15
15
|
copyCodeSnippet: {
|
|
16
16
|
hide: false,
|
|
@@ -23,15 +23,14 @@ export function useThemeConfig<T extends Record<string, unknown>>(): T & ThemeUI
|
|
|
23
23
|
baseUrl: '',
|
|
24
24
|
text: 'Edit this page',
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
frontMatterKeysToResolve: ['image', 'links'],
|
|
27
27
|
},
|
|
28
28
|
navigation: {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
nextButton: { text: 'next page theme config label' },
|
|
30
|
+
previousButton: { text: 'prev page theme config label' },
|
|
31
31
|
},
|
|
32
32
|
colorMode: {
|
|
33
33
|
modes: ['light', 'dark'],
|
|
34
|
-
default: 'light',
|
|
35
34
|
},
|
|
36
35
|
} as ThemeUIConfig as T & ThemeUIConfig;
|
|
37
36
|
}
|
package/src/settings.yaml
CHANGED
|
@@ -8,7 +8,6 @@ export declare const PUBLIC_ASSETS_FOLDER = '/assets';
|
|
|
8
8
|
export declare const PUBLIC_STATIC_FOLDER = '/static';
|
|
9
9
|
export declare const PERMISSION_PROP_NAME = 'redocly::permission';
|
|
10
10
|
export declare const DEFAULT_PLACEHOLDER_PERMISSION = 'redocly:default-permission';
|
|
11
|
-
export declare const DIRECTORY_PERMISSIONS_FILE_NAME = 'permissions.rbac.yaml';
|
|
12
11
|
export declare const REQUIRED_OIDC_SCOPES: string[];
|
|
13
12
|
export declare const DEFAULT_COOKIE_EXPIRATION: number;
|
|
14
13
|
export declare const DEFAULT_AUTHENTICATED_ROLE = 'AuthenticatedUser';
|