@redocly/theme 0.71.0-next.4 → 0.71.0-next.6

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.
Files changed (80) hide show
  1. package/lib/components/Buttons/MobileMenuButton.d.ts +8 -0
  2. package/lib/components/Buttons/MobileMenuButton.js +58 -0
  3. package/lib/components/Catalog/CatalogFilter/CatalogFilter.js +1 -1
  4. package/lib/components/Feedback/Mood.js +1 -1
  5. package/lib/components/Feedback/Rating.js +1 -1
  6. package/lib/components/Feedback/Scale.js +1 -1
  7. package/lib/components/Feedback/Sentiment.js +1 -1
  8. package/lib/components/Filter/Filter.js +1 -1
  9. package/lib/components/MCP/McpConnectionTabs.d.ts +1 -1
  10. package/lib/components/MCP/McpConnectionTabs.js +24 -1
  11. package/lib/components/MissingTranslationNotice/MissingTranslationNotice.d.ts +11 -0
  12. package/lib/components/MissingTranslationNotice/MissingTranslationNotice.js +83 -0
  13. package/lib/components/MissingTranslationNotice/variables.d.ts +1 -0
  14. package/lib/components/MissingTranslationNotice/variables.dark.d.ts +1 -0
  15. package/lib/components/MissingTranslationNotice/variables.dark.js +10 -0
  16. package/lib/components/MissingTranslationNotice/variables.js +29 -0
  17. package/lib/components/Navbar/Navbar.js +10 -18
  18. package/lib/components/PageActions/PageActions.js +1 -0
  19. package/lib/components/Select/Select.js +1 -2
  20. package/lib/core/hooks/use-active-section-id.js +8 -0
  21. package/lib/core/hooks/use-focus-trap.js +6 -5
  22. package/lib/core/hooks/use-page-actions.d.ts +1 -1
  23. package/lib/core/hooks/use-page-actions.js +47 -35
  24. package/lib/core/styles/dark.js +4 -2
  25. package/lib/core/styles/global.js +70 -68
  26. package/lib/core/types/hooks.d.ts +2 -5
  27. package/lib/core/types/l10n.d.ts +2 -1
  28. package/lib/core/utils/get-ai-prompt-link.d.ts +3 -1
  29. package/lib/core/utils/get-ai-prompt-link.js +1 -0
  30. package/lib/core/utils/mcp.d.ts +1 -0
  31. package/lib/core/utils/mcp.js +4 -0
  32. package/lib/icons/GrokIcon/GrokIcon.d.ts +25 -0
  33. package/lib/icons/GrokIcon/GrokIcon.js +23 -0
  34. package/lib/icons/McpIcon/McpIcon.d.ts +25 -0
  35. package/lib/icons/McpIcon/McpIcon.js +24 -0
  36. package/lib/icons/TranslateIcon/TranslateIcon.d.ts +25 -0
  37. package/lib/icons/TranslateIcon/TranslateIcon.js +21 -0
  38. package/lib/index.d.ts +3 -0
  39. package/lib/index.js +4 -0
  40. package/lib/layouts/CodeWalkthroughLayout.js +9 -1
  41. package/lib/layouts/DocumentationLayout.js +2 -0
  42. package/lib/markdoc/default.d.ts +2 -0
  43. package/lib/markdoc/default.js +2 -0
  44. package/package.json +4 -3
  45. package/src/components/Buttons/MobileMenuButton.tsx +45 -0
  46. package/src/components/Catalog/CatalogFilter/CatalogFilter.tsx +2 -2
  47. package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +1 -1
  48. package/src/components/Feedback/Feedback.tsx +1 -3
  49. package/src/components/Feedback/Mood.tsx +1 -1
  50. package/src/components/Feedback/Rating.tsx +1 -1
  51. package/src/components/Feedback/Scale.tsx +1 -1
  52. package/src/components/Feedback/Sentiment.tsx +1 -1
  53. package/src/components/Filter/Filter.tsx +2 -2
  54. package/src/components/MCP/McpConnectionTabs.tsx +56 -2
  55. package/src/components/MissingTranslationNotice/MissingTranslationNotice.tsx +113 -0
  56. package/src/components/MissingTranslationNotice/variables.dark.ts +7 -0
  57. package/src/components/MissingTranslationNotice/variables.ts +26 -0
  58. package/src/components/Navbar/Navbar.tsx +15 -30
  59. package/src/components/PageActions/PageActions.tsx +1 -0
  60. package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +1 -1
  61. package/src/components/Select/Select.tsx +1 -2
  62. package/src/core/hooks/__mocks__/use-theme-hooks.ts +1 -1
  63. package/src/core/hooks/use-active-section-id.ts +13 -0
  64. package/src/core/hooks/use-codeblock-tabs-controls.ts +1 -1
  65. package/src/core/hooks/use-focus-trap.ts +8 -7
  66. package/src/core/hooks/use-page-actions.ts +73 -43
  67. package/src/core/styles/dark.ts +2 -0
  68. package/src/core/styles/global.ts +2 -0
  69. package/src/core/types/hooks.ts +2 -2
  70. package/src/core/types/l10n.ts +15 -2
  71. package/src/core/utils/get-ai-prompt-link.ts +5 -2
  72. package/src/core/utils/mcp.ts +4 -0
  73. package/src/icons/GrokIcon/GrokIcon.tsx +24 -0
  74. package/src/icons/McpIcon/McpIcon.tsx +37 -0
  75. package/src/icons/TranslateIcon/TranslateIcon.tsx +22 -0
  76. package/src/index.ts +4 -0
  77. package/src/layouts/CodeWalkthroughLayout.tsx +11 -1
  78. package/src/layouts/DocumentationLayout.tsx +2 -0
  79. package/src/markdoc/default.ts +2 -0
  80. package/src/markdoc/tags/code-walkthrough.ts +1 -1
@@ -2,19 +2,22 @@ import { useEffect } from 'react';
2
2
 
3
3
  import type { RefObject } from 'react';
4
4
 
5
+ const FOCUSABLE_SELECTOR =
6
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
7
+
5
8
  export function useFocusTrap(containerRef: RefObject<HTMLElement | null>): void {
6
9
  useEffect(() => {
7
10
  const trapElement = containerRef.current;
8
11
 
9
12
  if (!trapElement) return;
10
13
 
11
- const focusableElements = trapElement.querySelectorAll<HTMLElement>(
12
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
13
- );
14
- const firstElement = focusableElements[0];
14
+ const getFocusableElements = () =>
15
+ trapElement.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);
15
16
 
16
17
  const handleKeyDown = (event: KeyboardEvent) => {
17
18
  if (event.key === 'Tab') {
19
+ const focusableElements = getFocusableElements();
20
+ const firstElement = focusableElements[0];
18
21
  const lastElement = focusableElements[focusableElements.length - 1];
19
22
  if (event.shiftKey && document.activeElement === firstElement) {
20
23
  lastElement?.focus();
@@ -28,9 +31,7 @@ export function useFocusTrap(containerRef: RefObject<HTMLElement | null>): void
28
31
 
29
32
  trapElement.addEventListener('keydown', handleKeyDown);
30
33
 
31
- if (firstElement) {
32
- firstElement.focus();
33
- }
34
+ getFocusableElements()[0]?.focus();
34
35
 
35
36
  return () => {
36
37
  trapElement.removeEventListener('keydown', handleKeyDown);
@@ -1,4 +1,5 @@
1
1
  import { useMemo, useCallback } from 'react';
2
+ import type { ComponentType } from 'react';
2
3
 
3
4
  import type { PageProps, UiAccessibleConfig } from '@redocly/config';
4
5
  import type { PageAction, MCPClientType, McpConnectionParams } from '../types';
@@ -6,6 +7,8 @@ import type { PageAction, MCPClientType, McpConnectionParams } from '../types';
6
7
  import { CopyIcon } from '@redocly/theme/icons/CopyIcon/CopyIcon';
7
8
  import { ChatGptIcon } from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
8
9
  import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
10
+ import { GrokIcon } from '@redocly/theme/icons/GrokIcon/GrokIcon';
11
+ import { McpIcon } from '@redocly/theme/icons/McpIcon/McpIcon';
9
12
  import { MarkdownFullIcon } from '@redocly/theme/icons/MarkdownFullIcon/MarkdownFullIcon';
10
13
  import { VSCodeIcon } from '@redocly/theme/icons/VSCodeIcon/VSCodeIcon';
11
14
  import { CursorIcon } from '@redocly/theme/icons/CursorIcon/CursorIcon';
@@ -30,9 +33,11 @@ const DEFAULT_ENABLED_ACTIONS = [
30
33
  'view',
31
34
  'chatgpt',
32
35
  'claude',
33
- 'docs-mcp-cursor',
34
- 'docs-mcp-vscode',
36
+ 'grok',
35
37
  'docs-mcp-claude',
38
+ 'docs-mcp-vscode',
39
+ 'docs-mcp-cursor',
40
+ 'copy-mcp-url',
36
41
  ] as const;
37
42
 
38
43
  export type PageActionType =
@@ -40,9 +45,11 @@ export type PageActionType =
40
45
  | 'view'
41
46
  | 'chatgpt'
42
47
  | 'claude'
43
- | 'docs-mcp-cursor'
44
- | 'docs-mcp-vscode'
48
+ | 'grok'
45
49
  | 'docs-mcp-claude'
50
+ | 'docs-mcp-vscode'
51
+ | 'docs-mcp-cursor'
52
+ | 'copy-mcp-url'
46
53
  // Used in OpenAPI docs x-mcp
47
54
  | 'mcp-cursor'
48
55
  | 'mcp-vscode';
@@ -115,10 +122,52 @@ export function usePageActions(
115
122
  : combineUrls(origin, removeTrailingSlash(pathname) + '.md');
116
123
  const externalAiPrompt = `Read ${mdPageUrl} and answer questions based on the content.`;
117
124
 
125
+ const createAiPromptAction =
126
+ (
127
+ target: 'chatgpt' | 'claude' | 'grok',
128
+ iconComponent: ComponentType,
129
+ texts: Pick<PageAction, 'buttonText' | 'title' | 'description'>,
130
+ ) =>
131
+ (): PageAction => {
132
+ const link = getAiPromptLink(target, externalAiPrompt);
133
+ return {
134
+ ...texts,
135
+ iconComponent,
136
+ link,
137
+ onClick: () => {
138
+ telemetry.sendPageActionsClickedMessage([
139
+ {
140
+ ...getBaseDataAttributes('pageActions', 'button'),
141
+ actionType: target,
142
+ },
143
+ ]);
144
+ window.location.href = link;
145
+ },
146
+ };
147
+ };
148
+
118
149
  const actionHandlers: Record<PageActionType, () => PageAction> = {
119
150
  'docs-mcp-cursor': createMCPHandler('cursor', false),
120
151
  'docs-mcp-vscode': createMCPHandler('vscode', false),
121
152
  'docs-mcp-claude': createMCPHandler('claude', false),
153
+ 'copy-mcp-url': () => ({
154
+ buttonText: translate('page.actions.connectMcp.copyUrl', 'Copy MCP server URL'),
155
+ title: translate('page.actions.connectMcp.copyUrl', 'Copy MCP server URL'),
156
+ description: translate(
157
+ 'page.actions.connectMcp.copyUrlDescription',
158
+ 'Copy the MCP server URL to the clipboard',
159
+ ),
160
+ iconComponent: McpIcon,
161
+ onClick: () => {
162
+ ClipboardService.copyCustom(mcpConfig.serverUrl);
163
+ telemetry.sendPageActionsClickedMessage([
164
+ {
165
+ ...getBaseDataAttributes('pageActions', 'button'),
166
+ actionType: 'copy-mcp-url',
167
+ },
168
+ ]);
169
+ },
170
+ }),
122
171
  'mcp-cursor': createMCPHandler('cursor', true),
123
172
  'mcp-vscode': createMCPHandler('vscode', true),
124
173
 
@@ -163,45 +212,23 @@ export function usePageActions(
163
212
  },
164
213
  }),
165
214
 
166
- chatgpt: () => {
167
- const link = getAiPromptLink('chatgpt', externalAiPrompt);
168
- return {
169
- buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
170
- title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
171
- description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'),
172
- iconComponent: ChatGptIcon,
173
- link,
174
- onClick: () => {
175
- telemetry.sendPageActionsClickedMessage([
176
- {
177
- ...getBaseDataAttributes('pageActions', 'button'),
178
- actionType: 'chatgpt',
179
- },
180
- ]);
181
- window.location.href = link;
182
- },
183
- };
184
- },
215
+ chatgpt: createAiPromptAction('chatgpt', ChatGptIcon, {
216
+ buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
217
+ title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
218
+ description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'),
219
+ }),
185
220
 
186
- claude: () => {
187
- const link = getAiPromptLink('claude', externalAiPrompt);
188
- return {
189
- buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
190
- title: translate('page.actions.claudeTitle', 'Open in Claude'),
191
- description: translate('page.actions.claudeDescription', 'Get insights from Claude'),
192
- iconComponent: ClaudeIcon,
193
- link,
194
- onClick: () => {
195
- telemetry.sendPageActionsClickedMessage([
196
- {
197
- ...getBaseDataAttributes('pageActions', 'button'),
198
- actionType: 'claude',
199
- },
200
- ]);
201
- window.location.href = link;
202
- },
203
- };
204
- },
221
+ claude: createAiPromptAction('claude', ClaudeIcon, {
222
+ buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
223
+ title: translate('page.actions.claudeTitle', 'Open in Claude'),
224
+ description: translate('page.actions.claudeDescription', 'Get insights from Claude'),
225
+ }),
226
+
227
+ grok: createAiPromptAction('grok', GrokIcon, {
228
+ buttonText: translate('page.actions.grokButtonText', 'Open in Grok'),
229
+ title: translate('page.actions.grokTitle', 'Open in Grok'),
230
+ description: translate('page.actions.grokDescription', 'Get insights from Grok'),
231
+ }),
205
232
  };
206
233
 
207
234
  return (themeConfig.navigation?.actions?.items || actions || DEFAULT_ENABLED_ACTIONS)
@@ -215,6 +242,7 @@ export function usePageActions(
215
242
  isPublic,
216
243
  mcpUrl,
217
244
  mcpConfig.isMcpDisabled,
245
+ mcpConfig.serverUrl,
218
246
  pageSlug,
219
247
  actions,
220
248
  translate,
@@ -311,7 +339,7 @@ function shouldHideAction(
311
339
  return true;
312
340
  }
313
341
 
314
- const actionDependsOnLlmsTxt = ['view', 'copy', 'chatgpt', 'claude'].includes(action);
342
+ const actionDependsOnLlmsTxt = ['view', 'copy', 'chatgpt', 'claude', 'grok'].includes(action);
315
343
 
316
344
  if (actionDependsOnLlmsTxt) {
317
345
  // Can't use any actions if search is globally disabled (markdown files are not generated)
@@ -345,10 +373,12 @@ function shouldHideActionByType(
345
373
  switch (action) {
346
374
  case 'chatgpt':
347
375
  case 'claude':
376
+ case 'grok':
348
377
  return !isPublic;
349
378
  case 'docs-mcp-cursor':
350
379
  case 'docs-mcp-vscode':
351
380
  case 'docs-mcp-claude':
381
+ case 'copy-mcp-url':
352
382
  return Boolean(mcpUrl) || isMcpDisabled;
353
383
  case 'mcp-cursor':
354
384
  case 'mcp-vscode':
@@ -16,6 +16,7 @@ import { pageActionsDarkMode } from '@redocly/theme/components/PageActions/varia
16
16
  import { tooltipDarkMode } from '@redocly/theme/components/Tooltip/variables.dark';
17
17
  import { bannerDarkMode } from '@redocly/theme/components/Banner/variables.dark';
18
18
  import { admonitionDarkMode } from '@redocly/theme/components/Admonition/variables.dark';
19
+ import { missingTranslationNoticeDarkMode } from '@redocly/theme/components/MissingTranslationNotice/variables.dark';
19
20
  import { codeBlockDarkMode } from '@redocly/theme/components/CodeBlock/variables.dark';
20
21
 
21
22
  import { activeBrandPaletteDark } from './palette.dark';
@@ -363,6 +364,7 @@ export const darkMode = css`
363
364
  ${tooltipDarkMode}
364
365
  ${bannerDarkMode}
365
366
  ${admonitionDarkMode}
367
+ ${missingTranslationNoticeDarkMode}
366
368
  ${badgesDarkMode}
367
369
  ${numberedListDarkMode}
368
370
  ${activeBrandPaletteDark}
@@ -18,6 +18,7 @@ import { dropdown } from '@redocly/theme/components/Dropdown/variables';
18
18
  import { tooltip } from '@redocly/theme/components/Tooltip/variables';
19
19
  import { checkbox } from '@redocly/theme/icons/CheckboxIcon/variables';
20
20
  import { admonition } from '@redocly/theme/components/Admonition/variables';
21
+ import { missingTranslationNotice } from '@redocly/theme/components/MissingTranslationNotice/variables';
21
22
  import { footer } from '@redocly/theme/components/Footer/variables';
22
23
  import { button } from '@redocly/theme/components/Button/variables';
23
24
  import { aiAssistantButton, connectMcpButton } from '@redocly/theme/components/Buttons/variables';
@@ -1295,6 +1296,7 @@ const replay = css`
1295
1296
  export const tokens = css`
1296
1297
  ${accordion}
1297
1298
  ${admonition}
1299
+ ${missingTranslationNotice}
1298
1300
  ${apiReferenceDocs}
1299
1301
  ${apiReferencePanels}
1300
1302
  ${badges}
@@ -39,7 +39,7 @@ import type {
39
39
  ToolCall,
40
40
  } from './search';
41
41
  import type { SubmitFeedbackParams } from './feedback';
42
- import type { TFunction } from './l10n';
42
+ import type { Locale, TFunction } from './l10n';
43
43
  import type { BreadcrumbItem } from './breadcrumb';
44
44
  import type { UseConsentResult } from './consent';
45
45
 
@@ -234,5 +234,5 @@ export type ThemeHooks = {
234
234
  export type L10nConfig = {
235
235
  currentLocale: string;
236
236
  defaultLocale: string;
237
- locales: { code: string; name: string }[];
237
+ locales: Locale[];
238
238
  };
@@ -157,11 +157,16 @@ export type TranslationKey =
157
157
  | 'page.mcpNotAllowed.snippets.chatgptApp.headline'
158
158
  | 'page.mcpNotAllowed.snippets.chatgptApp.instruction'
159
159
  | 'page.mcpNotAllowed.snippets.codexCli.headline'
160
+ | 'page.mcpNotAllowed.snippets.grokBuild.headline'
161
+ | 'page.mcpNotAllowed.snippets.grokApp.headline'
162
+ | 'page.mcpNotAllowed.snippets.grokApp.instruction'
163
+ | 'page.mcpNotAllowed.snippets.grokApp.openConnectors'
160
164
  | 'page.mcpNotAllowed.snippets.prompt.headline'
161
165
  | 'page.mcpNotAllowed.snippets.prompt.hint'
162
166
  | 'page.mcpNotAllowed.snippets.json.hint'
163
167
  | 'page.mcpNotAllowed.tabs.claude'
164
168
  | 'page.mcpNotAllowed.tabs.chatgpt'
169
+ | 'page.mcpNotAllowed.tabs.grok'
165
170
  | 'page.mcpNotAllowed.tabs.json'
166
171
  | 'page.lastUpdated.timeago'
167
172
  | 'page.lastUpdated.on'
@@ -292,6 +297,9 @@ export type TranslationKey =
292
297
  | 'page.actions.claudeTitle'
293
298
  | 'page.actions.claudeButtonText'
294
299
  | 'page.actions.claudeDescription'
300
+ | 'page.actions.grokTitle'
301
+ | 'page.actions.grokButtonText'
302
+ | 'page.actions.grokDescription'
295
303
  | 'page.actions.cursorMcpButtonText'
296
304
  | 'page.actions.cursorMcpTitle'
297
305
  | 'page.actions.cursorMcpDescription'
@@ -308,6 +316,8 @@ export type TranslationKey =
308
316
  | 'page.actions.connectMcp.codexDescription'
309
317
  | 'page.actions.connectMcp.copyConfig'
310
318
  | 'page.actions.connectMcp.copyConfigDescription'
319
+ | 'page.actions.connectMcp.copyUrl'
320
+ | 'page.actions.connectMcp.copyUrlDescription'
311
321
  | 'page.actions.connectMcp.moreOptions'
312
322
  | 'page.actions.moreActions'
313
323
  | 'promptTag.copy.buttonText'
@@ -556,9 +566,12 @@ export type TranslationKey =
556
566
  | 'consent.category.analytics.description'
557
567
  | 'consent.category.marketing.title'
558
568
  | 'consent.category.marketing.description'
559
- | 'consent.settingsLink';
569
+ | 'consent.settingsLink'
570
+ | 'missingTranslationNotice.title'
571
+ | 'missingTranslationNotice.content'
572
+ | 'missingTranslationNotice.close';
560
573
 
561
- export type Locale = { code: string; name: string };
574
+ export type Locale = { code: string; name: string; showMissingTranslationNotice?: boolean };
562
575
 
563
576
  export type TFunction = (
564
577
  // A workaround for literals + strings Typescript autosuggestion: 'https://github.com/microsoft/TypeScript/issues/29729'
@@ -2,9 +2,12 @@ import type { AiPromptTarget } from '../types/prompt';
2
2
 
3
3
  type AiPromptEndpoint = { baseUrl: string; queryParam: string };
4
4
 
5
- const AI_PROMPT_ENDPOINTS: Record<AiPromptTarget, AiPromptEndpoint> = {
5
+ type AiPromptLinkTarget = AiPromptTarget | 'grok';
6
+
7
+ const AI_PROMPT_ENDPOINTS: Record<AiPromptLinkTarget, AiPromptEndpoint> = {
6
8
  chatgpt: { baseUrl: 'https://chat.openai.com', queryParam: 'q' },
7
9
  claude: { baseUrl: 'https://claude.ai/new', queryParam: 'q' },
10
+ grok: { baseUrl: 'https://grok.com/', queryParam: 'q' },
8
11
  // Encoding: https://cursor.com/docs/integrations/deeplinks
9
12
  cursor: { baseUrl: 'https://cursor.com/link/prompt', queryParam: 'text' },
10
13
  };
@@ -22,7 +25,7 @@ const AI_PROMPT_ENDPOINTS: Record<AiPromptTarget, AiPromptEndpoint> = {
22
25
  * // 'https://claude.ai/new?q=Summarize+this+page'
23
26
  * ```
24
27
  */
25
- export function getAiPromptLink(target: AiPromptTarget, prompt: string): string {
28
+ export function getAiPromptLink(target: AiPromptLinkTarget, prompt: string): string {
26
29
  const { baseUrl, queryParam } = AI_PROMPT_ENDPOINTS[target];
27
30
  const url = new URL(baseUrl);
28
31
  url.searchParams.set(queryParam, prompt);
@@ -58,6 +58,10 @@ export function generateClaudeCodeCommand(config: McpConnectionParams): string {
58
58
  return `claude mcp add --transport http ${slugifyMcpServerName(config.serverName)} ${config.url}`;
59
59
  }
60
60
 
61
+ export function generateGrokBuildCommand(config: McpConnectionParams): string {
62
+ return `grok mcp add --transport http ${slugifyMcpServerName(config.serverName)} ${config.url}`;
63
+ }
64
+
61
65
  export function generateCodexCommand(config: McpConnectionParams): string {
62
66
  return `codex mcp add ${slugifyMcpServerName(config.serverName)} --url ${config.url}`;
63
67
  }
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { IconProps } from '@redocly/theme/icons/types';
5
+
6
+ import { getCssColorVariable } from '@redocly/theme/core/utils';
7
+
8
+ const Icon = (props: IconProps) => (
9
+ <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
10
+ <path d="M6.6345 9.6347L10.6239 6.6862C10.8195 6.5417 11.0991 6.598 11.1923 6.8226C11.6827 8.0067 11.4636 9.4297 10.4877 10.4067C9.5119 11.3837 8.1541 11.5979 6.9131 11.1099L5.5573 11.7384C7.5019 13.0691 9.8631 12.74 11.3387 11.2617C12.5091 10.0899 12.8716 8.4926 12.5327 7.0522L12.5357 7.0553C12.0442 4.9393 12.6566 4.0935 13.9109 2.364C13.9406 2.3229 13.9703 2.2819 14 2.2399L12.3493 3.8925V3.8874L6.6335 9.6357" />
11
+ <path d="M5.8113 10.3513C4.4156 9.0165 4.6562 6.9507 5.8471 5.7594C6.7277 4.8777 8.1705 4.5179 9.43 5.0469L10.7827 4.4215C10.539 4.2452 10.2266 4.0555 9.8682 3.9223C8.2483 3.2549 6.3089 3.587 4.9921 4.9044C3.7254 6.1726 3.3271 8.1225 4.0111 9.7864C4.5221 11.03 3.6844 11.9096 2.8407 12.7974C2.5417 13.1122 2.2417 13.4269 2 13.7601L5.8102 10.3523" />
12
+ </svg>
13
+ );
14
+
15
+ export const GrokIcon = styled(Icon).attrs({
16
+ 'data-component-name': 'icons/GrokIcon/GrokIcon',
17
+ })`
18
+ path {
19
+ fill: ${({ color }) => getCssColorVariable(color)};
20
+ }
21
+
22
+ height: ${({ size }) => size || '16px'};
23
+ width: ${({ size }) => size || '16px'};
24
+ `;
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { IconProps } from '@redocly/theme/icons/types';
5
+
6
+ import { getCssColorVariable } from '@redocly/theme/core/utils';
7
+
8
+ const Icon = (props: IconProps) => (
9
+ <svg viewBox="14 13 150 154" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
10
+ <path
11
+ d="M23.5996 85.2532L86.2021 22.6507C94.8457 14.0071 108.86 14.0071 117.503 22.6507C126.147 31.2942 126.147 45.3083 117.503 53.9519L70.2254 101.23"
12
+ strokeWidth="11"
13
+ strokeLinecap="round"
14
+ />
15
+ <path
16
+ d="M70.8789 100.578L117.504 53.952C126.148 45.3083 140.163 45.3083 148.806 53.952L149.132 54.278C157.776 62.9216 157.776 76.9357 149.132 85.5792L92.5139 142.198C89.6327 145.079 89.6327 149.75 92.5139 152.631L104.14 164.257"
17
+ strokeWidth="11"
18
+ strokeLinecap="round"
19
+ />
20
+ <path
21
+ d="M101.853 38.3013L55.553 84.6011C46.9094 93.2447 46.9094 107.258 55.553 115.902C64.1966 124.546 78.2106 124.546 86.8543 115.902L133.154 69.6025"
22
+ strokeWidth="11"
23
+ strokeLinecap="round"
24
+ />
25
+ </svg>
26
+ );
27
+
28
+ export const McpIcon = styled(Icon).attrs({
29
+ 'data-component-name': 'icons/McpIcon/McpIcon',
30
+ })`
31
+ path {
32
+ stroke: ${({ color }) => getCssColorVariable(color)};
33
+ }
34
+
35
+ height: ${({ size }) => size || '16px'};
36
+ width: ${({ size }) => size || '16px'};
37
+ `;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { IconProps } from '@redocly/theme/icons/types';
5
+
6
+ import { getCssColorVariable } from '@redocly/theme/core/utils';
7
+
8
+ const Icon = (props: IconProps) => (
9
+ <svg viewBox="0 0 24 24" fill="inherit" xmlns="http://www.w3.org/2000/svg" {...props}>
10
+ <path d="M12.87 15.07L10.33 12.56L10.36 12.53C12.1 10.59 13.34 8.36 14.07 6H17V4H10V2H8V4H1V6H12.17C11.5 7.92 10.44 9.75 9 11.35C8.07 10.32 7.3 9.19 6.69 8H4.69C5.42 9.63 6.42 11.17 7.67 12.56L2.58 17.58L4 19L9 14L12.11 17.11L12.87 15.07ZM18.5 10H16.5L12 22H14L15.12 19H19.87L21 22H23L18.5 10ZM15.88 17L17.5 12.67L19.12 17H15.88Z" />
11
+ </svg>
12
+ );
13
+
14
+ export const TranslateIcon = styled(Icon).attrs({
15
+ 'data-component-name': 'icons/TranslateIcon/TranslateIcon',
16
+ })`
17
+ path {
18
+ fill: ${({ color }) => getCssColorVariable(color)};
19
+ }
20
+ height: ${({ size }) => size || '20px'};
21
+ width: ${({ size }) => size || '20px'};
22
+ `;
package/src/index.ts CHANGED
@@ -46,6 +46,8 @@ export * from '@redocly/theme/components/Markdown/styles/heading-anchor';
46
46
  export * from '@redocly/theme/components/Markdown/styles/links';
47
47
  /* Admonition */
48
48
  export * from '@redocly/theme/components/Admonition/Admonition';
49
+ /* MissingTranslationNotice */
50
+ export * from '@redocly/theme/components/MissingTranslationNotice/MissingTranslationNotice';
49
51
  /* ApiOnboarding */
50
52
  export * from '@redocly/theme/components/ApiOnboarding/AppCustomAttributes';
51
53
  /* Navbar */
@@ -193,6 +195,8 @@ export * from '@redocly/theme/icons/SpinnerIcon/SpinnerIcon';
193
195
  export * from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
194
196
  export * from '@redocly/theme/icons/CopyIcon/CopyIcon';
195
197
  export * from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
198
+ export * from '@redocly/theme/icons/GrokIcon/GrokIcon';
199
+ export * from '@redocly/theme/icons/McpIcon/McpIcon';
196
200
  export * from '@redocly/theme/icons/CleanIcon/CleanIcon';
197
201
  export * from '@redocly/theme/icons/GraphqlIcon/GraphqlIcon';
198
202
  export * from '@redocly/theme/icons/DeselectIcon/DeselectIcon';
@@ -5,6 +5,7 @@ import type { JSX } from 'react';
5
5
 
6
6
  import { H1_CLASS } from '@redocly/theme/core/constants';
7
7
  import { breakpoints } from '@redocly/theme/core/utils';
8
+ import { MissingTranslationNotice } from '@redocly/theme/components/MissingTranslationNotice/MissingTranslationNotice';
8
9
 
9
10
  export type CodeWalkthroughLayoutProps = React.PropsWithChildren<{
10
11
  className?: string;
@@ -16,7 +17,10 @@ export function CodeWalkthroughLayout({
16
17
  }: CodeWalkthroughLayoutProps): JSX.Element {
17
18
  return (
18
19
  <LayoutWrapper data-component-name="Layout/CodeWalkthroughLayout" className={className}>
19
- <ContentWrapper>{children}</ContentWrapper>
20
+ <ContentWrapper>
21
+ <Notice />
22
+ {children}
23
+ </ContentWrapper>
20
24
  </LayoutWrapper>
21
25
  );
22
26
  }
@@ -29,6 +33,12 @@ const LayoutWrapper = styled.div.attrs(({ className }) => ({
29
33
  width: 100%;
30
34
  `;
31
35
 
36
+ const Notice = styled(MissingTranslationNotice)`
37
+ max-width: var(--md-content-max-width);
38
+ margin-left: auto;
39
+ margin-right: auto;
40
+ `;
41
+
32
42
  const ContentWrapper = styled.section`
33
43
  width: 100%;
34
44
  --md-content-font-size: var(--font-size-lg);
@@ -10,6 +10,7 @@ import { H1_CLASS } from '@redocly/theme/core/constants';
10
10
  import { CodeSnippetProvider } from '@redocly/theme/core/contexts/CodeSnippetContext';
11
11
  import { DocumentationLayoutTop } from '@redocly/theme/layouts/DocumentationLayoutTop';
12
12
  import { DocumentationLayoutBottom } from '@redocly/theme/layouts/DocumentationLayoutBottom';
13
+ import { MissingTranslationNotice } from '@redocly/theme/components/MissingTranslationNotice/MissingTranslationNotice';
13
14
 
14
15
  type DocumentationLayoutProps = {
15
16
  tableOfContent: React.ReactNode;
@@ -48,6 +49,7 @@ export function DocumentationLayout({
48
49
  >
49
50
  <ContentWrapper>
50
51
  <DocumentationLayoutTop config={config} editPage={editPage} lastModified={lastModified} />
52
+ <MissingTranslationNotice />
51
53
  {children}
52
54
  <DocumentationLayoutBottom feedback={feedback} nextPage={nextPage} prevPage={prevPage} />
53
55
  </ContentWrapper>
@@ -33,6 +33,7 @@ import { icon } from '@redocly/theme/markdoc/tags/icon';
33
33
  import { connectMcp } from '@redocly/theme/markdoc/tags/connect-mcp';
34
34
  import { loginButton } from '@redocly/theme/markdoc/tags/login-button';
35
35
  import { diagram } from '@redocly/theme/markdoc/tags/diagram';
36
+ import { visibility } from '@redocly/theme/markdoc/tags/visibility';
36
37
  import { prompt } from '@redocly/theme/markdoc/tags/prompt';
37
38
 
38
39
  export const tags = {
@@ -61,5 +62,6 @@ export const tags = {
61
62
  [connectMcp.tagName]: connectMcp.schema,
62
63
  [loginButton.tagName]: loginButton.schema,
63
64
  [diagram.tagName]: diagram.schema,
65
+ [visibility.tagName]: visibility.schema,
64
66
  [prompt.tagName]: prompt.schema,
65
67
  };
@@ -201,7 +201,7 @@ export function collectTogglesFromChildren(
201
201
  toggles[id] = {
202
202
  when: child.attributes.when,
203
203
  unless: child.attributes.unless,
204
- } as TogglesMarkdocAttr;
204
+ };
205
205
  }
206
206
  }
207
207