@redocly/theme 0.71.0-next.5 → 0.71.0-next.7
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/components/Feedback/Mood.js +1 -1
- package/lib/components/Feedback/Rating.js +1 -1
- package/lib/components/Feedback/Scale.js +1 -1
- package/lib/components/Feedback/Sentiment.js +1 -1
- package/lib/components/Filter/Filter.js +1 -1
- package/lib/components/MCP/McpConnectionTabs.d.ts +1 -1
- package/lib/components/MCP/McpConnectionTabs.js +24 -1
- package/lib/components/MissingTranslationNotice/MissingTranslationNotice.d.ts +11 -0
- package/lib/components/MissingTranslationNotice/MissingTranslationNotice.js +83 -0
- package/lib/components/MissingTranslationNotice/variables.d.ts +1 -0
- package/lib/components/MissingTranslationNotice/variables.dark.d.ts +1 -0
- package/lib/components/MissingTranslationNotice/variables.dark.js +10 -0
- package/lib/components/MissingTranslationNotice/variables.js +29 -0
- package/lib/components/PageActions/PageActions.js +4 -2
- package/lib/components/PageActions/variables.js +2 -1
- package/lib/components/Select/Select.js +1 -2
- package/lib/core/hooks/use-active-section-id.js +8 -0
- package/lib/core/hooks/use-page-actions.d.ts +1 -1
- package/lib/core/hooks/use-page-actions.js +18 -2
- package/lib/core/styles/dark.js +4 -2
- package/lib/core/styles/global.js +70 -68
- package/lib/core/types/hooks.d.ts +2 -5
- package/lib/core/types/l10n.d.ts +2 -1
- package/lib/core/utils/mcp.d.ts +1 -0
- package/lib/core/utils/mcp.js +4 -0
- package/lib/icons/McpIcon/McpIcon.d.ts +25 -0
- package/lib/icons/McpIcon/McpIcon.js +24 -0
- package/lib/icons/TranslateIcon/TranslateIcon.d.ts +25 -0
- package/lib/icons/TranslateIcon/TranslateIcon.js +21 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/layouts/CodeWalkthroughLayout.js +9 -1
- package/lib/layouts/DocumentationLayout.js +2 -0
- package/lib/markdoc/components/Heading/Heading.js +9 -0
- package/package.json +3 -3
- package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +1 -1
- package/src/components/Feedback/Mood.tsx +1 -1
- package/src/components/Feedback/Rating.tsx +1 -1
- package/src/components/Feedback/Scale.tsx +1 -1
- package/src/components/Feedback/Sentiment.tsx +1 -1
- package/src/components/Filter/Filter.tsx +2 -2
- package/src/components/MCP/McpConnectionTabs.tsx +56 -2
- package/src/components/MissingTranslationNotice/MissingTranslationNotice.tsx +113 -0
- package/src/components/MissingTranslationNotice/variables.dark.ts +7 -0
- package/src/components/MissingTranslationNotice/variables.ts +26 -0
- package/src/components/PageActions/PageActions.tsx +5 -2
- package/src/components/PageActions/variables.ts +2 -1
- package/src/components/Search/FilterFields/SearchFilterFieldSelect.tsx +1 -1
- package/src/components/Select/Select.tsx +1 -2
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +1 -1
- package/src/core/hooks/use-active-section-id.ts +13 -0
- package/src/core/hooks/use-codeblock-tabs-controls.ts +1 -1
- package/src/core/hooks/use-page-actions.ts +27 -4
- package/src/core/styles/dark.ts +2 -0
- package/src/core/styles/global.ts +2 -0
- package/src/core/types/hooks.ts +2 -2
- package/src/core/types/l10n.ts +12 -2
- package/src/core/utils/mcp.ts +4 -0
- package/src/icons/McpIcon/McpIcon.tsx +37 -0
- package/src/icons/TranslateIcon/TranslateIcon.tsx +22 -0
- package/src/index.ts +3 -0
- package/src/layouts/CodeWalkthroughLayout.tsx +11 -1
- package/src/layouts/DocumentationLayout.tsx +2 -0
- package/src/markdoc/components/Heading/Heading.tsx +10 -1
- package/src/markdoc/tags/code-walkthrough.ts +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { JSX } from 'react';
|
|
5
|
+
|
|
6
|
+
import { CloseIcon } from '@redocly/theme/icons/CloseIcon/CloseIcon';
|
|
7
|
+
import { TranslateIcon } from '@redocly/theme/icons/TranslateIcon/TranslateIcon';
|
|
8
|
+
import { Markdown } from '@redocly/theme/components/Markdown/Markdown';
|
|
9
|
+
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
10
|
+
|
|
11
|
+
export type MissingTranslationNoticeProps = {
|
|
12
|
+
className?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tells the reader that the page shows the original language,
|
|
17
|
+
* because the translation for the selected locale is missing.
|
|
18
|
+
* Renders only on fallback pages of a locale that sets `showMissingTranslationNotice`.
|
|
19
|
+
* The reader can close the notice for the current page.
|
|
20
|
+
*/
|
|
21
|
+
export function MissingTranslationNotice({
|
|
22
|
+
className,
|
|
23
|
+
}: MissingTranslationNoticeProps): JSX.Element | null {
|
|
24
|
+
const { useTranslate, useMarkdownText, usePageProps, useL10nConfig } = useThemeHooks();
|
|
25
|
+
const { translate } = useTranslate();
|
|
26
|
+
const { isTranslationFallback } = usePageProps<{ isTranslationFallback?: boolean }>();
|
|
27
|
+
const { currentLocale, defaultLocale, locales } = useL10nConfig();
|
|
28
|
+
const [isDismissed, setIsDismissed] = React.useState(false);
|
|
29
|
+
|
|
30
|
+
const isShown =
|
|
31
|
+
isTranslationFallback === true &&
|
|
32
|
+
currentLocale !== defaultLocale &&
|
|
33
|
+
locales.some(
|
|
34
|
+
({ code, showMissingTranslationNotice }) =>
|
|
35
|
+
code === currentLocale && showMissingTranslationNotice === true,
|
|
36
|
+
);
|
|
37
|
+
const language = locales.find(({ code }) => code === defaultLocale)?.name || defaultLocale;
|
|
38
|
+
const content = useMarkdownText(
|
|
39
|
+
isShown ? translate('missingTranslationNotice.content', { language }) : '',
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (!isShown || isDismissed) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<MissingTranslationNoticeWrapper
|
|
48
|
+
className={className}
|
|
49
|
+
data-component-name="MissingTranslationNotice/MissingTranslationNotice"
|
|
50
|
+
>
|
|
51
|
+
<Icon color="--missing-translation-notice-icon-color" />
|
|
52
|
+
<Content>
|
|
53
|
+
<Title>
|
|
54
|
+
{translate('missingTranslationNotice.title', {
|
|
55
|
+
defaultValue: 'This page has not yet been translated',
|
|
56
|
+
})}
|
|
57
|
+
</Title>
|
|
58
|
+
<Markdown compact>{content}</Markdown>
|
|
59
|
+
</Content>
|
|
60
|
+
<CloseButton
|
|
61
|
+
type="button"
|
|
62
|
+
aria-label={translate('missingTranslationNotice.close', { defaultValue: 'Close' })}
|
|
63
|
+
onClick={() => setIsDismissed(true)}
|
|
64
|
+
>
|
|
65
|
+
<CloseIcon color="--missing-translation-notice-text-color" />
|
|
66
|
+
</CloseButton>
|
|
67
|
+
</MissingTranslationNoticeWrapper>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const MissingTranslationNoticeWrapper = styled.div`
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: row;
|
|
74
|
+
align-items: flex-start;
|
|
75
|
+
gap: var(--missing-translation-notice-gap);
|
|
76
|
+
|
|
77
|
+
padding: var(--missing-translation-notice-padding);
|
|
78
|
+
margin: var(--missing-translation-notice-margin-vertical) 0;
|
|
79
|
+
color: var(--missing-translation-notice-text-color);
|
|
80
|
+
background-color: var(--missing-translation-notice-bg-color);
|
|
81
|
+
border: 1px solid var(--missing-translation-notice-border-color);
|
|
82
|
+
border-left: var(--missing-translation-notice-accent-width) solid
|
|
83
|
+
var(--missing-translation-notice-accent-color);
|
|
84
|
+
border-radius: var(--missing-translation-notice-border-radius);
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const Icon = styled(TranslateIcon)`
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const Content = styled.div`
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
flex: 1;
|
|
95
|
+
gap: var(--spacing-xxs);
|
|
96
|
+
|
|
97
|
+
font-size: var(--missing-translation-notice-font-size);
|
|
98
|
+
line-height: var(--missing-translation-notice-line-height);
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
const Title = styled.span`
|
|
102
|
+
font-size: var(--missing-translation-notice-title-font-size);
|
|
103
|
+
font-weight: var(--missing-translation-notice-title-font-weight);
|
|
104
|
+
`;
|
|
105
|
+
|
|
106
|
+
const CloseButton = styled.button`
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-shrink: 0;
|
|
109
|
+
padding: 0;
|
|
110
|
+
border: none;
|
|
111
|
+
background: none;
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { css } from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const missingTranslationNoticeDarkMode = css`
|
|
4
|
+
--missing-translation-notice-bg-color: var(--color-warm-grey-3); // @presenter Color
|
|
5
|
+
--missing-translation-notice-icon-color: var(--color-blue-4); // @presenter Color
|
|
6
|
+
--missing-translation-notice-accent-color: var(--color-blue-4); // @presenter Color
|
|
7
|
+
`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { css } from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const missingTranslationNotice = css`
|
|
4
|
+
/**
|
|
5
|
+
* @tokens Missing translation notice
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
--missing-translation-notice-bg-color: var(--color-warm-grey-1); // @presenter Color
|
|
9
|
+
--missing-translation-notice-text-color: var(--text-color-primary); // @presenter Color
|
|
10
|
+
--missing-translation-notice-icon-color: var(--color-blue-6); // @presenter Color
|
|
11
|
+
--missing-translation-notice-border-color: var(--border-color-secondary); // @presenter Color
|
|
12
|
+
--missing-translation-notice-accent-color: var(--color-blue-6); // @presenter Color
|
|
13
|
+
|
|
14
|
+
--missing-translation-notice-accent-width: 3px; // @presenter Spacing
|
|
15
|
+
--missing-translation-notice-border-radius: var(--border-radius-lg); // @presenter BorderRadius
|
|
16
|
+
--missing-translation-notice-padding: var(--spacing-sm) var(--spacing-base); // @presenter Spacing
|
|
17
|
+
--missing-translation-notice-margin-vertical: var(--spacing-base); // @presenter Spacing
|
|
18
|
+
--missing-translation-notice-gap: var(--spacing-sm); // @presenter Spacing
|
|
19
|
+
|
|
20
|
+
--missing-translation-notice-title-font-size: var(--font-size-base); // @presenter FontSize
|
|
21
|
+
--missing-translation-notice-title-font-weight: var(--font-weight-semibold); // @presenter FontWeight
|
|
22
|
+
--missing-translation-notice-font-size: var(--font-size-base); // @presenter FontSize
|
|
23
|
+
--missing-translation-notice-line-height: var(--line-height-base); // @presenter LineHeight
|
|
24
|
+
|
|
25
|
+
// @tokens End
|
|
26
|
+
`;
|
|
@@ -78,11 +78,12 @@ export function PageActions(props: PageActionProps): JSX.Element | null {
|
|
|
78
78
|
<SplitButton
|
|
79
79
|
portalled
|
|
80
80
|
variant="outlined"
|
|
81
|
-
size="
|
|
81
|
+
size="small"
|
|
82
82
|
toggleAriaLabel={translate('page.actions.moreActions', 'More actions')}
|
|
83
83
|
button={
|
|
84
84
|
<Button
|
|
85
85
|
variant="outlined"
|
|
86
|
+
size="small"
|
|
86
87
|
icon={renderIcon(buttonAction, actionState)}
|
|
87
88
|
to={'link' in buttonAction ? buttonAction.link : undefined}
|
|
88
89
|
external
|
|
@@ -112,10 +113,12 @@ function renderIcon(buttonAction: PageAction, actionState: ActionState) {
|
|
|
112
113
|
const PageActionsWrapper = styled.div`
|
|
113
114
|
margin-left: auto;
|
|
114
115
|
padding-left: var(--page-actions-padding-left);
|
|
116
|
+
user-select: none;
|
|
115
117
|
--button-color: var(--page-actions-button-text-color);
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
&& .button.button-size-small {
|
|
118
120
|
--button-icon-left-padding: var(--page-actions-button-padding);
|
|
121
|
+
--button-icon-padding: var(--page-actions-toggle-padding);
|
|
119
122
|
}
|
|
120
123
|
`;
|
|
121
124
|
|
|
@@ -5,7 +5,8 @@ export const pageActions = css`
|
|
|
5
5
|
--page-actions-padding-left: var(--spacing-sm);
|
|
6
6
|
|
|
7
7
|
--page-actions-button-text-color: var(--text-color-secondary);
|
|
8
|
-
--page-actions-button-padding:
|
|
8
|
+
--page-actions-button-padding: 0 var(--spacing-sm) 0 10px;
|
|
9
|
+
--page-actions-toggle-padding: 4px;
|
|
9
10
|
|
|
10
11
|
--page-actions-dropdown-max-height: fit-content;
|
|
11
12
|
|
|
@@ -92,7 +92,7 @@ function facetValueToSelectOption(facetValue?: SearchFacetCount | string) {
|
|
|
92
92
|
value: facetValue,
|
|
93
93
|
};
|
|
94
94
|
} else {
|
|
95
|
-
const { value, count, isCounterVisible } = facetValue
|
|
95
|
+
const { value, count, isCounterVisible } = facetValue;
|
|
96
96
|
return {
|
|
97
97
|
element: (
|
|
98
98
|
<FilterSelectOptionWrapper>
|
|
@@ -46,8 +46,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
|
|
|
46
46
|
.map((value) => {
|
|
47
47
|
const selectedOption = options.find((option) => option.value === value);
|
|
48
48
|
return (
|
|
49
|
-
selectedOption ||
|
|
50
|
-
(typeof value === 'string' ? ({ value } as SelectOption<T>) : (value as SelectOption<T>))
|
|
49
|
+
selectedOption || (typeof value === 'string' ? { value } : (value as SelectOption<T>))
|
|
51
50
|
);
|
|
52
51
|
})
|
|
53
52
|
.filter((option) => !!option);
|
|
@@ -7,7 +7,7 @@ export const useThemeHooks = vi.fn(() => ({
|
|
|
7
7
|
translate: vi.fn((key: string, defaultValue: string | { defaultValue: string }) =>
|
|
8
8
|
defaultValue
|
|
9
9
|
? typeof defaultValue !== 'string'
|
|
10
|
-
?
|
|
10
|
+
? defaultValue.defaultValue
|
|
11
11
|
: defaultValue
|
|
12
12
|
: key,
|
|
13
13
|
),
|
|
@@ -60,7 +60,15 @@ export function useActiveSectionId(
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// A one-event scroll jump is read before the section it lands on stops being skipped.
|
|
64
|
+
const onContentVisibilityChange = (event: Event) => {
|
|
65
|
+
if ('skipped' in event && event.skipped === false) {
|
|
66
|
+
scrollListener();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
63
70
|
window.addEventListener('scroll', scrollListener, { capture: false });
|
|
71
|
+
window.addEventListener('contentvisibilityautostatechange', onContentVisibilityChange, true);
|
|
64
72
|
const initialRead = setTimeout(() => {
|
|
65
73
|
scrollListener();
|
|
66
74
|
}, 10);
|
|
@@ -69,6 +77,11 @@ export function useActiveSectionId(
|
|
|
69
77
|
clearTimeout(initialRead);
|
|
70
78
|
scrollListener.cancel();
|
|
71
79
|
window.removeEventListener('scroll', scrollListener);
|
|
80
|
+
window.removeEventListener(
|
|
81
|
+
'contentvisibilityautostatechange',
|
|
82
|
+
onContentVisibilityChange,
|
|
83
|
+
true,
|
|
84
|
+
);
|
|
72
85
|
};
|
|
73
86
|
}, [location, heightOffset, scrollListener]);
|
|
74
87
|
|
|
@@ -41,7 +41,7 @@ export function useCodeBlockTabsControls({ tabs, containerRef, tabRefs }: CodeBl
|
|
|
41
41
|
resizeObserver.observe(container);
|
|
42
42
|
|
|
43
43
|
return () => {
|
|
44
|
-
resizeObserver.unobserve(container
|
|
44
|
+
resizeObserver.unobserve(container);
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -8,6 +8,7 @@ import { CopyIcon } from '@redocly/theme/icons/CopyIcon/CopyIcon';
|
|
|
8
8
|
import { ChatGptIcon } from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
|
|
9
9
|
import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
|
|
10
10
|
import { GrokIcon } from '@redocly/theme/icons/GrokIcon/GrokIcon';
|
|
11
|
+
import { McpIcon } from '@redocly/theme/icons/McpIcon/McpIcon';
|
|
11
12
|
import { MarkdownFullIcon } from '@redocly/theme/icons/MarkdownFullIcon/MarkdownFullIcon';
|
|
12
13
|
import { VSCodeIcon } from '@redocly/theme/icons/VSCodeIcon/VSCodeIcon';
|
|
13
14
|
import { CursorIcon } from '@redocly/theme/icons/CursorIcon/CursorIcon';
|
|
@@ -33,9 +34,10 @@ const DEFAULT_ENABLED_ACTIONS = [
|
|
|
33
34
|
'chatgpt',
|
|
34
35
|
'claude',
|
|
35
36
|
'grok',
|
|
36
|
-
'docs-mcp-cursor',
|
|
37
|
-
'docs-mcp-vscode',
|
|
38
37
|
'docs-mcp-claude',
|
|
38
|
+
'docs-mcp-vscode',
|
|
39
|
+
'docs-mcp-cursor',
|
|
40
|
+
'copy-mcp-url',
|
|
39
41
|
] as const;
|
|
40
42
|
|
|
41
43
|
export type PageActionType =
|
|
@@ -44,9 +46,10 @@ export type PageActionType =
|
|
|
44
46
|
| 'chatgpt'
|
|
45
47
|
| 'claude'
|
|
46
48
|
| 'grok'
|
|
47
|
-
| 'docs-mcp-cursor'
|
|
48
|
-
| 'docs-mcp-vscode'
|
|
49
49
|
| 'docs-mcp-claude'
|
|
50
|
+
| 'docs-mcp-vscode'
|
|
51
|
+
| 'docs-mcp-cursor'
|
|
52
|
+
| 'copy-mcp-url'
|
|
50
53
|
// Used in OpenAPI docs x-mcp
|
|
51
54
|
| 'mcp-cursor'
|
|
52
55
|
| 'mcp-vscode';
|
|
@@ -147,6 +150,24 @@ export function usePageActions(
|
|
|
147
150
|
'docs-mcp-cursor': createMCPHandler('cursor', false),
|
|
148
151
|
'docs-mcp-vscode': createMCPHandler('vscode', false),
|
|
149
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
|
+
}),
|
|
150
171
|
'mcp-cursor': createMCPHandler('cursor', true),
|
|
151
172
|
'mcp-vscode': createMCPHandler('vscode', true),
|
|
152
173
|
|
|
@@ -221,6 +242,7 @@ export function usePageActions(
|
|
|
221
242
|
isPublic,
|
|
222
243
|
mcpUrl,
|
|
223
244
|
mcpConfig.isMcpDisabled,
|
|
245
|
+
mcpConfig.serverUrl,
|
|
224
246
|
pageSlug,
|
|
225
247
|
actions,
|
|
226
248
|
translate,
|
|
@@ -356,6 +378,7 @@ function shouldHideActionByType(
|
|
|
356
378
|
case 'docs-mcp-cursor':
|
|
357
379
|
case 'docs-mcp-vscode':
|
|
358
380
|
case 'docs-mcp-claude':
|
|
381
|
+
case 'copy-mcp-url':
|
|
359
382
|
return Boolean(mcpUrl) || isMcpDisabled;
|
|
360
383
|
case 'mcp-cursor':
|
|
361
384
|
case 'mcp-vscode':
|
package/src/core/styles/dark.ts
CHANGED
|
@@ -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}
|
package/src/core/types/hooks.ts
CHANGED
|
@@ -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:
|
|
237
|
+
locales: Locale[];
|
|
238
238
|
};
|
package/src/core/types/l10n.ts
CHANGED
|
@@ -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'
|
|
@@ -311,6 +316,8 @@ export type TranslationKey =
|
|
|
311
316
|
| 'page.actions.connectMcp.codexDescription'
|
|
312
317
|
| 'page.actions.connectMcp.copyConfig'
|
|
313
318
|
| 'page.actions.connectMcp.copyConfigDescription'
|
|
319
|
+
| 'page.actions.connectMcp.copyUrl'
|
|
320
|
+
| 'page.actions.connectMcp.copyUrlDescription'
|
|
314
321
|
| 'page.actions.connectMcp.moreOptions'
|
|
315
322
|
| 'page.actions.moreActions'
|
|
316
323
|
| 'promptTag.copy.buttonText'
|
|
@@ -559,9 +566,12 @@ export type TranslationKey =
|
|
|
559
566
|
| 'consent.category.analytics.description'
|
|
560
567
|
| 'consent.category.marketing.title'
|
|
561
568
|
| 'consent.category.marketing.description'
|
|
562
|
-
| 'consent.settingsLink'
|
|
569
|
+
| 'consent.settingsLink'
|
|
570
|
+
| 'missingTranslationNotice.title'
|
|
571
|
+
| 'missingTranslationNotice.content'
|
|
572
|
+
| 'missingTranslationNotice.close';
|
|
563
573
|
|
|
564
|
-
export type Locale = { code: string; name: string };
|
|
574
|
+
export type Locale = { code: string; name: string; showMissingTranslationNotice?: boolean };
|
|
565
575
|
|
|
566
576
|
export type TFunction = (
|
|
567
577
|
// A workaround for literals + strings Typescript autosuggestion: 'https://github.com/microsoft/TypeScript/issues/29729'
|
package/src/core/utils/mcp.ts
CHANGED
|
@@ -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,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 */
|
|
@@ -194,6 +196,7 @@ 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';
|
|
196
198
|
export * from '@redocly/theme/icons/GrokIcon/GrokIcon';
|
|
199
|
+
export * from '@redocly/theme/icons/McpIcon/McpIcon';
|
|
197
200
|
export * from '@redocly/theme/icons/CleanIcon/CleanIcon';
|
|
198
201
|
export * from '@redocly/theme/icons/GraphqlIcon/GraphqlIcon';
|
|
199
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>
|
|
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>
|
|
@@ -5,7 +5,7 @@ import { useLocation } from 'react-router';
|
|
|
5
5
|
import type { JSX, PropsWithChildren, ReactElement, ReactNode } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Image as MarkdocImage } from '@redocly/theme/markdoc/components/Image/Image';
|
|
8
|
-
import { concatClassNames } from '@redocly/theme/core/utils';
|
|
8
|
+
import { breakpoints, concatClassNames } from '@redocly/theme/core/utils';
|
|
9
9
|
import { LinkIcon } from '@redocly/theme/icons/LinkIcon/LinkIcon';
|
|
10
10
|
import { PageActions } from '@redocly/theme/components/PageActions/PageActions';
|
|
11
11
|
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
@@ -125,6 +125,15 @@ const HeadingContentWrapper = styled.div`
|
|
|
125
125
|
visibility: hidden;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
@media screen and (max-width: ${breakpoints.small}) {
|
|
130
|
+
flex-wrap: wrap;
|
|
131
|
+
|
|
132
|
+
& > [data-component-name='PageActions/PageActions'] {
|
|
133
|
+
flex-basis: 100%;
|
|
134
|
+
--page-actions-padding-left: 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
128
137
|
`;
|
|
129
138
|
|
|
130
139
|
const StyledHeadingText = styled.span`
|