@redocly/theme 0.5.0 → 0.6.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/ColorModeSwitcher/ColorModeSwitcher.js +23 -10
- package/lib/EditPageButton/EditPageButton.d.ts +1 -1
- package/lib/EditPageButton/EditPageButton.js +1 -1
- package/lib/Footer/Footer.js +2 -2
- package/lib/LastUpdated/LastUpdated.js +30 -7
- package/lib/Markdown/CodeSample/CodeSample.js +6 -14
- package/lib/Markdown/MarkdownLayout.d.ts +1 -1
- package/lib/Markdown/MarkdownLayout.js +5 -1
- package/lib/Navbar/Navbar.js +2 -2
- package/lib/PageNavigation/NextPageLink.js +30 -7
- package/lib/PageNavigation/PageNavigation.js +4 -3
- package/lib/PageNavigation/PreviousPageLink.js +4 -4
- package/lib/Sidebar/SidebarLayout.js +2 -2
- package/lib/Sidebar/types/MenuStyle.js +0 -1
- package/lib/TableOfContent/TableOfContent.d.ts +0 -1
- package/lib/TableOfContent/TableOfContent.js +5 -7
- package/lib/config.d.ts +385 -0
- package/lib/config.js +113 -0
- package/lib/globalStyle.js +3 -5
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useActiveHeading.js +1 -1
- package/lib/hooks/useActiveSectionId.js +1 -1
- package/lib/hooks/useThemeConfig.d.ts +1 -0
- package/lib/hooks/useThemeConfig.js +6 -0
- package/lib/icons/ColorModeIcon/ColorModeIcon.js +3 -3
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/mocks/Link.js +1 -1
- package/lib/mocks/hooks/index.d.ts +2 -5
- package/lib/mocks/hooks/index.js +22 -6
- package/lib/mocks/types.d.ts +0 -11
- package/lib/mocks/types.js +1 -0
- package/lib/mocks/utils.js +1 -1
- package/lib/types/config.d.ts +5 -0
- package/lib/types/config.js +3 -0
- package/lib/utils/args-typecheck.js +1 -1
- package/package.json +10 -8
- package/src/ColorModeSwitcher/ColorModeSwitcher.tsx +29 -12
- package/src/EditPageButton/EditPageButton.tsx +2 -2
- package/src/Footer/Footer.tsx +2 -2
- package/src/LastUpdated/LastUpdated.tsx +8 -6
- package/src/Markdown/CodeSample/CodeSample.tsx +7 -16
- package/src/Markdown/MarkdownLayout.tsx +9 -3
- package/src/Navbar/Navbar.tsx +2 -2
- package/src/PageNavigation/NextPageLink.tsx +8 -5
- package/src/PageNavigation/PageNavigation.tsx +3 -3
- package/src/PageNavigation/PreviousPageLink.tsx +7 -4
- package/src/Sidebar/SidebarLayout.tsx +2 -2
- package/src/Sidebar/types/MenuStyle.ts +0 -1
- package/src/TableOfContent/TableOfContent.tsx +5 -7
- package/src/config.ts +130 -0
- package/src/globalStyle.ts +3 -5
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useActiveHeading.ts +3 -1
- package/src/hooks/useActiveSectionId.ts +1 -1
- package/src/hooks/useThemeConfig.ts +1 -0
- package/src/icons/ColorModeIcon/ColorModeIcon.tsx +3 -3
- package/src/index.ts +3 -0
- package/src/mocks/Link.tsx +8 -1
- package/src/mocks/hooks/index.ts +22 -9
- package/src/mocks/types.ts +2 -11
- package/src/mocks/utils.ts +1 -1
- package/src/types/config.ts +5 -0
- package/src/types/portal/src/shared/constants.d.ts +0 -1
- package/src/utils/args-typecheck.ts +1 -1
- package/lib/hooks/useDefaultThemeSettings.d.ts +0 -2
- package/lib/hooks/useDefaultThemeSettings.js +0 -10
- package/src/hooks/useDefaultThemeSettings.ts +0 -7
package/src/config.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const LogoConfig = z
|
|
4
|
+
.object({
|
|
5
|
+
image: z.string().optional(),
|
|
6
|
+
altText: z.string().optional(),
|
|
7
|
+
link: z.string().optional(),
|
|
8
|
+
favicon: z.string().optional(),
|
|
9
|
+
})
|
|
10
|
+
.strict();
|
|
11
|
+
|
|
12
|
+
const HideConfig = z.object({
|
|
13
|
+
hide: z.boolean().optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const ThemeConfig = z
|
|
17
|
+
.object({
|
|
18
|
+
imports: z.array(z.string()).default([]).optional(),
|
|
19
|
+
|
|
20
|
+
logo: LogoConfig.optional(),
|
|
21
|
+
navbar: HideConfig.strict().optional(),
|
|
22
|
+
footer: HideConfig.strict().optional(),
|
|
23
|
+
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
|
+
|
|
27
|
+
scripts: z
|
|
28
|
+
.array(z.union([z.string(), z.record(z.union([z.boolean(), z.string()]))]))
|
|
29
|
+
.optional(),
|
|
30
|
+
postBodyScripts: z
|
|
31
|
+
.array(z.union([z.string(), z.record(z.union([z.boolean(), z.string()]))]))
|
|
32
|
+
.optional(),
|
|
33
|
+
styles: z.array(z.union([z.string(), z.record(z.union([z.boolean(), z.string()]))])).optional(),
|
|
34
|
+
|
|
35
|
+
search: z
|
|
36
|
+
.object({
|
|
37
|
+
placement: z.string().default('navbar').optional(),
|
|
38
|
+
})
|
|
39
|
+
.extend(HideConfig.shape)
|
|
40
|
+
.strict()
|
|
41
|
+
.default({})
|
|
42
|
+
.optional(),
|
|
43
|
+
|
|
44
|
+
colorMode: z
|
|
45
|
+
.object({
|
|
46
|
+
disableDetect: z.boolean().optional(),
|
|
47
|
+
default: z.string().optional(),
|
|
48
|
+
modes: z.array(z.string()).default(['light', 'dark']).optional(),
|
|
49
|
+
})
|
|
50
|
+
.extend(HideConfig.shape)
|
|
51
|
+
.strict()
|
|
52
|
+
.optional()
|
|
53
|
+
.default({}),
|
|
54
|
+
navigation: z
|
|
55
|
+
.object({
|
|
56
|
+
nextPageLink: z
|
|
57
|
+
.object({ label: z.string().default('Next to {label}') })
|
|
58
|
+
.extend(HideConfig.shape)
|
|
59
|
+
.optional()
|
|
60
|
+
.default({}),
|
|
61
|
+
prevPageLink: z
|
|
62
|
+
.object({ label: z.string().default('Back to {label}') })
|
|
63
|
+
.extend(HideConfig.shape)
|
|
64
|
+
.optional()
|
|
65
|
+
.default({}),
|
|
66
|
+
})
|
|
67
|
+
.strict()
|
|
68
|
+
.optional()
|
|
69
|
+
.default({}),
|
|
70
|
+
markdown: z
|
|
71
|
+
.object({
|
|
72
|
+
frontmatterKeysToResolve: z.array(z.string()).default(['image', 'links']).optional(),
|
|
73
|
+
lastUpdatedBlock: z
|
|
74
|
+
.object({
|
|
75
|
+
format: z.enum(['timeago', 'iso', 'long', 'short']).default('timeago').optional(),
|
|
76
|
+
locale: z.string().default('en-US').optional(),
|
|
77
|
+
})
|
|
78
|
+
.extend(HideConfig.shape)
|
|
79
|
+
.default({})
|
|
80
|
+
.optional(),
|
|
81
|
+
toc: z
|
|
82
|
+
.object({
|
|
83
|
+
header: z.string().default('On this page').optional(),
|
|
84
|
+
maxDepth: z.number().default(3).optional(),
|
|
85
|
+
})
|
|
86
|
+
.extend(HideConfig.shape)
|
|
87
|
+
.optional()
|
|
88
|
+
.default({}),
|
|
89
|
+
editPage: z
|
|
90
|
+
.object({
|
|
91
|
+
baseUrl: z.string().optional(),
|
|
92
|
+
icon: z.string().optional(),
|
|
93
|
+
text: z.string().optional().default('Edit this page'),
|
|
94
|
+
})
|
|
95
|
+
.extend(HideConfig.shape)
|
|
96
|
+
.default({})
|
|
97
|
+
.optional(),
|
|
98
|
+
copyCodeSnippet: z
|
|
99
|
+
.object({
|
|
100
|
+
buttonText: z.string().default('Copy').optional(),
|
|
101
|
+
tooltipText: z.string().default('Copy to clipboard').optional(),
|
|
102
|
+
toasterText: z.string().default('Copied').optional(),
|
|
103
|
+
toasterDuration: z.number().default(1500).optional(),
|
|
104
|
+
})
|
|
105
|
+
.extend(HideConfig.shape)
|
|
106
|
+
.optional()
|
|
107
|
+
.default({}),
|
|
108
|
+
})
|
|
109
|
+
.strict()
|
|
110
|
+
.default({})
|
|
111
|
+
.optional(),
|
|
112
|
+
openapi: z.object({}).passthrough().optional(),
|
|
113
|
+
graphql: z.object({}).passthrough().optional(),
|
|
114
|
+
})
|
|
115
|
+
.passthrough()
|
|
116
|
+
.default({});
|
|
117
|
+
|
|
118
|
+
export type ThemeConfig = z.infer<typeof ThemeConfig>;
|
|
119
|
+
export type ThemeUIConfig = Omit<
|
|
120
|
+
ThemeConfig,
|
|
121
|
+
'navbarItems' | 'footerItems' | 'styles' | 'scripts' | 'postBodyScripts'
|
|
122
|
+
> & {
|
|
123
|
+
navbarItems?: any; // TODO
|
|
124
|
+
footerItems?: any; // TODO
|
|
125
|
+
auth?: {
|
|
126
|
+
// used by portal dev login emulator
|
|
127
|
+
idpIds?: string[];
|
|
128
|
+
devLogin?: boolean;
|
|
129
|
+
};
|
|
130
|
+
};
|
package/src/globalStyle.ts
CHANGED
|
@@ -182,7 +182,7 @@ const headingsTypography = css`
|
|
|
182
182
|
--heading-anchor-color: var(--color-primary-500); // @presenter Color
|
|
183
183
|
--heading-anchor-icon: none;
|
|
184
184
|
|
|
185
|
-
// TODO: implement a theme
|
|
185
|
+
// TODO: implement a theme config for heading-anchor-location: left right
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
188
|
* @tokens Heading level 1
|
|
@@ -316,7 +316,6 @@ const buttons = css`
|
|
|
316
316
|
--button-active-background-color: var(--color-emphasis-600); // @presenter Color
|
|
317
317
|
--button-active-border-color: var(--color-emphasis-600); // @presenter Color
|
|
318
318
|
|
|
319
|
-
/* TODO more styles for disabled state ??? */
|
|
320
319
|
--button-disabled-color: var(--button-color); // @presenter Color
|
|
321
320
|
--button-disabled-background-color: var(--color-emphasis-200); // @presenter Color
|
|
322
321
|
|
|
@@ -495,8 +494,8 @@ const sidebar = css`
|
|
|
495
494
|
--sidebar-item-group-active-text-color: var(--sidebar-item-active-color);
|
|
496
495
|
--sidebar-item-group-active-background-color: var(--sidebar-item-active-background-color);
|
|
497
496
|
|
|
498
|
-
// we need a theme
|
|
499
|
-
// we need another theme
|
|
497
|
+
// we need a theme config for chevron-location: left (default), right-compact, right, none
|
|
498
|
+
// we need another theme config for chevron-style: up-down, down-up, right-down, down-right
|
|
500
499
|
|
|
501
500
|
--sidebar-group-item-chevron-size: var(--sidebar-spacing-unit);
|
|
502
501
|
--sidebar-group-item-chevron-color: var(--sidebar-item-text-color);
|
|
@@ -556,7 +555,6 @@ const admonition = css`
|
|
|
556
555
|
--admonition-padding-vertical: calc(var(--spacing-unit) * 4);
|
|
557
556
|
--admonition-icon-size: 25px;
|
|
558
557
|
|
|
559
|
-
// TODO this is should be changed to --border-radius-lg
|
|
560
558
|
/**
|
|
561
559
|
* @tokens Admonition border
|
|
562
560
|
*/
|
package/src/hooks/index.ts
CHANGED
|
@@ -11,7 +11,9 @@ export function useActiveHeading(
|
|
|
11
11
|
contentElement: HTMLDivElement | null,
|
|
12
12
|
displayedHeaders: Array<string | undefined>,
|
|
13
13
|
): UseActiveHeadingReturnType {
|
|
14
|
-
const [heading, setHeading] = useState<string | undefined>(
|
|
14
|
+
const [heading, setHeading] = useState<string | undefined>(
|
|
15
|
+
displayedHeaders.length > 1 ? displayedHeaders[0] : undefined,
|
|
16
|
+
);
|
|
15
17
|
const [headingElements, setHeadingElements] = useState<HTMLElement[]>([]);
|
|
16
18
|
const headingElementsRef = useRef<HeadingEntry>({});
|
|
17
19
|
|
|
@@ -46,7 +46,7 @@ export function useActiveSectionId(
|
|
|
46
46
|
}, 0);
|
|
47
47
|
|
|
48
48
|
return () => {
|
|
49
|
-
window.removeEventListener('scroll', scrollListener);
|
|
49
|
+
window.removeEventListener('scroll', scrollListener);
|
|
50
50
|
};
|
|
51
51
|
}, [location, navbarHeight, scrollListener]);
|
|
52
52
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useThemeConfig } from '@portal/hooks';
|
|
@@ -11,7 +11,7 @@ function Icon({ mode, className }: ColorModeIconProps) {
|
|
|
11
11
|
case 'dark':
|
|
12
12
|
return (
|
|
13
13
|
<svg
|
|
14
|
-
className={className}
|
|
14
|
+
className={className + ' dark'}
|
|
15
15
|
data-testid="dark"
|
|
16
16
|
viewBox="0 0 16 16"
|
|
17
17
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -23,7 +23,7 @@ function Icon({ mode, className }: ColorModeIconProps) {
|
|
|
23
23
|
return (
|
|
24
24
|
<svg
|
|
25
25
|
data-testid="light"
|
|
26
|
-
className={className}
|
|
26
|
+
className={className + ' light'}
|
|
27
27
|
viewBox="0 0 16 16"
|
|
28
28
|
xmlns="http://www.w3.org/2000/svg"
|
|
29
29
|
>
|
|
@@ -34,7 +34,7 @@ function Icon({ mode, className }: ColorModeIconProps) {
|
|
|
34
34
|
return (
|
|
35
35
|
<svg
|
|
36
36
|
data-testid="custom"
|
|
37
|
-
className={className}
|
|
37
|
+
className={className + (mode ? ' ' + mode : '')}
|
|
38
38
|
viewBox="0 0 16 16"
|
|
39
39
|
xmlns="http://www.w3.org/2000/svg"
|
|
40
40
|
>
|
package/src/index.ts
CHANGED
package/src/mocks/Link.tsx
CHANGED
|
@@ -3,7 +3,14 @@ import React from 'react';
|
|
|
3
3
|
// TODO: use real typings here
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
5
5
|
export function Link(props: any): JSX.Element {
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
active: _,
|
|
8
|
+
httpVerb: _1,
|
|
9
|
+
hasActiveSubItem: _2,
|
|
10
|
+
routeSlug: _3,
|
|
11
|
+
external: _4,
|
|
12
|
+
...filteredProps
|
|
13
|
+
} = props;
|
|
7
14
|
// We omit "active" property to avoid "Warning: Received `false` for a non-boolean attribute `active`."
|
|
8
15
|
return <a href={filteredProps.to} {...filteredProps} />;
|
|
9
16
|
}
|
package/src/mocks/hooks/index.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
name: string;
|
|
3
|
-
settings?: any;
|
|
4
|
-
}
|
|
1
|
+
import type { ThemeUIConfig } from '@theme/config';
|
|
5
2
|
|
|
6
3
|
interface PageLink {
|
|
7
4
|
label: string;
|
|
@@ -9,18 +6,34 @@ interface PageLink {
|
|
|
9
6
|
type: 'link';
|
|
10
7
|
}
|
|
11
8
|
|
|
12
|
-
export function
|
|
9
|
+
export function useThemeConfig<T extends Record<string, unknown>>(): T & ThemeUIConfig {
|
|
13
10
|
return {
|
|
14
|
-
|
|
11
|
+
search: { hide: false, placement: 'navbar' },
|
|
12
|
+
markdown: {
|
|
13
|
+
toc: { maxDepth: 3, header: 'Table of contents', hide: false },
|
|
14
|
+
lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
|
|
15
|
+
copyCodeSnippet: {
|
|
16
|
+
hide: false,
|
|
17
|
+
buttonText: 'Copy',
|
|
18
|
+
tooltipText: 'Copy to clipboard',
|
|
19
|
+
toasterText: 'Copied',
|
|
20
|
+
toasterDuration: 1500,
|
|
21
|
+
},
|
|
22
|
+
editPage: {
|
|
23
|
+
baseUrl: '',
|
|
24
|
+
text: 'Edit this page',
|
|
25
|
+
},
|
|
26
|
+
frontmatterKeysToResolve: ['image', 'links'],
|
|
27
|
+
},
|
|
15
28
|
navigation: {
|
|
16
|
-
nextPageLink: { label: 'next page theme
|
|
17
|
-
prevPageLink: { label: 'prev page theme
|
|
29
|
+
nextPageLink: { label: 'next page theme config label' },
|
|
30
|
+
prevPageLink: { label: 'prev page theme config label' },
|
|
18
31
|
},
|
|
19
32
|
colorMode: {
|
|
20
33
|
modes: ['light', 'dark'],
|
|
21
34
|
default: 'light',
|
|
22
35
|
},
|
|
23
|
-
};
|
|
36
|
+
} as ThemeUIConfig as T & ThemeUIConfig;
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
export function useSidebarSiblingsData(): { nextPage: PageLink | null; prevPage: PageLink | null } {
|
package/src/mocks/types.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
export type ActiveItem<T> = T;
|
|
2
2
|
export type SearchDocument = any;
|
|
3
3
|
export type OperationParameter = any;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
settings: {
|
|
7
|
-
lastUpdatedBlock?: {
|
|
8
|
-
hide?: boolean;
|
|
9
|
-
format?: 'timeago' | 'iso' | 'short' | 'long';
|
|
10
|
-
locale?: string;
|
|
11
|
-
};
|
|
12
|
-
[k: string]: any; // TODO: add missing settings
|
|
13
|
-
};
|
|
14
|
-
}
|
|
4
|
+
|
|
5
|
+
// TODO: get rid of these types
|
package/src/mocks/utils.ts
CHANGED
|
@@ -3,7 +3,7 @@ export function withPathPrefix(link: string): string {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export function timeAgo(lastModified: string | Date): string {
|
|
6
|
-
// should return format(lastModified) in
|
|
6
|
+
// should return format(lastModified) in portal
|
|
7
7
|
const d = new Date(lastModified);
|
|
8
8
|
return `${d.getDate()}-${d.getMonth() + 1}-${d.getFullYear()}`;
|
|
9
9
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export declare const RUNTIME_RESOURCES_DIR = 'runtime';
|
|
2
2
|
export declare const REDOC_OVERVIEW_ITEM_ID = 'overview';
|
|
3
|
-
export declare const PORTAL_CUSTOM_THEMES_FOLDER = '@theme';
|
|
4
3
|
export declare const DEFAULT_THEME_NAME = '@redocly/theme';
|
|
5
4
|
export declare const CUSTOM_MARKDOC_OPTIONS_PATH = 'markdoc';
|
|
6
5
|
export declare const CUSTOM_MARKDOC_TAGS_PATH = 'tags';
|
|
@@ -5,5 +5,5 @@ export function isEmptyArray(items: any): boolean {
|
|
|
5
5
|
|
|
6
6
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
7
7
|
export function isPrimitive(arg: any): boolean {
|
|
8
|
-
return ['string', 'boolean', 'number'].includes(typeof arg);
|
|
8
|
+
return ['string', 'boolean', 'number', 'undefined'].includes(typeof arg);
|
|
9
9
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useDefaultThemeSettings = void 0;
|
|
4
|
-
const hooks_1 = require("../mocks/hooks");
|
|
5
|
-
const constants_1 = require("../mocks/constants");
|
|
6
|
-
function useDefaultThemeSettings() {
|
|
7
|
-
return (0, hooks_1.useThemeSettings)(constants_1.DEFAULT_THEME_NAME);
|
|
8
|
-
}
|
|
9
|
-
exports.useDefaultThemeSettings = useDefaultThemeSettings;
|
|
10
|
-
//# sourceMappingURL=useDefaultThemeSettings.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { useThemeSettings } from '@portal/hooks';
|
|
2
|
-
import { DEFAULT_THEME_NAME } from '@portal/constants';
|
|
3
|
-
import type { RawTheme } from '@portal/types';
|
|
4
|
-
|
|
5
|
-
export function useDefaultThemeSettings(): RawTheme['settings'] {
|
|
6
|
-
return useThemeSettings(DEFAULT_THEME_NAME);
|
|
7
|
-
}
|