@redocly/theme 0.70.0-next.7 → 0.70.0-next.8
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/Buttons/ConnectMCPButton.js +11 -1
- package/lib/components/Buttons/variables.d.ts +1 -0
- package/lib/components/Buttons/variables.js +4 -1
- package/lib/components/Catalog/Catalog.js +2 -2
- package/lib/components/JsonViewer/Helpers.js +3 -3
- package/lib/components/MCP/McpConnectionTabs.js +9 -2
- package/lib/components/Search/SearchItem.js +1 -1
- package/lib/components/Search/SearchTrigger.js +33 -8
- package/lib/components/Search/variables.js +2 -0
- package/lib/core/constants/mcp.d.ts +2 -2
- package/lib/core/constants/mcp.js +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-panel.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +1 -1
- package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +1 -2
- package/lib/core/hooks/code-walkthrough/use-renderable-files.d.ts +1 -1
- package/lib/core/hooks/use-connect-mcp-button.js +1 -0
- package/lib/core/hooks/use-page-actions.d.ts +1 -1
- package/lib/core/hooks/use-page-actions.js +6 -0
- package/lib/core/styles/global.js +1 -0
- package/lib/core/types/code-walkthrough.d.ts +84 -0
- package/lib/core/types/hooks.d.ts +1 -1
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/mcp.d.ts +1 -1
- package/lib/core/utils/download-code-walkthrough.d.ts +1 -1
- package/lib/core/utils/get-code-walkthrough-file-text.d.ts +1 -1
- package/lib/core/utils/match-code-walkthrough-conditions.d.ts +1 -1
- package/lib/core/utils/mcp.js +7 -2
- package/lib/markdoc/components/CodeWalkthrough/CodeFilters.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeStep.d.ts +1 -1
- package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.d.ts +1 -1
- package/lib/markdoc/components/Tabs/TabList.js +8 -6
- package/lib/markdoc/tags/code-walkthrough.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/Buttons/ConnectMCPButton.tsx +13 -2
- package/src/components/Buttons/variables.ts +4 -0
- package/src/components/Catalog/Catalog.tsx +5 -3
- package/src/components/JsonViewer/Helpers.tsx +5 -3
- package/src/components/MCP/McpConnectionTabs.tsx +22 -5
- package/src/components/Search/SearchItem.tsx +3 -1
- package/src/components/Search/SearchTrigger.tsx +42 -7
- package/src/components/Search/variables.ts +2 -0
- package/src/core/constants/mcp.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-panel.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +2 -2
- package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +1 -1
- package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +3 -3
- package/src/core/hooks/code-walkthrough/use-renderable-files.ts +1 -1
- package/src/core/hooks/use-connect-mcp-button.ts +7 -1
- package/src/core/hooks/use-page-actions.ts +17 -0
- package/src/core/styles/global.ts +2 -1
- package/src/core/types/code-walkthrough.ts +103 -0
- package/src/core/types/hooks.ts +1 -0
- package/src/core/types/l10n.ts +3 -0
- package/src/core/types/mcp.ts +1 -1
- package/src/core/utils/download-code-walkthrough.ts +1 -1
- package/src/core/utils/get-code-walkthrough-file-text.ts +1 -1
- package/src/core/utils/match-code-walkthrough-conditions.ts +1 -1
- package/src/core/utils/mcp.ts +8 -2
- package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +1 -1
- package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +1 -1
- package/src/markdoc/components/Tabs/TabList.tsx +9 -12
- package/src/markdoc/tags/code-walkthrough.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
|
-
import type { CodeWalkthroughFile } from '
|
|
3
|
+
import type { CodeWalkthroughFile } from '../../../core/types';
|
|
4
4
|
export type CodePanelProps = {
|
|
5
5
|
files: CodeWalkthroughFile[];
|
|
6
6
|
downloadAssociatedFiles: CodeWalkthroughFile[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
|
-
import type { CodeWalkthroughFile } from '
|
|
2
|
+
import type { CodeWalkthroughFile } from '../../../core/types';
|
|
3
3
|
export type CodePanelHeaderProps = {
|
|
4
4
|
files: CodeWalkthroughFile[];
|
|
5
5
|
handleTabSwitch: (name: string) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React, { type PropsWithChildren } from 'react';
|
|
2
|
-
import type { CodeWalkthroughAttr } from '
|
|
2
|
+
import type { CodeWalkthroughAttr } from '../../../core/types';
|
|
3
3
|
export type CodeWalkthroughProps = PropsWithChildren<CodeWalkthroughAttr>;
|
|
4
4
|
export declare function CodeWalkthrough({ children, steps, preview, ...attributes }: CodeWalkthroughProps): React.JSX.Element;
|
|
@@ -152,7 +152,7 @@ function TabList({ childrenArray, size, activeTab, onTabChange, containerRef, on
|
|
|
152
152
|
overflowTabs.some((i) => childrenArray[i] && activeTab === childrenArray[i].props.label);
|
|
153
153
|
// Show as selector when no visible tabs (all tabs in dropdown)
|
|
154
154
|
const showAsSelector = visibleTabs.length === 0 && hasOverflow;
|
|
155
|
-
const { dropdownPosition, setIsDropdownOpen, setDropdownPosition } = useDropdownPosition(hasOverflow, dropdownRef);
|
|
155
|
+
const { dropdownPosition, isDropdownOpen, setIsDropdownOpen, setDropdownPosition } = useDropdownPosition(hasOverflow, dropdownRef);
|
|
156
156
|
return (react_1.default.createElement(exports.TabListContainer, { role: "tablist", ref: containerRef },
|
|
157
157
|
react_1.default.createElement(HighlightBar, { $size: size, style: highlightStyle },
|
|
158
158
|
react_1.default.createElement("div", null)),
|
|
@@ -163,11 +163,9 @@ function TabList({ childrenArray, size, activeTab, onTabChange, containerRef, on
|
|
|
163
163
|
return null;
|
|
164
164
|
return renderTab(child, index, size, setTabRef, handleKeyboard, onTabClick);
|
|
165
165
|
}),
|
|
166
|
-
hasOverflow && (react_1.default.createElement(exports.TabItem, { size: size, active: isMoreActive || showAsSelector, tabIndex: 0, className:
|
|
167
|
-
react_1.default.createElement(DropdownWrapper, { $top: dropdownPosition.top, $left: dropdownPosition.left,
|
|
168
|
-
|
|
169
|
-
} },
|
|
170
|
-
react_1.default.createElement(FixedPositionDropdown, { ref: dropdownRef, trigger: react_1.default.createElement(exports.TabButtonLink, { size: size, className: isMoreActive || showAsSelector ? 'active' : undefined }, showAsSelector ? react_1.default.createElement(TabButtonText, null, activeTab) : 'More'), alignment: "start", withArrow: true, onClose: () => {
|
|
166
|
+
hasOverflow && (react_1.default.createElement(exports.TabItem, { size: size, active: isMoreActive || showAsSelector, tabIndex: 0, className: isDropdownOpen ? 'dropdown-tab dropdown-tab-open' : 'dropdown-tab' },
|
|
167
|
+
react_1.default.createElement(DropdownWrapper, { $top: dropdownPosition.top, $left: dropdownPosition.left },
|
|
168
|
+
react_1.default.createElement(FixedPositionDropdown, { ref: dropdownRef, trigger: react_1.default.createElement(exports.TabButtonLink, { size: size, className: isMoreActive || showAsSelector ? 'active' : undefined }, showAsSelector ? react_1.default.createElement(TabButtonText, null, activeTab) : 'More'), alignment: "start", withArrow: true, onOpen: () => setIsDropdownOpen(true), onClose: () => {
|
|
171
169
|
setIsDropdownOpen(false);
|
|
172
170
|
setDropdownPosition({});
|
|
173
171
|
} },
|
|
@@ -259,6 +257,10 @@ exports.TabListContainer = styled_components_1.default.ul `
|
|
|
259
257
|
min-width: 0;
|
|
260
258
|
max-width: 100%;
|
|
261
259
|
}
|
|
260
|
+
|
|
261
|
+
&.dropdown-tab-open {
|
|
262
|
+
z-index: var(--dropdown-menu-z-index);
|
|
263
|
+
}
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Node, RenderableTreeNode } from '@markdoc/markdoc';
|
|
2
2
|
import type { MarkdocSchemaWrapper } from '../../markdoc/tags/types';
|
|
3
|
-
import type { CodeWalkthroughConditions, CodeWalkthroughFilter, TogglesMarkdocAttr, InputsMarkdocAttr } from '
|
|
3
|
+
import type { CodeWalkthroughConditions, CodeWalkthroughFilter, TogglesMarkdocAttr, InputsMarkdocAttr } from '../../core/types';
|
|
4
4
|
export declare const codeWalkthrough: MarkdocSchemaWrapper;
|
|
5
5
|
export declare function collectStepsFromChildren(children: RenderableTreeNode[], idx?: number): RenderableTreeNode[];
|
|
6
6
|
export declare function collectTogglesFromChildren(children: Node[], toggles?: TogglesMarkdocAttr): TogglesMarkdocAttr;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.70.0-next.
|
|
3
|
+
"version": "0.70.0-next.8",
|
|
4
4
|
"description": "Shared UI components lib",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"theme",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@babel/core": "7.29.7",
|
|
44
44
|
"@markdoc/markdoc": "0.5.2",
|
|
45
|
-
"@redocly/realm-asyncapi-sdk": "0.16.0-next.
|
|
45
|
+
"@redocly/realm-asyncapi-sdk": "0.16.0-next.4",
|
|
46
46
|
"@redocly/tooling-test-utils": "0.0.0",
|
|
47
47
|
"@shikijs/types": "3.21.0",
|
|
48
48
|
"@testing-library/react": "16.3.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"webpack": "5.105.2"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@redocly/config": "0.
|
|
75
|
+
"@redocly/config": "0.65.0",
|
|
76
76
|
"@tanstack/react-query": "5.62.3",
|
|
77
77
|
"@tanstack/react-virtual": "3.13.0",
|
|
78
78
|
"@xyflow/react": "12.8.3",
|
|
@@ -41,6 +41,13 @@ const MENU_OPTIONS: Record<MCPOption, MenuOption> = {
|
|
|
41
41
|
descriptionTranslationKey: 'page.actions.connectMcp.vscodeDescription',
|
|
42
42
|
descriptionDefault: 'Install MCP server on VS Code',
|
|
43
43
|
},
|
|
44
|
+
claude: {
|
|
45
|
+
icon: ClaudeIcon,
|
|
46
|
+
titleTranslationKey: 'page.actions.connectMcp.claude',
|
|
47
|
+
titleDefault: 'Connect to Claude',
|
|
48
|
+
descriptionTranslationKey: 'page.actions.connectMcp.claudeDescription',
|
|
49
|
+
descriptionDefault: 'Add MCP server to your Claude account',
|
|
50
|
+
},
|
|
44
51
|
'claude-code': {
|
|
45
52
|
icon: ClaudeIcon,
|
|
46
53
|
titleTranslationKey: 'page.actions.connectMcp.claudeCode',
|
|
@@ -118,7 +125,7 @@ export function ConnectMCPButton({
|
|
|
118
125
|
>
|
|
119
126
|
{dropdownOptions.length > 0
|
|
120
127
|
? ({ close }: { close: () => void }) => (
|
|
121
|
-
<
|
|
128
|
+
<StyledDropdownMenu>
|
|
122
129
|
{dropdownOptions.map((option) => {
|
|
123
130
|
const Icon = option.icon;
|
|
124
131
|
const showCheckmark = copiedOption === option.key;
|
|
@@ -150,7 +157,7 @@ export function ConnectMCPButton({
|
|
|
150
157
|
</DropdownMenuItem>
|
|
151
158
|
);
|
|
152
159
|
})}
|
|
153
|
-
</
|
|
160
|
+
</StyledDropdownMenu>
|
|
154
161
|
)
|
|
155
162
|
: null}
|
|
156
163
|
</SplitButton>
|
|
@@ -158,6 +165,10 @@ export function ConnectMCPButton({
|
|
|
158
165
|
);
|
|
159
166
|
}
|
|
160
167
|
|
|
168
|
+
const StyledDropdownMenu = styled(DropdownMenu)`
|
|
169
|
+
--dropdown-menu-max-height: var(--connect-mcp-button-dropdown-max-height);
|
|
170
|
+
`;
|
|
171
|
+
|
|
161
172
|
const ConnectMCPButtonWrapper = styled.div`
|
|
162
173
|
display: inline-block;
|
|
163
174
|
position: relative;
|
|
@@ -162,9 +162,11 @@ export function Catalog(props: CatalogProps): JSX.Element {
|
|
|
162
162
|
<CatalogPageContentWrapper>
|
|
163
163
|
<CatalogTitleWrapper>
|
|
164
164
|
<CatalogTitle data-translation-key={catalogConfig?.titleTranslationKey}>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
<span>
|
|
166
|
+
{catalogConfig?.titleTranslationKey
|
|
167
|
+
? translate(catalogConfig?.titleTranslationKey)
|
|
168
|
+
: catalogConfig?.slug}
|
|
169
|
+
</span>{' '}
|
|
168
170
|
</CatalogTitle>
|
|
169
171
|
<CounterTag borderless>{entitiesCounter}</CounterTag>
|
|
170
172
|
</CatalogTitleWrapper>
|
|
@@ -79,7 +79,7 @@ export function JsonValue(props: {
|
|
|
79
79
|
fold={fold}
|
|
80
80
|
maxStringLength={maxStringLength}
|
|
81
81
|
/>
|
|
82
|
-
{index < value.length - 1 ? ',\n' : null}
|
|
82
|
+
{index < value.length - 1 ? <span>{',\n'}</span> : null}
|
|
83
83
|
</React.Fragment>
|
|
84
84
|
))
|
|
85
85
|
: keys.map((key, index) => (
|
|
@@ -92,7 +92,7 @@ export function JsonValue(props: {
|
|
|
92
92
|
fold={fold}
|
|
93
93
|
maxStringLength={maxStringLength}
|
|
94
94
|
/>
|
|
95
|
-
{index < keys.length - 1 ? ',\n' : null}
|
|
95
|
+
{index < keys.length - 1 ? <span>{',\n'}</span> : null}
|
|
96
96
|
</React.Fragment>
|
|
97
97
|
));
|
|
98
98
|
|
|
@@ -177,7 +177,9 @@ function JsonKeyValue(props: {
|
|
|
177
177
|
{isFoldable(value) ? (
|
|
178
178
|
<ExpandIcon onClick={() => fold.setExpanded(path, !isExpanded)} isExpanded={isExpanded} />
|
|
179
179
|
) : null}
|
|
180
|
-
<span className="property token string">{`"${name}"`}</span
|
|
180
|
+
<span className="property token string">{`"${name}"`}</span>
|
|
181
|
+
<span>{': '}</span>
|
|
182
|
+
{valueElement}
|
|
181
183
|
</>
|
|
182
184
|
);
|
|
183
185
|
}
|
|
@@ -10,9 +10,11 @@ import { useMCPConfig, useThemeHooks } from '@redocly/theme/core/hooks';
|
|
|
10
10
|
import {
|
|
11
11
|
generateClaudeCodeCommand,
|
|
12
12
|
generateCodexCommand,
|
|
13
|
+
generateMCPDeepLink,
|
|
13
14
|
generateMcpInstallPrompt,
|
|
14
15
|
getBaseDataAttributes,
|
|
15
16
|
} from '@redocly/theme/core/utils';
|
|
17
|
+
import { Button } from '@redocly/theme/components/Button/Button';
|
|
16
18
|
import { CodeBlock } from '@redocly/theme/components/CodeBlock/CodeBlock';
|
|
17
19
|
import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
|
|
18
20
|
import { ChatGptIcon } from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
|
|
@@ -167,16 +169,26 @@ function renderTabContent(
|
|
|
167
169
|
),
|
|
168
170
|
},
|
|
169
171
|
{
|
|
170
|
-
headline: translate(
|
|
171
|
-
'page.mcpNotAllowed.snippets.claudeDesktop.headline',
|
|
172
|
-
'Claude Desktop',
|
|
173
|
-
),
|
|
172
|
+
headline: translate('page.mcpNotAllowed.snippets.claudeDesktop.headline', 'Claude app'),
|
|
174
173
|
content: (
|
|
175
174
|
<>
|
|
175
|
+
<TabHint>
|
|
176
|
+
{translate(
|
|
177
|
+
'page.mcpNotAllowed.snippets.claudeDesktop.accountHint',
|
|
178
|
+
'Claude adds the connector to your account and syncs it between Claude on the web and Claude Desktop.',
|
|
179
|
+
)}
|
|
180
|
+
</TabHint>
|
|
181
|
+
<ConnectButton
|
|
182
|
+
variant="secondary"
|
|
183
|
+
icon={<ClaudeIcon />}
|
|
184
|
+
onClick={() => window.open(generateMCPDeepLink('claude', connection), '_blank')}
|
|
185
|
+
>
|
|
186
|
+
{translate('page.actions.connectMcp.claude', 'Connect to Claude')}
|
|
187
|
+
</ConnectButton>
|
|
176
188
|
<TabHint>
|
|
177
189
|
{translate(
|
|
178
190
|
'page.mcpNotAllowed.snippets.claudeDesktop.instruction',
|
|
179
|
-
'
|
|
191
|
+
'Or open Customize → Connectors → Add custom connector and paste this server URL:',
|
|
180
192
|
)}
|
|
181
193
|
</TabHint>
|
|
182
194
|
<CodeBlock
|
|
@@ -278,6 +290,11 @@ const McpConnectionTabsWrapper = styled.div`
|
|
|
278
290
|
}
|
|
279
291
|
`;
|
|
280
292
|
|
|
293
|
+
const ConnectButton = styled(Button)`
|
|
294
|
+
align-self: flex-start;
|
|
295
|
+
margin-bottom: var(--spacing-sm);
|
|
296
|
+
`;
|
|
297
|
+
|
|
281
298
|
const TabHint = styled.p`
|
|
282
299
|
margin: 0 0 var(--spacing-xs);
|
|
283
300
|
color: var(--page-mcp-405-snippets-hint-text-color);
|
|
@@ -78,7 +78,9 @@ export function SearchItem({
|
|
|
78
78
|
<SearchItemOperationTag color={httpColor}>
|
|
79
79
|
{document.httpMethod.toUpperCase()}
|
|
80
80
|
</SearchItemOperationTag>
|
|
81
|
-
|
|
81
|
+
<span>
|
|
82
|
+
{highlight.httpPath ? searchHighlight(highlight.httpPath) : document.httpPath}
|
|
83
|
+
</span>
|
|
82
84
|
</SearchItemOperation>
|
|
83
85
|
) : null}
|
|
84
86
|
<SearchItemTitleWrapper>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import styled from 'styled-components';
|
|
2
|
+
import styled, { keyframes } from 'styled-components';
|
|
3
3
|
|
|
4
4
|
import type { JSX } from 'react';
|
|
5
5
|
|
|
@@ -9,6 +9,9 @@ import { SearchIcon } from '@redocly/theme/icons/SearchIcon/SearchIcon';
|
|
|
9
9
|
import { breakpoints, getUserAgent } from '@redocly/theme/core/utils';
|
|
10
10
|
import { DEFAULT_KEYBOARD_SHORTCUTS } from '@redocly/theme/core/constants';
|
|
11
11
|
|
|
12
|
+
const MAC_SHORTCUT_LABEL = '⌘K';
|
|
13
|
+
const SHORTCUT_LABEL = 'Ctrl+K';
|
|
14
|
+
|
|
12
15
|
export type SearchTriggerProps = {
|
|
13
16
|
onClick: () => void;
|
|
14
17
|
className?: string;
|
|
@@ -31,8 +34,8 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
mainShortcutKey = mainShortcutKey?.toUpperCase();
|
|
34
|
-
// A page can be cached and served to every platform, so the server renders
|
|
35
|
-
//
|
|
37
|
+
// A page can be cached and served to every platform, so the server renders an empty
|
|
38
|
+
// slot and the browser picks the label after hydration.
|
|
36
39
|
const [isMac, setIsMac] = React.useState<boolean | undefined>(undefined);
|
|
37
40
|
React.useEffect(() => setIsMac(getUserAgent().includes('Mac')), []);
|
|
38
41
|
|
|
@@ -56,8 +59,12 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
|
|
|
56
59
|
<SearchIcon />
|
|
57
60
|
{translate('search.navbar.label', 'Search')}
|
|
58
61
|
{mainShortcutKey === DEFAULT_KEYBOARD_SHORTCUTS ? (
|
|
59
|
-
<SearchTriggerShortcut
|
|
60
|
-
{isMac ?
|
|
62
|
+
<SearchTriggerShortcut>
|
|
63
|
+
{isMac === undefined ? null : (
|
|
64
|
+
<SearchTriggerShortcutLabel>
|
|
65
|
+
{isMac ? MAC_SHORTCUT_LABEL : SHORTCUT_LABEL}
|
|
66
|
+
</SearchTriggerShortcutLabel>
|
|
67
|
+
)}
|
|
61
68
|
</SearchTriggerShortcut>
|
|
62
69
|
) : (
|
|
63
70
|
<span>{mainShortcutKey}</span>
|
|
@@ -85,8 +92,36 @@ const SearchTriggerButton = styled(Button)`
|
|
|
85
92
|
}
|
|
86
93
|
`;
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
// The hidden copy of the wider label keeps the slot the same width before and after
|
|
96
|
+
// hydration on every platform, so the trigger does not shift when the label appears.
|
|
97
|
+
const SearchTriggerShortcut = styled.span`
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
align-items: flex-end;
|
|
101
|
+
|
|
102
|
+
&::after {
|
|
103
|
+
content: '${SHORTCUT_LABEL}';
|
|
104
|
+
height: 0;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
visibility: hidden;
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
|
|
110
|
+
const shortcutAppear = keyframes`
|
|
111
|
+
from {
|
|
112
|
+
opacity: 0;
|
|
113
|
+
filter: blur(2px);
|
|
114
|
+
transform: translateY(3px);
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
const SearchTriggerShortcutLabel = styled.span`
|
|
119
|
+
animation: ${shortcutAppear} var(--search-trigger-shortcut-appear-duration)
|
|
120
|
+
var(--search-trigger-shortcut-appear-easing);
|
|
121
|
+
|
|
122
|
+
@media (prefers-reduced-motion: reduce) {
|
|
123
|
+
animation: none;
|
|
124
|
+
}
|
|
90
125
|
`;
|
|
91
126
|
|
|
92
127
|
const SearchTriggerInput = styled.div`
|
|
@@ -145,6 +145,8 @@ export const search = css`
|
|
|
145
145
|
--search-trigger-bg-color: var(--navbar-bg-color);
|
|
146
146
|
--search-trigger-icon-size: 16px;
|
|
147
147
|
--search-trigger-line-height: var(--line-height-base);
|
|
148
|
+
--search-trigger-shortcut-appear-duration: 300ms;
|
|
149
|
+
--search-trigger-shortcut-appear-easing: ease-out;
|
|
148
150
|
|
|
149
151
|
/**
|
|
150
152
|
* @tokens AI Search
|
|
@@ -4,6 +4,6 @@ export const MCP_ROUTE = '/mcp';
|
|
|
4
4
|
|
|
5
5
|
export const PUBLIC_MCP_ROUTE = '/mcp-public';
|
|
6
6
|
|
|
7
|
-
export const MCP_OPTIONS = ['cursor', 'vscode', 'claude-code', 'codex', 'copy'] as const;
|
|
7
|
+
export const MCP_OPTIONS = ['cursor', 'vscode', 'claude', 'claude-code', 'codex', 'copy'] as const;
|
|
8
8
|
|
|
9
9
|
export const DEFAULT_MCP_OPTIONS = [...MCP_OPTIONS];
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
CodeWalkthroughFile,
|
|
5
5
|
CodeWalkthroughNode,
|
|
6
6
|
CodeWalkthroughConditionsObject,
|
|
7
|
-
} from '@redocly/
|
|
7
|
+
} from '@redocly/theme/core/types';
|
|
8
8
|
|
|
9
9
|
import { CodeWalkthroughControlsStateContext } from '../../contexts/CodeWalkthrough/CodeWalkthroughControlsContext';
|
|
10
10
|
import { CodeWalkthroughStepsContext } from '../../contexts/CodeWalkthrough/CodeWalkthroughStepsContext';
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
CodeWalkthroughFilterItem,
|
|
11
11
|
CodeWalkthroughConditionsObject,
|
|
12
12
|
CodeWalkthroughControlsState,
|
|
13
|
-
} from '@redocly/
|
|
13
|
+
} from '@redocly/theme/core/types';
|
|
14
14
|
|
|
15
15
|
import { downloadCodeWalkthrough } from '../../utils/download-code-walkthrough';
|
|
16
16
|
import { matchCodeWalkthroughConditions } from '../../utils/match-code-walkthrough-conditions';
|
|
@@ -98,7 +98,7 @@ export function useCodeWalkthroughControls(
|
|
|
98
98
|
Object.entries(newState).forEach(([id, control]) => {
|
|
99
99
|
const existingControl = controlsState[id];
|
|
100
100
|
if (existingControl && existingControl.type === control.type) {
|
|
101
|
-
// @ts-expect-error
|
|
101
|
+
// @ts-expect-error: TS2322 - the spread loses the link between `type` and `value` in the control union
|
|
102
102
|
newState[id] = {
|
|
103
103
|
...control,
|
|
104
104
|
value: existingControl.value,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
|
|
2
2
|
import { useLocation, useNavigate } from 'react-router';
|
|
3
3
|
|
|
4
|
-
import type { CodeWalkthroughStepAttr } from '@redocly/
|
|
4
|
+
import type { CodeWalkthroughStepAttr } from '@redocly/theme/core/types';
|
|
5
5
|
import type { ActiveStep, WalkthroughStepsState } from '../../types/code-walkthrough';
|
|
6
6
|
import type { MarkerArea } from '../../types/marker';
|
|
7
7
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
CodeWalkthroughAttr,
|
|
2
3
|
CodeWalkthroughFile,
|
|
3
4
|
CodeWalkthroughStepAttr,
|
|
4
|
-
|
|
5
|
-
} from '
|
|
6
|
-
import type { WalkthroughStepsState } from '../../types/code-walkthrough';
|
|
5
|
+
WalkthroughStepsState,
|
|
6
|
+
} from '../../types/code-walkthrough';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
useCodeWalkthroughControls,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import type { CodeWalkthroughFile } from '@redocly/
|
|
3
|
+
import type { CodeWalkthroughFile } from '@redocly/theme/core/types';
|
|
4
4
|
|
|
5
5
|
import { findClosestCommonDirectory } from '../../utils/find-closest-common-directory';
|
|
6
6
|
import { getFileIconByExt } from '../../utils/GetFileIcon';
|
|
@@ -7,7 +7,12 @@ import { useThemeHooks } from './use-theme-hooks';
|
|
|
7
7
|
import { useMCPConfig } from './use-mcp-config';
|
|
8
8
|
import { ClipboardService } from '../utils/clipboard-service';
|
|
9
9
|
import { DEFAULT_MCP_OPTIONS } from '../constants/mcp';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
generateClaudeCodeCommand,
|
|
12
|
+
generateCodexCommand,
|
|
13
|
+
generateMCPDeepLink,
|
|
14
|
+
isMCPOption,
|
|
15
|
+
} from '../utils/mcp';
|
|
11
16
|
import { getBaseDataAttributes } from '../utils/telemetry/get-base-data-attributes';
|
|
12
17
|
|
|
13
18
|
export type McpButtonOptions = {
|
|
@@ -68,6 +73,7 @@ export function useConnectMCPButton({
|
|
|
68
73
|
const urlMap: Partial<Record<MCPOption, string>> = {
|
|
69
74
|
cursor: cursorUrl,
|
|
70
75
|
vscode: vscodeUrl,
|
|
76
|
+
claude: generateMCPDeepLink('claude', connection),
|
|
71
77
|
};
|
|
72
78
|
|
|
73
79
|
window.open(urlMap[action], '_blank');
|
|
@@ -31,6 +31,7 @@ const DEFAULT_ENABLED_ACTIONS = [
|
|
|
31
31
|
'claude',
|
|
32
32
|
'docs-mcp-cursor',
|
|
33
33
|
'docs-mcp-vscode',
|
|
34
|
+
'docs-mcp-claude',
|
|
34
35
|
] as const;
|
|
35
36
|
|
|
36
37
|
export type PageActionType =
|
|
@@ -40,6 +41,7 @@ export type PageActionType =
|
|
|
40
41
|
| 'claude'
|
|
41
42
|
| 'docs-mcp-cursor'
|
|
42
43
|
| 'docs-mcp-vscode'
|
|
44
|
+
| 'docs-mcp-claude'
|
|
43
45
|
// Used in OpenAPI docs x-mcp
|
|
44
46
|
| 'mcp-cursor'
|
|
45
47
|
| 'mcp-vscode';
|
|
@@ -114,6 +116,7 @@ export function usePageActions(
|
|
|
114
116
|
const actionHandlers: Record<PageActionType, () => PageAction> = {
|
|
115
117
|
'docs-mcp-cursor': createMCPHandler('cursor', false),
|
|
116
118
|
'docs-mcp-vscode': createMCPHandler('vscode', false),
|
|
119
|
+
'docs-mcp-claude': createMCPHandler('claude', false),
|
|
117
120
|
'mcp-cursor': createMCPHandler('cursor', true),
|
|
118
121
|
'mcp-vscode': createMCPHandler('vscode', true),
|
|
119
122
|
|
|
@@ -261,6 +264,19 @@ function createMCPAction({
|
|
|
261
264
|
};
|
|
262
265
|
}
|
|
263
266
|
|
|
267
|
+
if (clientType === 'claude') {
|
|
268
|
+
return {
|
|
269
|
+
...sharedProps,
|
|
270
|
+
buttonText: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
|
|
271
|
+
title: translate('page.actions.connectMcp.claude', 'Connect to Claude'),
|
|
272
|
+
description: translate(
|
|
273
|
+
'page.actions.connectMcp.claudeDescription',
|
|
274
|
+
'Add MCP server to your Claude account',
|
|
275
|
+
),
|
|
276
|
+
iconComponent: ClaudeIcon,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
264
280
|
return {
|
|
265
281
|
...sharedProps,
|
|
266
282
|
buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'),
|
|
@@ -337,6 +353,7 @@ function shouldHideActionByType(
|
|
|
337
353
|
return !isPublic;
|
|
338
354
|
case 'docs-mcp-cursor':
|
|
339
355
|
case 'docs-mcp-vscode':
|
|
356
|
+
case 'docs-mcp-claude':
|
|
340
357
|
return Boolean(mcpUrl) || isMcpDisabled;
|
|
341
358
|
case 'mcp-cursor':
|
|
342
359
|
case 'mcp-vscode':
|
|
@@ -20,7 +20,7 @@ import { checkbox } from '@redocly/theme/icons/CheckboxIcon/variables';
|
|
|
20
20
|
import { admonition } from '@redocly/theme/components/Admonition/variables';
|
|
21
21
|
import { footer } from '@redocly/theme/components/Footer/variables';
|
|
22
22
|
import { button } from '@redocly/theme/components/Button/variables';
|
|
23
|
-
import { aiAssistantButton } from '@redocly/theme/components/Buttons/variables';
|
|
23
|
+
import { aiAssistantButton, connectMcpButton } from '@redocly/theme/components/Buttons/variables';
|
|
24
24
|
import { navbar } from '@redocly/theme/components/Navbar/variables';
|
|
25
25
|
import { search } from '@redocly/theme/components/Search/variables';
|
|
26
26
|
import { menu, mobileMenu } from '@redocly/theme/components/Menu/variables';
|
|
@@ -1343,6 +1343,7 @@ export const tokens = css`
|
|
|
1343
1343
|
${breadcrumbs}
|
|
1344
1344
|
${button}
|
|
1345
1345
|
${aiAssistantButton}
|
|
1346
|
+
${connectMcpButton}
|
|
1346
1347
|
${cards}
|
|
1347
1348
|
${catalog}
|
|
1348
1349
|
${catalogClassic}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { MarkerArea } from './marker';
|
|
2
3
|
|
|
3
4
|
export type ActiveStep = string | null;
|
|
@@ -13,3 +14,105 @@ export type WalkthroughStepsState = {
|
|
|
13
14
|
lockObserver?: React.RefObject<boolean>;
|
|
14
15
|
filtersElementRef?: React.RefObject<HTMLDivElement | null>;
|
|
15
16
|
};
|
|
17
|
+
|
|
18
|
+
export type CodeWalkthroughStepAttr = {
|
|
19
|
+
id: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type FilesetsMarkdocAttr = WithConditions<{
|
|
24
|
+
files?: string[];
|
|
25
|
+
downloadAssociatedFiles?: string[];
|
|
26
|
+
}>[];
|
|
27
|
+
|
|
28
|
+
export type InputsMarkdocAttr = {
|
|
29
|
+
[id: string]: WithConditions<{ value: string }>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type TogglesMarkdocAttr = {
|
|
33
|
+
[id: string]: CodeWalkthroughConditionsObject;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type CodeWalkthroughConditions = {
|
|
37
|
+
[key: string]: string | string[] | undefined | boolean;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type CodeWalkthroughFileset = WithConditions<{
|
|
41
|
+
files?: CodeWalkthroughFile[];
|
|
42
|
+
downloadAssociatedFiles?: CodeWalkthroughFile[];
|
|
43
|
+
}>;
|
|
44
|
+
export type CodeWalkthroughFile = {
|
|
45
|
+
path: string;
|
|
46
|
+
content: CodeWalkthroughNode[];
|
|
47
|
+
basename: string;
|
|
48
|
+
metadata: CodeWalkthroughFileMetadata;
|
|
49
|
+
language: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type CodeWalkthroughChunk = {
|
|
53
|
+
start: number;
|
|
54
|
+
children: CodeWalkthroughNode[];
|
|
55
|
+
condition: CodeWalkthroughChunkCondition;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type CodeWalkthroughChunkCondition = WithConditions<{
|
|
59
|
+
steps: string[];
|
|
60
|
+
}>;
|
|
61
|
+
|
|
62
|
+
export type CodeWalkthroughNode = CodeWalkthroughChunk | string;
|
|
63
|
+
|
|
64
|
+
export type CodeWalkthroughFileMetadata = {
|
|
65
|
+
steps: string[];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type CodeWalkthroughFilter = WithConditions<{
|
|
69
|
+
id: string;
|
|
70
|
+
label?: string;
|
|
71
|
+
items: CodeWalkthroughFilterItem[];
|
|
72
|
+
}>;
|
|
73
|
+
|
|
74
|
+
export type CodeWalkthroughFilterItem = WithConditions<{
|
|
75
|
+
value: string;
|
|
76
|
+
}>;
|
|
77
|
+
|
|
78
|
+
export type CodeWalkthroughConditionsObject = {
|
|
79
|
+
when?: CodeWalkthroughConditions;
|
|
80
|
+
unless?: CodeWalkthroughConditions;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type WithConditions<T> = T & CodeWalkthroughConditionsObject;
|
|
84
|
+
|
|
85
|
+
export type CodeWalkthroughControls = {
|
|
86
|
+
toggle: boolean;
|
|
87
|
+
input: string;
|
|
88
|
+
filter: string;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type CodeWalkthroughControlState = WithConditions<
|
|
92
|
+
| {
|
|
93
|
+
value: string;
|
|
94
|
+
render: boolean;
|
|
95
|
+
type: 'input';
|
|
96
|
+
}
|
|
97
|
+
| {
|
|
98
|
+
value: string;
|
|
99
|
+
render: boolean;
|
|
100
|
+
type: 'filter';
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
value: boolean;
|
|
104
|
+
render: boolean;
|
|
105
|
+
type: 'toggle';
|
|
106
|
+
}
|
|
107
|
+
>;
|
|
108
|
+
export type CodeWalkthroughControlsState = Record<string, CodeWalkthroughControlState>;
|
|
109
|
+
|
|
110
|
+
export type CodeWalkthroughAttr = {
|
|
111
|
+
steps: CodeWalkthroughStepAttr[];
|
|
112
|
+
filters: Record<string, CodeWalkthroughFilter>;
|
|
113
|
+
filesets: CodeWalkthroughFileset[];
|
|
114
|
+
preview: ReactNode[];
|
|
115
|
+
inputs: InputsMarkdocAttr;
|
|
116
|
+
toggles: TogglesMarkdocAttr;
|
|
117
|
+
__idx: number;
|
|
118
|
+
};
|