@redocly/theme 0.9.13 → 0.9.15

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.
@@ -13,6 +13,10 @@ export const SeparatorItem = styled(MenuItemLabel).attrs(() => ({
13
13
  text-transform: var(--sidebar-item-separator-text-transform);
14
14
  background: var(--sidebar-item-separator-background-color);
15
15
 
16
+ *:not(:first-child) > & {
17
+ margin-top: var(--sidebar-item-separator-offset);
18
+ }
19
+
16
20
  :hover {
17
21
  color: inherit;
18
22
  background-color: inherit;
@@ -5,5 +5,5 @@ export const SeparatorLine = styled.div.attrs(() => ({
5
5
  }))`
6
6
  height: 1px;
7
7
  background-color: var(--sidebar-item-separator-line-color);
8
- margin: var(--sidebar-item-padding-vertical) 0;
8
+ margin: var(--sidebar-item-separator-offset) 0 var(--sidebar-item-padding-vertical) 0;
9
9
  `;
package/src/config.ts CHANGED
@@ -1,234 +1,350 @@
1
- import { z } from 'zod';
1
+ import type { FromSchema } from 'json-schema-to-ts';
2
+ import type { MenuStyle } from './types/portal';
2
3
 
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();
4
+ const logoConfigSchema = {
5
+ type: 'object',
6
+ properties: {
7
+ image: { type: 'string' },
8
+ altText: { type: 'string' },
9
+ link: { type: 'string' },
10
+ favicon: { type: 'string' },
11
+ },
12
+ additionalProperties: false,
13
+ } as const;
11
14
 
12
- const HideConfig = z.object({
13
- hide: z.boolean().optional(),
14
- });
15
+ const hideConfigSchema = {
16
+ type: 'object',
17
+ properties: {
18
+ hide: { type: 'boolean' },
19
+ },
20
+ additionalProperties: false,
21
+ } as const;
15
22
 
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();
23
+ const scriptConfigSchema = {
24
+ type: 'object',
25
+ properties: {
26
+ src: { type: 'string' },
27
+ async: { type: 'boolean' },
28
+ crossorigin: { type: 'string' },
29
+ defer: { type: 'boolean' },
30
+ fetchpriority: { type: 'string' },
31
+ integrity: { type: 'string' },
32
+ module: { type: 'boolean' },
33
+ nomodule: { type: 'boolean' },
34
+ nonce: { type: 'string' },
35
+ referrerpolicy: { type: 'string' },
36
+ type: { type: 'string' },
37
+ },
38
+ required: ['src'],
39
+ additionalProperties: true,
40
+ } as const;
31
41
 
32
- const LinksConfig = z
33
- .object({
34
- href: z.string(),
42
+ const linksConfigSchema = {
43
+ type: 'object',
44
+ properties: {
45
+ href: { type: 'string' },
46
+ as: { type: 'string' },
47
+ crossorigin: { type: 'string' },
48
+ fetchpriority: { type: 'string' },
49
+ hreflang: { type: 'string' },
50
+ imagesizes: { type: 'string' },
51
+ imagesrcset: { type: 'string' },
52
+ integrity: { type: 'string' },
53
+ media: { type: 'string' },
54
+ prefetch: { type: 'string' },
55
+ referrerpolicy: { type: 'string' },
56
+ rel: { type: 'string' },
57
+ sizes: { type: 'string' },
58
+ title: { type: 'string' },
59
+ type: { type: 'string' },
60
+ },
61
+ required: ['href'],
62
+ additionalProperties: true,
63
+ } as const;
35
64
 
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();
65
+ const markdownConfigSchema = {
66
+ type: 'object',
67
+ properties: {
68
+ frontMatterKeysToResolve: {
69
+ type: 'array',
70
+ items: { type: 'string' },
71
+ default: ['image', 'links'],
72
+ },
73
+ lastUpdatedBlock: {
74
+ type: 'object',
75
+ properties: {
76
+ format: {
77
+ type: 'string',
78
+ enum: ['timeago', 'iso', 'long', 'short'],
79
+ default: 'timeago',
80
+ },
81
+ locale: { type: 'string', default: 'en-US' },
82
+ ...hideConfigSchema.properties,
83
+ },
84
+ additionalProperties: false,
85
+ default: {},
86
+ },
87
+ toc: {
88
+ type: 'object',
89
+ properties: {
90
+ header: { type: 'string', default: 'On this page' },
91
+ depth: { type: 'number', default: 3 },
92
+ ...hideConfigSchema.properties,
93
+ },
94
+ additionalProperties: false,
95
+ default: {},
96
+ },
97
+ editPage: {
98
+ type: 'object',
99
+ properties: {
100
+ baseUrl: { type: 'string' },
101
+ icon: { type: 'string' },
102
+ text: { type: 'string', default: 'Edit this page' },
103
+ ...hideConfigSchema.properties,
104
+ },
105
+ additionalProperties: false,
106
+ default: {},
107
+ },
108
+ },
109
+ additionalProperties: false,
110
+ default: {},
111
+ } as const;
52
112
 
53
- const MarkdownConfig = z
54
- .object({
55
- frontMatterKeysToResolve: z.array(z.string()).default(['image', 'links']).optional(),
56
- lastUpdatedBlock: z
57
- .object({
58
- format: z.enum(['timeago', 'iso', 'long', 'short']).default('timeago').optional(),
59
- locale: z.string().default('en-US').optional(),
60
- })
61
- .extend(HideConfig.shape)
62
- .default({})
63
- .optional(),
64
- toc: z
65
- .object({
66
- header: z.string().default('On this page').optional(),
67
- depth: z.number().default(3).optional(),
68
- })
69
- .extend(HideConfig.shape)
70
- .optional()
71
- .default({}),
72
- editPage: z
73
- .object({
74
- baseUrl: z.string().optional(),
75
- icon: z.string().optional(),
76
- text: z.string().optional().default('Edit this page'),
77
- })
78
- .extend(HideConfig.shape)
79
- .default({})
80
- .optional(),
81
- })
82
- .strict()
83
- .default({});
113
+ const navItemSchema = {
114
+ type: 'object',
115
+ properties: {
116
+ page: { type: 'string' },
117
+ directory: { type: 'string' },
118
+ group: { type: 'string' },
119
+ label: { type: 'string' },
120
+ separator: { type: 'string' },
121
+ separatorLine: { type: 'boolean' },
122
+ version: { type: 'string' },
123
+ menuStyle: { type: 'string', enum: ['drilldown' as MenuStyle] },
124
+ expanded: { type: 'string', const: 'always' },
125
+ selectFirstItemOnExpand: { type: 'boolean' },
126
+ flatten: { type: 'boolean' },
127
+ },
128
+ } as const;
84
129
 
85
- export const ThemeConfig = z
86
- .object({
87
- imports: z.array(z.string()).default([]).optional(),
130
+ const navItemsSchema = {
131
+ type: 'array',
132
+ items: {
133
+ ...navItemSchema,
134
+ properties: {
135
+ ...navItemSchema.properties,
136
+ items: { type: 'array', items: navItemSchema },
137
+ },
138
+ },
139
+ } as const;
88
140
 
89
- logo: LogoConfig.optional(),
90
- navbar: z
91
- .object({
92
- items: z.array(z.any()).optional(), // todo: think about validation here
93
- })
94
- .extend(HideConfig.shape)
95
- .strict()
96
- .optional(),
141
+ export const themeConfigSchema = {
142
+ type: 'object',
143
+ properties: {
144
+ imports: {
145
+ type: 'array',
146
+ items: { type: 'string' },
147
+ default: [],
148
+ },
149
+ logo: logoConfigSchema,
150
+ navbar: {
151
+ type: 'object',
152
+ properties: {
153
+ items: navItemsSchema,
154
+ ...hideConfigSchema.properties,
155
+ },
156
+ additionalProperties: false,
157
+ },
158
+ footer: {
159
+ type: 'object',
160
+ properties: {
161
+ items: navItemsSchema,
162
+ copyrightText: { type: 'string' },
163
+ ...hideConfigSchema.properties,
164
+ },
165
+ additionalProperties: false,
166
+ },
167
+ sidebar: hideConfigSchema,
168
+ scripts: {
169
+ type: 'object',
170
+ properties: {
171
+ head: { type: 'array', items: scriptConfigSchema },
172
+ body: { type: 'array', items: scriptConfigSchema },
173
+ },
174
+ additionalProperties: false,
175
+ },
176
+ links: { type: 'array', items: linksConfigSchema },
177
+ feedback: {
178
+ type: 'object',
179
+ properties: {
180
+ hide: {
181
+ type: 'boolean',
182
+ default: false,
183
+ },
184
+ type: {
185
+ type: 'string',
186
+ enum: ['rating', 'sentiment', 'comment', 'reasons'],
187
+ default: 'sentiment',
188
+ },
189
+ settings: {
190
+ type: 'object',
191
+ properties: {
192
+ label: { type: 'string' },
193
+ submitText: { type: 'string' },
194
+ max: { type: 'number' },
195
+ buttonText: { type: 'string' },
196
+ multi: { type: 'boolean' },
197
+ items: { type: 'array', items: { type: 'string' }, minItems: 1 },
198
+ reasons: {
199
+ type: 'object',
200
+ properties: {
201
+ enable: { type: 'boolean', default: true },
202
+ multi: { type: 'boolean' },
203
+ label: { type: 'string' },
204
+ items: { type: 'array', items: { type: 'string' } },
205
+ },
206
+ additionalProperties: false,
207
+ },
208
+ comment: {
209
+ type: 'object',
210
+ properties: {
211
+ enable: { type: 'boolean', default: true },
212
+ label: { type: 'string' },
213
+ likeLabel: { type: 'string' },
214
+ dislikeLabel: { type: 'string' },
215
+ },
216
+ additionalProperties: false,
217
+ },
218
+ },
219
+ additionalProperties: false,
220
+ ...hideConfigSchema.properties,
221
+ },
222
+ },
223
+ additionalProperties: false,
224
+ default: {},
225
+ },
226
+ search: {
227
+ type: 'object',
228
+ properties: {
229
+ placement: {
230
+ type: 'string',
231
+ default: 'navbar',
232
+ },
233
+ shortcuts: {
234
+ type: 'array',
235
+ items: { type: 'string' },
236
+ default: ['/'],
237
+ },
238
+ ...hideConfigSchema.properties,
239
+ },
240
+ additionalProperties: false,
241
+ default: {},
242
+ },
243
+ colorMode: {
244
+ type: 'object',
245
+ properties: {
246
+ ignoreDetection: { type: 'boolean' },
247
+ modes: {
248
+ type: 'array',
249
+ items: { type: 'string' },
250
+ default: ['light', 'dark'],
251
+ },
252
+ ...hideConfigSchema.properties,
253
+ },
254
+ additionalProperties: false,
255
+ default: {},
256
+ },
257
+ navigation: {
258
+ type: 'object',
259
+ properties: {
260
+ nextButton: {
261
+ type: 'object',
262
+ properties: {
263
+ text: { type: 'string', default: 'Next to {label}' },
264
+ ...hideConfigSchema.properties,
265
+ },
266
+ additionalProperties: false,
267
+ default: {},
268
+ },
269
+ previousButton: {
270
+ type: 'object',
271
+ properties: {
272
+ text: { type: 'string', default: 'Back to {label}' },
273
+ ...hideConfigSchema.properties,
274
+ },
275
+ additionalProperties: false,
276
+ default: {},
277
+ },
278
+ },
279
+ additionalProperties: false,
280
+ default: {},
281
+ },
282
+ codeSnippet: {
283
+ type: 'object',
284
+ properties: {
285
+ copy: {
286
+ type: 'object',
287
+ properties: {
288
+ buttonText: { type: 'string', default: 'Copy' },
289
+ tooltipText: { type: 'string', default: 'Copy to clipboard' },
290
+ toasterText: { type: 'string', default: 'Copied!' },
291
+ toasterDuration: { type: 'number', default: 1500 },
292
+ ...hideConfigSchema.properties,
293
+ },
294
+ additionalProperties: false,
295
+ default: {},
296
+ },
297
+ report: {
298
+ type: 'object',
299
+ properties: {
300
+ tooltipText: { type: 'string', default: 'Report a problem' },
301
+ label: { type: 'string' },
302
+ ...hideConfigSchema.properties,
303
+ },
304
+ additionalProperties: false,
305
+ default: { hide: true },
306
+ },
307
+ },
308
+ additionalProperties: false,
309
+ default: {},
310
+ },
311
+ markdown: markdownConfigSchema,
312
+ openapi: { type: 'object', additionalProperties: true },
313
+ graphql: { type: 'object', additionalProperties: true },
314
+ analytics: {
315
+ type: ['array', 'boolean', 'number', 'object', 'string'],
316
+ },
317
+ userProfile: {
318
+ type: 'object',
319
+ properties: {
320
+ loginLabel: { type: 'string', default: 'Login' },
321
+ logoutLabel: { type: 'string', default: 'Logout' },
322
+ menu: {
323
+ type: 'array',
324
+ items: {
325
+ type: 'object',
326
+ properties: {
327
+ label: { type: 'string' },
328
+ external: { type: 'boolean' },
329
+ link: { type: 'string' },
330
+ separatorLine: { type: 'boolean' },
331
+ },
332
+ additionalProperties: true,
333
+ },
334
+ default: [],
335
+ },
336
+ ...hideConfigSchema.properties,
337
+ },
338
+ additionalProperties: false,
339
+ default: {},
340
+ },
341
+ },
342
+ additionalProperties: true,
343
+ default: {},
344
+ } as const;
97
345
 
98
- footer: z
99
- .object({
100
- items: z.array(z.any()).optional(), // todo: think about validation here
101
- copyrightText: z.string().optional(),
102
- })
103
- .extend(HideConfig.shape)
104
- .strict()
105
- .optional(),
106
- sidebar: HideConfig.strict().optional(),
107
-
108
- scripts: z
109
- .object({
110
- head: z.array(ScriptConfig).optional(),
111
- body: z.array(ScriptConfig).optional(),
112
- })
113
- .optional(),
114
- links: z.array(LinksConfig).optional(),
115
-
116
- feedback: z
117
- .object({
118
- type: z.enum(['rating', 'sentiment', 'comment', 'reasons']).default('sentiment'),
119
- settings: z
120
- .object({
121
- label: z.string().optional(),
122
- submitText: z.string().optional(),
123
- max: z.number().optional(),
124
- buttonText: z.string().optional(),
125
- multi: z.boolean().optional(),
126
- items: z.array(z.string()).min(1).optional(),
127
- reasons: z
128
- .object({
129
- enable: z.boolean().default(true),
130
- multi: z.boolean().optional(),
131
- label: z.string().optional(),
132
- items: z.array(z.string()),
133
- })
134
- .optional(),
135
- comment: z
136
- .object({
137
- enable: z.boolean().default(true),
138
- label: z.string().optional(),
139
- likeLabel: z.string().optional(),
140
- dislikeLabel: z.string().optional(),
141
- })
142
- .optional(),
143
- })
144
- .optional(),
145
- })
146
- .extend(HideConfig.shape)
147
- .strict()
148
- .default({})
149
- .optional(),
150
-
151
- search: z
152
- .object({
153
- placement: z.string().default('navbar').optional(),
154
- shortcuts: z.array(z.string()).default(['/']).optional(),
155
- })
156
- .extend(HideConfig.shape)
157
- .strict()
158
- .default({})
159
- .optional(),
160
-
161
- colorMode: z
162
- .object({
163
- ignoreDetection: z.boolean().optional(),
164
- modes: z.array(z.string()).default(['light', 'dark']).optional(),
165
- })
166
- .extend(HideConfig.shape)
167
- .strict()
168
- .optional()
169
- .default({}),
170
- navigation: z
171
- .object({
172
- nextButton: z
173
- .object({ text: z.string().default('Next to {label}') })
174
- .extend(HideConfig.shape)
175
- .optional()
176
- .default({}),
177
- previousButton: z
178
- .object({ text: z.string().default('Back to {label}') })
179
- .extend(HideConfig.shape)
180
- .optional()
181
- .default({}),
182
- })
183
- .strict()
184
- .optional()
185
- .default({}),
186
- codeSnippet: z
187
- .object({
188
- copy: z
189
- .object({
190
- buttonText: z.string().default('Copy').optional(),
191
- tooltipText: z.string().default('Copy to clipboard').optional(),
192
- toasterText: z.string().default('Copied!').optional(),
193
- toasterDuration: z.number().default(1500).optional(),
194
- })
195
- .extend(HideConfig.shape)
196
- .optional()
197
- .default({}),
198
- report: z
199
- .object({
200
- tooltipText: z.string().default('Report a problem').optional(),
201
- label: z.string().optional(),
202
- })
203
- .extend(HideConfig.shape)
204
- .optional()
205
- .default({ hide: true }),
206
- })
207
- .strict()
208
- .default({})
209
- .optional(),
210
- markdown: MarkdownConfig.optional(),
211
- openapi: z.object({}).passthrough().optional(),
212
- graphql: z.object({}).passthrough().optional(),
213
- analytics: z.any().optional(),
214
- userProfile: z
215
- .object({
216
- loginLabel: z.string().default('Login').optional(),
217
- logoutLabel: z.string().default('Logout').optional(),
218
- menu: z.array(z.any()).optional(), // should be same as navbar items type
219
- })
220
- .extend(HideConfig.shape)
221
- .optional()
222
- .default({}),
223
- })
224
- .passthrough()
225
- .default({});
226
-
227
- export type ThemeConfig = z.infer<typeof ThemeConfig>;
228
- // export type ThemeUIConfig = Omit<ThemeConfig, 'navbar' | 'footer' | 'links' | 'scripts'> & {
346
+ export type ThemeConfig = FromSchema<typeof themeConfigSchema>;
229
347
  export type ThemeUIConfig = ThemeConfig & {
230
- navbar?: any; // TODO
231
- footer?: any; // TODO
232
348
  auth?: {
233
349
  // used by portal dev login emulator
234
350
  idpsInfo?: {
@@ -243,4 +359,4 @@ export type ThemeUIConfig = ThemeConfig & {
243
359
  };
244
360
  };
245
361
 
246
- export type MarkdownConfig = z.infer<typeof MarkdownConfig>;
362
+ export type MarkdownConfig = FromSchema<typeof markdownConfigSchema>;
@@ -510,6 +510,7 @@ const sidebar = css`
510
510
  --sidebar-item-separator-text-color: var(--sidebar-item-text-color);
511
511
  --sidebar-item-separator-background-color: var(--sidebar-background-color);
512
512
  --sidebar-item-separator-line-color: var(--border-color); // but has line color
513
+ --sidebar-item-separator-offset: calc(var(--sidebar-spacing-unit) * 2);
513
514
 
514
515
  /**
515
516
  * @tokens Sidebar back button
@@ -567,7 +568,7 @@ const admonition = css`
567
568
  * @tokens Admonition type info
568
569
  */
569
570
 
570
- --admonition-info-background-color: var(--color-emphasis-200); // @presenter Color
571
+ --admonition-info-background-color: var(--color-secondary-200); // @presenter Color
571
572
  --admonition-info-heading-text-color: var(--text-color); // @presenter Color
572
573
  --admonition-info-text-color: var(--text-color); // @presenter Color
573
574
  --admonition-info-icon-color: var(--color-accent-900); // @presenter Color
@@ -1967,7 +1968,7 @@ const pages = css`
1967
1968
  const userProfile = css`
1968
1969
 
1969
1970
  /**
1970
- * @tokens User Profile
1971
+ * @tokens User Profile
1971
1972
  */
1972
1973
 
1973
1974
  --profile-name-font-family: var(--navbar-item-font-family); // @presenter FontFamily
@@ -1975,12 +1976,12 @@ const userProfile = css`
1975
1976
  --profile-name-font-weight: var(--font-weight-regular); // @presenter FontWeight
1976
1977
  --profile-name-line-height: var(--line-height-base); // @presenter LineHeight
1977
1978
  --profile-name-text-color: var(--navbar-text-color); // @presenter Color
1978
-
1979
+
1979
1980
  --profile-name-padding-horizontal: 0; // @presenter Spacing
1980
1981
  --profile-name-padding-vertical: 0; // @presenter Spacing
1981
1982
  --profile-name-margin-horizontal: 0; // @presenter Spacing
1982
1983
 
1983
- --profile-avatar-width: 40px;
1984
+ --profile-avatar-width: 40px;
1984
1985
  --profile-avatar-height: 40px;
1985
1986
  --profile-avatar-border-radius: 50%; // @presenter BorderRadius
1986
1987
 
@@ -2008,7 +2009,7 @@ const userProfile = css`
2008
2009
  --profile-menu-item-font-weight: var(--font-weight-regular); // @presenter FontWeight
2009
2010
  --profile-menu-item-line-height: var(--line-height-base); // @presenter LineHeight
2010
2011
  --profile-menu-item-text-align: left;
2011
-
2012
+
2012
2013
  --profile-menu-item-padding-horizontal: 15px; // @presenter Spacing
2013
2014
  --profile-menu-item-padding-vertical: 20px; // @presenter Spacing
2014
2015
 
@@ -2022,7 +2023,7 @@ const userProfile = css`
2022
2023
  --profile-menu-item-separator-line-color: var(--border-color); // @presenter Color
2023
2024
 
2024
2025
  // @tokens End
2025
-
2026
+
2026
2027
  `;
2027
2028
 
2028
2029
  const modal = css`
@@ -34,10 +34,9 @@ const DropDownHeader = styled.div`
34
34
  display: flex;
35
35
  justify-content: space-between;
36
36
  align-items: center;
37
- background: #fff;
38
37
  padding: 8px 10px;
39
38
  border-radius: 4px;
40
- border: 1px solid #e4e7eb;
39
+ border: 1px solid var(--border-color);
41
40
  font-weight: 600;
42
41
  color: var(--text-color);
43
42
  background: var(--color-secondary-200);
@@ -65,16 +64,16 @@ const IconWrapper = styled.span`
65
64
  `;
66
65
 
67
66
  const ListItem = styled.div`
68
- background-color: #fff;
67
+ background-color: var(--color-secondary-200);
69
68
  padding: 0.4em 10px;
70
69
  font-size: 1em;
71
70
  color: var(--text-color);
72
71
  cursor: pointer;
73
72
  &:hover {
74
- background-color: rgba(38, 50, 56, 0.12);
73
+ background-color: var(--color-secondary-300);
75
74
  }
76
75
  &.active {
77
- background-color: rgba(0, 0, 0, 0.05);
76
+ background-color: var(--color-secondary-300);
78
77
  }
79
78
  `;
80
79