@redocly/theme 0.58.0-next.1 → 0.58.0-next.11
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/Catalog/Catalog.d.ts +2 -2
- package/lib/components/Catalog/Catalog.js +6 -4
- package/lib/components/Catalog/CatalogCardView/CatalogCard.js +15 -14
- package/lib/components/Catalog/CatalogEntity/CatalogEntity.d.ts +5 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +4 -4
- package/lib/components/Catalog/CatalogEntity/CatalogEntityLinks.js +0 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +3 -4
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.js +0 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityProperties/CatalogEntityPropertyCard.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.d.ts +5 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +9 -7
- package/lib/components/Catalog/CatalogEntityIcon.d.ts +2 -0
- package/lib/components/Catalog/CatalogEntityIcon.js +31 -14
- package/lib/components/Catalog/CatalogEntityTypeIcon.js +19 -6
- package/lib/components/Catalog/CatalogEntityTypeTag.js +9 -3
- package/lib/components/Catalog/CatalogSelector.d.ts +1 -1
- package/lib/components/Catalog/CatalogTableView/CatalogEntityCell.js +1 -1
- package/lib/components/Catalog/CatalogViewModeToggle.d.ts +1 -1
- package/lib/components/Catalog/variables.js +9 -6
- package/lib/components/CatalogClassic/CatalogClassic.js +9 -2
- package/lib/components/CodeBlock/CodeBlock.d.ts +5 -12
- package/lib/components/CodeBlock/CodeBlockControls.d.ts +3 -3
- package/lib/components/CodeBlock/CodeBlockControls.js +1 -1
- package/lib/components/CodeBlock/CodeBlockDropdown.d.ts +2 -2
- package/lib/components/CodeBlock/CodeBlockDropdown.js +4 -13
- package/lib/components/CodeBlock/CodeBlockTabs.d.ts +2 -2
- package/lib/components/CodeBlock/CodeBlockTabs.js +4 -3
- package/lib/components/JsonViewer/JsonViewer.d.ts +1 -1
- package/lib/components/JsonViewer/JsonViewer.js +9 -10
- package/lib/components/PageActions/PageActions.d.ts +4 -1
- package/lib/components/PageActions/PageActions.js +2 -2
- package/lib/components/Search/SearchDialog.js +12 -6
- package/lib/components/Search/SearchFilter.js +2 -1
- package/lib/components/Tooltip/Tooltip.js +7 -9
- package/lib/components/Tooltip/TooltipWrapper.js +1 -1
- package/lib/core/constants/catalog.d.ts +1 -1
- package/lib/core/constants/catalog.js +13 -27
- package/lib/core/contexts/CodeSnippetContext.d.ts +14 -6
- package/lib/core/contexts/CodeSnippetContext.js +57 -14
- package/lib/core/hooks/catalog/useCatalogTableViewRow.js +1 -1
- package/lib/core/hooks/use-active-section-id.js +4 -0
- package/lib/core/hooks/use-codeblock-tabs-controls.d.ts +2 -2
- package/lib/core/hooks/use-control.js +17 -2
- package/lib/core/hooks/use-local-state.js +22 -18
- package/lib/core/hooks/use-page-actions.d.ts +2 -1
- package/lib/core/hooks/use-page-actions.js +48 -6
- package/lib/core/hooks/use-telemetry-fallback.d.ts +5 -0
- package/lib/core/hooks/use-telemetry-fallback.js +5 -0
- package/lib/core/openapi/index.d.ts +9 -4
- package/lib/core/openapi/index.js +11 -9
- package/lib/core/styles/global.js +19 -0
- package/lib/core/types/catalog.d.ts +1 -1
- package/lib/core/types/hooks.d.ts +2 -2
- package/lib/core/types/index.d.ts +1 -0
- package/lib/core/types/index.js +1 -0
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/open-api-info.d.ts +34 -0
- package/lib/core/types/open-api-info.js +3 -0
- package/lib/core/types/open-api-server.d.ts +1 -0
- package/lib/core/types/search.d.ts +2 -3
- package/lib/core/utils/urls.js +1 -1
- package/lib/ext/useConfigureReplay.d.ts +2 -1
- package/lib/icons/CursorIcon/CursorIcon.d.ts +9 -0
- package/lib/icons/CursorIcon/CursorIcon.js +22 -0
- package/lib/icons/HierarchyIcon/HierarchyIcon.d.ts +9 -0
- package/lib/icons/HierarchyIcon/HierarchyIcon.js +23 -0
- package/lib/icons/NoteIcon/NoteIcon.d.ts +9 -0
- package/lib/icons/NoteIcon/NoteIcon.js +24 -0
- package/lib/icons/ShareIcon/ShareIcon.d.ts +9 -0
- package/lib/icons/ShareIcon/ShareIcon.js +22 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/layouts/DocumentationLayout.js +1 -3
- package/lib/markdoc/components/CodeGroup/CodeGroup.js +49 -27
- package/lib/markdoc/components/Tabs/TabList.js +2 -0
- package/lib/markdoc/components/Tabs/Tabs.d.ts +2 -1
- package/lib/markdoc/components/Tabs/Tabs.js +3 -2
- package/package.json +4 -4
- package/src/components/Catalog/Catalog.tsx +18 -6
- package/src/components/Catalog/CatalogCardView/CatalogCard.tsx +20 -19
- package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +15 -2
- package/src/components/Catalog/CatalogEntity/CatalogEntityLinks.tsx +0 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityMetadata.tsx +3 -4
- package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +0 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityProperties/CatalogEntityPropertyCard.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +27 -18
- package/src/components/Catalog/CatalogEntityIcon.tsx +53 -18
- package/src/components/Catalog/CatalogEntityTypeIcon.tsx +19 -8
- package/src/components/Catalog/CatalogEntityTypeTag.tsx +11 -3
- package/src/components/Catalog/CatalogSelector.tsx +1 -1
- package/src/components/Catalog/CatalogTableView/CatalogEntityCell.tsx +1 -1
- package/src/components/Catalog/CatalogViewModeToggle.tsx +1 -1
- package/src/components/Catalog/variables.ts +9 -6
- package/src/components/CatalogClassic/CatalogClassic.tsx +26 -10
- package/src/components/CodeBlock/CodeBlock.tsx +5 -11
- package/src/components/CodeBlock/CodeBlockControls.tsx +4 -7
- package/src/components/CodeBlock/CodeBlockDropdown.tsx +11 -20
- package/src/components/CodeBlock/CodeBlockTabs.tsx +8 -8
- package/src/components/JsonViewer/JsonViewer.tsx +16 -9
- package/src/components/PageActions/PageActions.tsx +6 -4
- package/src/components/Search/SearchDialog.tsx +14 -5
- package/src/components/Search/SearchFilter.tsx +2 -1
- package/src/components/Tooltip/Tooltip.tsx +6 -8
- package/src/components/Tooltip/TooltipWrapper.tsx +1 -1
- package/src/core/constants/catalog.ts +13 -27
- package/src/core/contexts/CodeSnippetContext.tsx +54 -18
- package/src/core/hooks/catalog/useCatalogTableViewRow.ts +1 -1
- package/src/core/hooks/use-active-section-id.ts +6 -0
- package/src/core/hooks/use-codeblock-tabs-controls.ts +2 -2
- package/src/core/hooks/use-control.ts +21 -3
- package/src/core/hooks/use-local-state.ts +28 -19
- package/src/core/hooks/use-page-actions.ts +63 -6
- package/src/core/hooks/use-telemetry-fallback.ts +5 -0
- package/src/core/openapi/index.ts +9 -4
- package/src/core/styles/global.ts +19 -0
- package/src/core/types/catalog.ts +1 -2
- package/src/core/types/hooks.ts +6 -1
- package/src/core/types/index.ts +1 -0
- package/src/core/types/l10n.ts +16 -0
- package/src/core/types/open-api-info.ts +34 -0
- package/src/core/types/open-api-server.ts +1 -0
- package/src/core/types/search.ts +3 -3
- package/src/core/utils/urls.ts +2 -1
- package/src/ext/useConfigureReplay.ts +2 -1
- package/src/icons/CursorIcon/CursorIcon.tsx +35 -0
- package/src/icons/HierarchyIcon/HierarchyIcon.tsx +32 -0
- package/src/icons/NoteIcon/NoteIcon.tsx +35 -0
- package/src/icons/ShareIcon/ShareIcon.tsx +23 -0
- package/src/index.ts +2 -0
- package/src/layouts/DocumentationLayout.tsx +3 -10
- package/src/markdoc/components/CodeGroup/CodeGroup.tsx +81 -52
- package/src/markdoc/components/Tabs/TabList.tsx +1 -0
- package/src/markdoc/components/Tabs/Tabs.tsx +10 -2
|
@@ -1,31 +1,67 @@
|
|
|
1
|
-
import { createContext, useContext,
|
|
1
|
+
import React, { createContext, useContext, useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
activeSnippetName: string;
|
|
5
|
-
setActiveSnippetName: (name: string) => void;
|
|
6
|
-
};
|
|
3
|
+
import { useLocalState } from '../hooks/use-local-state';
|
|
7
4
|
|
|
8
5
|
export const CODE_GROUP_SNIPPET_NAME_KEY = 'redocly:codeGroupSnippetName';
|
|
9
6
|
|
|
7
|
+
type CodeSnippetContextType = {
|
|
8
|
+
activeSnippets: Record<string, string>;
|
|
9
|
+
setActiveSnippet: (groupId: string, snippetId: string) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
10
12
|
export const CodeSnippetContext = createContext<CodeSnippetContextType | null>(null);
|
|
11
13
|
|
|
12
|
-
export function
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
export function CodeSnippetProvider({ children }: { children: React.ReactNode }) {
|
|
15
|
+
const [activeSnippets, setActiveSnippets] = useLocalState<Record<string, string>>(
|
|
16
|
+
CODE_GROUP_SNIPPET_NAME_KEY,
|
|
17
|
+
{},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const setActiveSnippet = useCallback(
|
|
21
|
+
(groupId: string, snippetId: string) => {
|
|
22
|
+
setActiveSnippets({ ...activeSnippets, [groupId]: snippetId });
|
|
23
|
+
},
|
|
24
|
+
[activeSnippets, setActiveSnippets],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const contextValue = { activeSnippets, setActiveSnippet };
|
|
28
|
+
|
|
29
|
+
return <CodeSnippetContext.Provider value={contextValue}>{children}</CodeSnippetContext.Provider>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const useCodeSnippetContext = (): CodeSnippetContextType => {
|
|
15
33
|
const context = useContext(CodeSnippetContext);
|
|
34
|
+
|
|
16
35
|
if (!context) {
|
|
17
36
|
throw new Error('useCodeSnippetContext must be used within a CodeSnippetContext');
|
|
18
37
|
}
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
|
|
39
|
+
return context;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const useActiveCodeSnippetId = (
|
|
43
|
+
groupId?: string,
|
|
44
|
+
availableSnippets?: { id: string }[],
|
|
45
|
+
): [string, (id: string) => void] => {
|
|
46
|
+
const { activeSnippets, setActiveSnippet } = useCodeSnippetContext();
|
|
47
|
+
|
|
48
|
+
const storedSnippetId = groupId ? activeSnippets[groupId] || '' : '';
|
|
49
|
+
|
|
50
|
+
const activeId = useMemo(() => {
|
|
51
|
+
if (!availableSnippets?.length) return storedSnippetId;
|
|
52
|
+
|
|
53
|
+
const found = storedSnippetId && availableSnippets.find((s) => s.id === storedSnippetId);
|
|
54
|
+
return found ? storedSnippetId : availableSnippets[0]?.id || '';
|
|
55
|
+
}, [storedSnippetId, availableSnippets]);
|
|
56
|
+
|
|
57
|
+
const setActiveSnippetId = useCallback(
|
|
58
|
+
(id: string) => {
|
|
59
|
+
if (groupId) {
|
|
60
|
+
setActiveSnippet(groupId, id);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
[groupId, setActiveSnippet],
|
|
22
64
|
);
|
|
23
65
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return [activeSnippetName, setActiveSnippetName];
|
|
27
|
-
} else {
|
|
28
|
-
// use global synced state for dropdown mode
|
|
29
|
-
return [context.activeSnippetName, context.setActiveSnippetName];
|
|
30
|
-
}
|
|
31
|
-
}
|
|
66
|
+
return [activeId, setActiveSnippetId];
|
|
67
|
+
};
|
|
@@ -21,7 +21,7 @@ export function useCatalogTableViewRow({
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return Object.values(entitiesCatalogConfig.catalogs ?? {}).find((catalog) => {
|
|
24
|
-
return catalog
|
|
24
|
+
return catalog?.includes?.some((include) => include.type === entityType);
|
|
25
25
|
});
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -25,6 +25,12 @@ export function useActiveSectionId(
|
|
|
25
25
|
setItemId('');
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
if (window.scrollY <= 0) {
|
|
30
|
+
setItemId(sections[0].getAttribute('data-section-id') || '');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
for (let i = 0; i < sections.length; i++) {
|
|
29
35
|
const section = sections[i];
|
|
30
36
|
const rect = section.getBoundingClientRect();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useEffect, useState, useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { CodeBlockItems } from '../../components/CodeBlock/CodeBlock';
|
|
4
4
|
|
|
5
5
|
type CodeBlockTabsProps = {
|
|
6
|
-
tabs:
|
|
6
|
+
tabs: CodeBlockItems;
|
|
7
7
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
8
8
|
tabRefs: React.RefObject<HTMLButtonElement[]>;
|
|
9
9
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { useState, useCallback } from 'react';
|
|
1
|
+
import { useState, useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_CONTROL_OPEN_DELAY = 300;
|
|
2
4
|
|
|
3
5
|
export type UseControlReturnType = {
|
|
4
6
|
isOpened: boolean;
|
|
@@ -8,9 +10,25 @@ export type UseControlReturnType = {
|
|
|
8
10
|
|
|
9
11
|
export const useControl = (initialVal = false): UseControlReturnType => {
|
|
10
12
|
const [isOpened, setIsOpened] = useState<boolean>(initialVal);
|
|
13
|
+
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
14
|
+
|
|
15
|
+
const clearOpenTimer = useCallback(() => {
|
|
16
|
+
if (timeoutRef.current) {
|
|
17
|
+
clearTimeout(timeoutRef.current);
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
const handleOpen = useCallback(() => {
|
|
22
|
+
clearOpenTimer();
|
|
23
|
+
timeoutRef.current = setTimeout(() => {
|
|
24
|
+
setIsOpened(true);
|
|
25
|
+
}, DEFAULT_CONTROL_OPEN_DELAY);
|
|
26
|
+
}, [clearOpenTimer]);
|
|
11
27
|
|
|
12
|
-
const
|
|
13
|
-
|
|
28
|
+
const handleClose = useCallback(() => {
|
|
29
|
+
clearOpenTimer();
|
|
30
|
+
setIsOpened(false);
|
|
31
|
+
}, [clearOpenTimer]);
|
|
14
32
|
|
|
15
33
|
return {
|
|
16
34
|
isOpened,
|
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
import { isBrowser } from '../utils/js-utils';
|
|
4
|
+
|
|
5
|
+
function getStoredValue<T>(key: string, fallback: T): T {
|
|
6
|
+
if (!isBrowser()) return fallback;
|
|
2
7
|
|
|
3
|
-
function getInitialValue<T>(key: string, initialValue: T): T {
|
|
4
|
-
if (typeof window === 'undefined') {
|
|
5
|
-
return initialValue;
|
|
6
|
-
}
|
|
7
8
|
try {
|
|
8
9
|
const savedValue = localStorage.getItem(key);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} catch (error) {
|
|
13
|
-
console.error(`Error reading from localStorage for key "${key}":`, error);
|
|
10
|
+
return savedValue ? (JSON.parse(savedValue) as T) : fallback;
|
|
11
|
+
} catch {
|
|
12
|
+
return fallback;
|
|
14
13
|
}
|
|
15
|
-
return initialValue;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
export function useLocalState<T>(key: string, initialValue: T): [T, (value: T) => void] {
|
|
19
|
-
const [value, setValue] = useState<T>(
|
|
17
|
+
const [value, setValue] = useState<T>(initialValue);
|
|
20
18
|
|
|
19
|
+
// Load stored value from localStorage after component mounts
|
|
20
|
+
// This ensures SSR compatibility: server and client both start with initialValue,
|
|
21
|
+
// then client loads the actual stored value without hydration mismatch
|
|
21
22
|
useEffect(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
if (!isBrowser()) return;
|
|
24
|
+
setValue(getStoredValue(key, initialValue));
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
}, [key]);
|
|
27
|
+
|
|
28
|
+
const handleSetValue = useCallback(
|
|
29
|
+
(newValue: T) => {
|
|
30
|
+
setValue(newValue);
|
|
31
|
+
if (isBrowser()) {
|
|
32
|
+
localStorage.setItem(key, JSON.stringify(newValue));
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
[key],
|
|
36
|
+
);
|
|
28
37
|
|
|
29
|
-
return [value,
|
|
38
|
+
return [value, handleSetValue] as const;
|
|
30
39
|
}
|
|
@@ -12,10 +12,19 @@ import { useThemeHooks } from './use-theme-hooks';
|
|
|
12
12
|
import { useThemeConfig } from './use-theme-config';
|
|
13
13
|
import { ClipboardService } from '../utils/clipboard-service';
|
|
14
14
|
import { IS_BROWSER } from '../utils/dom';
|
|
15
|
+
import { CursorIcon } from '../../icons/CursorIcon/CursorIcon';
|
|
15
16
|
|
|
16
17
|
const DEFAULT_ENABLED_ACTIONS = ['copy', 'view', 'chatgpt', 'claude'] as const;
|
|
18
|
+
const CURSOR_URL =
|
|
19
|
+
'cursor://anysphere.cursor-deeplink/mcp/install?name=$NAME&config=$BASE64_ENCODED_CONFIG';
|
|
17
20
|
|
|
18
|
-
export
|
|
21
|
+
export type PageActionType = 'copy' | 'view' | 'chatgpt' | 'claude' | 'mcp-cursor';
|
|
22
|
+
|
|
23
|
+
export function usePageActions(
|
|
24
|
+
pageSlug: string,
|
|
25
|
+
mcpUrl?: string,
|
|
26
|
+
actions?: PageActionType[],
|
|
27
|
+
): PageAction[] {
|
|
19
28
|
const { useTranslate, usePageData, usePageProps, usePageSharedData } = useThemeHooks();
|
|
20
29
|
const { translate } = useTranslate();
|
|
21
30
|
|
|
@@ -32,7 +41,7 @@ export function usePageActions(pageSlug: string): PageAction[] {
|
|
|
32
41
|
);
|
|
33
42
|
const { isPublic } = usePageData() || {};
|
|
34
43
|
|
|
35
|
-
const
|
|
44
|
+
const result: PageAction[] = useMemo(() => {
|
|
36
45
|
if (shouldHideAllActions) {
|
|
37
46
|
return [];
|
|
38
47
|
}
|
|
@@ -54,9 +63,49 @@ export function usePageActions(pageSlug: string): PageAction[] {
|
|
|
54
63
|
return url.toString();
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
return (themeConfig.navigation?.actions?.items || DEFAULT_ENABLED_ACTIONS)
|
|
66
|
+
return (themeConfig.navigation?.actions?.items || actions || DEFAULT_ENABLED_ACTIONS)
|
|
58
67
|
.map((action) => {
|
|
68
|
+
function generateMCPConfig(isCursor?: boolean): string {
|
|
69
|
+
const jsonConfig = {
|
|
70
|
+
'mcp-server': {
|
|
71
|
+
url: mcpUrl,
|
|
72
|
+
description: 'MCP Server',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
if (isCursor) {
|
|
76
|
+
const url = CURSOR_URL.replace('$NAME', 'mcp-server').replace(
|
|
77
|
+
'$BASE64_ENCODED_CONFIG',
|
|
78
|
+
btoa(JSON.stringify(jsonConfig['mcp-server'])),
|
|
79
|
+
);
|
|
80
|
+
return url;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return JSON.stringify(jsonConfig, null, 2);
|
|
84
|
+
}
|
|
85
|
+
|
|
59
86
|
switch (action) {
|
|
87
|
+
case 'mcp-cursor':
|
|
88
|
+
if (!mcpUrl) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
buttonText: translate('page.actions.cursorMcpButtonText', 'Connect to Cursor'),
|
|
94
|
+
title: translate('page.actions.cursorMcpTitle', 'Connect to Cursor'),
|
|
95
|
+
description: translate(
|
|
96
|
+
'page.actions.cursorMcpDescription',
|
|
97
|
+
'Install MCP server on Cursor',
|
|
98
|
+
),
|
|
99
|
+
iconComponent: CursorIcon,
|
|
100
|
+
onClick: () => {
|
|
101
|
+
try {
|
|
102
|
+
const url = generateMCPConfig(true);
|
|
103
|
+
window.open(url, '_blank');
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(error);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
60
109
|
case 'copy':
|
|
61
110
|
return {
|
|
62
111
|
buttonText: translate('page.actions.copyButtonText', 'Copy'),
|
|
@@ -121,9 +170,17 @@ export function usePageActions(pageSlug: string): PageAction[] {
|
|
|
121
170
|
}
|
|
122
171
|
})
|
|
123
172
|
.filter((action) => action !== null);
|
|
124
|
-
}, [
|
|
125
|
-
|
|
126
|
-
|
|
173
|
+
}, [
|
|
174
|
+
shouldHideAllActions,
|
|
175
|
+
pageSlug,
|
|
176
|
+
themeConfig.navigation?.actions?.items,
|
|
177
|
+
actions,
|
|
178
|
+
mcpUrl,
|
|
179
|
+
translate,
|
|
180
|
+
isPublic,
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
return result;
|
|
127
184
|
}
|
|
128
185
|
|
|
129
186
|
function shouldHidePageActions(
|
|
@@ -58,4 +58,9 @@ export const useTelemetryFallback = () => ({
|
|
|
58
58
|
sendAsyncapiDocsMessageClickedMessage: () => {},
|
|
59
59
|
sendAsyncapiDocsServerModalOpenedMessage: () => {},
|
|
60
60
|
sendAsyncapiDocsDownloadDefinitionClickedMessage: () => {},
|
|
61
|
+
sendGraphqlDocsViewedMessage: () => {},
|
|
62
|
+
sendGraphqlDocsPerformanceMetricsMessage: () => {},
|
|
63
|
+
sendGraphqlDocsReferencedInLinkClickedMessage: () => {},
|
|
64
|
+
sendGraphqlDocsRequiredScopesModalOpenedMessage: () => {},
|
|
65
|
+
sendGraphqlDocsDownloadDefinitionClickedMessage: () => {},
|
|
61
66
|
});
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
// This selective import approach will help with tree shaking and reduce
|
|
5
5
|
// the overall bundle size by avoiding importing the entire theme package
|
|
6
6
|
// when only specific functionality is needed.
|
|
7
|
+
export type { UserClaims } from '../types/user-claims';
|
|
8
|
+
export type { OperationParameter, ParameterHighlight } from '../types/search';
|
|
9
|
+
export type { TFunction, TOptions } from '../types/l10n';
|
|
10
|
+
export type { SelectOption, SelectProps } from '../types/select';
|
|
7
11
|
export { IS_BROWSER } from '../utils/dom';
|
|
8
12
|
export {
|
|
9
13
|
addLeadingSlash,
|
|
@@ -13,20 +17,21 @@ export {
|
|
|
13
17
|
addTrailingSlash,
|
|
14
18
|
withPathPrefix,
|
|
15
19
|
} from '../utils/urls';
|
|
20
|
+
export { capitalize } from '../utils/string';
|
|
16
21
|
export { typedMemo } from '../hoc/typedMemo';
|
|
17
22
|
export { useMount } from '../hooks/use-mount';
|
|
18
23
|
export { GlobalStyle } from '../styles/global';
|
|
19
24
|
export { breakpoints } from '../utils/media-css';
|
|
20
25
|
export { isPrimitive } from '../utils/args-typecheck';
|
|
21
|
-
export
|
|
26
|
+
export { ClipboardService } from '../utils/clipboard-service';
|
|
27
|
+
export { getUserAgent } from '../utils/get-user-agent';
|
|
22
28
|
export { useFocusTrap } from '../hooks/use-focus-trap';
|
|
23
|
-
export type { TFunction, TOptions } from '../types/l10n';
|
|
24
29
|
export { useThemeHooks } from '../hooks/use-theme-hooks';
|
|
25
30
|
export { useOutsideClick } from '../hooks/use-outside-click';
|
|
26
|
-
export type { SelectOption, SelectProps } from '../types/select';
|
|
27
31
|
export { useActiveSectionId } from '../hooks/use-active-section-id';
|
|
28
32
|
export { useModalScrollLock } from '../hooks/use-modal-scroll-lock';
|
|
33
|
+
export { useSearchDialog } from '../hooks/search/use-search-dialog';
|
|
34
|
+
export { useDialogHotKeys } from '../hooks/use-dialog-hotkeys';
|
|
29
35
|
export { SecurityVariablesEnvSuffix } from '../constants/environments';
|
|
30
36
|
export { isUndefined, isString, isNotNull, isObject } from '../utils/type-guards';
|
|
31
37
|
export { ThemeDataContext, type ThemeDataTransferObject } from '../contexts/ThemeDataContext';
|
|
32
|
-
export { ENTITY_RELATION_TYPES } from '../constants/catalog';
|
|
@@ -780,6 +780,25 @@ const apiReferenceDocs = css`
|
|
|
780
780
|
--fab-icon-color: var(--navbar-text-color); // @presenter Color
|
|
781
781
|
|
|
782
782
|
// @tokens End
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* @tokens OpenAPI Schema Catalog Link
|
|
786
|
+
*/
|
|
787
|
+
|
|
788
|
+
--schema-catalog-link-margin-bottom: var(--spacing-lg);
|
|
789
|
+
--schema-catalog-link-padding: 2px;
|
|
790
|
+
--schema-catalog-link-border-radius: var(--border-radius-md);
|
|
791
|
+
--schema-catalog-link-background-color: var(--layer-color);
|
|
792
|
+
--schema-catalog-link-color: var(--color-purple-7);
|
|
793
|
+
|
|
794
|
+
--schema-catalog-link-share-icon-color: var(--color-purple-7);
|
|
795
|
+
--schema-catalog-link-share-icon-background-color: var(--color-purple-1);
|
|
796
|
+
--schema-catalog-link-share-icon-border-radius: var(--border-radius-md);
|
|
797
|
+
--schema-catalog-link-share-icon-wrapper-size: var(--spacing-xl);
|
|
798
|
+
|
|
799
|
+
--schema-catalog-link-text-color: var(--text-color-primary);
|
|
800
|
+
|
|
801
|
+
// @tokens End
|
|
783
802
|
`;
|
|
784
803
|
|
|
785
804
|
const badges = css`
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query';
|
|
2
2
|
import { CatalogEntityConfig, LayoutVariant } from '@redocly/config';
|
|
3
|
+
import { ENTITY_RELATION_TYPES } from '@redocly/config';
|
|
3
4
|
|
|
4
5
|
import type { CatalogFilterConfig } from '@redocly/theme/config';
|
|
5
6
|
|
|
6
|
-
import { ENTITY_RELATION_TYPES } from '../constants/catalog';
|
|
7
|
-
|
|
8
7
|
export type SortOption = 'title' | '-title' | 'type' | '-type';
|
|
9
8
|
|
|
10
9
|
export type UseCatalogResponse = {
|
package/src/core/types/hooks.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
FilteredCatalog,
|
|
18
18
|
UseCatalogSortResponse,
|
|
19
19
|
UseCatalogSearchResponse,
|
|
20
|
+
CatalogViewMode,
|
|
20
21
|
} from './catalog';
|
|
21
22
|
import type { UserMenuData } from './user-menu';
|
|
22
23
|
import type { ItemState } from './sidebar';
|
|
@@ -139,7 +140,11 @@ export type ThemeHooks = {
|
|
|
139
140
|
nextPage?: ResolvedNavItemWithLink;
|
|
140
141
|
}
|
|
141
142
|
| undefined;
|
|
142
|
-
useCatalog: (
|
|
143
|
+
useCatalog: (
|
|
144
|
+
config?: CatalogEntityConfig,
|
|
145
|
+
entitiesCounterInitial?: number,
|
|
146
|
+
initialViewMode?: CatalogViewMode,
|
|
147
|
+
) => UseCatalogResponse;
|
|
143
148
|
useCatalogSort: () => UseCatalogSortResponse;
|
|
144
149
|
useCatalogSearch: () => UseCatalogSearchResponse;
|
|
145
150
|
useFetchCatalogEntities: (
|
package/src/core/types/index.ts
CHANGED
package/src/core/types/l10n.ts
CHANGED
|
@@ -206,6 +206,9 @@ export type TranslationKey =
|
|
|
206
206
|
| 'page.actions.claudeTitle'
|
|
207
207
|
| 'page.actions.claudeButtonText'
|
|
208
208
|
| 'page.actions.claudeDescription'
|
|
209
|
+
| 'page.actions.cursorMcpButtonText'
|
|
210
|
+
| 'page.actions.cursorMcpTitle'
|
|
211
|
+
| 'page.actions.cursorMcpDescription'
|
|
209
212
|
| 'openapi.download.description.title'
|
|
210
213
|
| 'openapi.info.title'
|
|
211
214
|
| 'openapi.info.contact.url'
|
|
@@ -280,6 +283,19 @@ export type TranslationKey =
|
|
|
280
283
|
| 'openapi.requiredScopes'
|
|
281
284
|
| 'openapi.unsupportedLanguage'
|
|
282
285
|
| 'openapi.failedToGenerateCodeSample'
|
|
286
|
+
| 'openapi.schemaCatalogLink.title'
|
|
287
|
+
| 'openapi.schemaCatalogLink.copyButtonTooltip'
|
|
288
|
+
| 'openapi.schemaCatalogLink.copiedTooltip'
|
|
289
|
+
| 'openapi.mcp.title'
|
|
290
|
+
| 'openapi.mcp.endpoint'
|
|
291
|
+
| 'openapi.mcp.tools'
|
|
292
|
+
| 'openapi.mcp.protocolVersion'
|
|
293
|
+
| 'openapi.mcp.capabilities'
|
|
294
|
+
| 'openapi.mcp.experimentalCapabilities'
|
|
295
|
+
| 'openapi.mcp.inputSchema'
|
|
296
|
+
| 'openapi.mcp.inputExample'
|
|
297
|
+
| 'openapi.mcp.outputSchema'
|
|
298
|
+
| 'openapi.mcp.outputExample'
|
|
283
299
|
| 'asyncapi.download.description.title'
|
|
284
300
|
| 'asyncapi.info.title'
|
|
285
301
|
| 'graphql.queries'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type OpenAPIInfo = {
|
|
2
|
+
title: string;
|
|
3
|
+
version: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
summary?: string;
|
|
6
|
+
termsOfService?: string;
|
|
7
|
+
contact?: {
|
|
8
|
+
name?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
email?: string;
|
|
11
|
+
};
|
|
12
|
+
license?: {
|
|
13
|
+
name: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
identifier?: string;
|
|
16
|
+
};
|
|
17
|
+
externalDocs?: {
|
|
18
|
+
description?: string;
|
|
19
|
+
url: string;
|
|
20
|
+
};
|
|
21
|
+
'x-logo'?: {
|
|
22
|
+
url?: string;
|
|
23
|
+
backgroundColor?: string;
|
|
24
|
+
altText?: string;
|
|
25
|
+
href?: string;
|
|
26
|
+
};
|
|
27
|
+
'x-metadata'?: {
|
|
28
|
+
apiId?: string;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
'x-seo'?: {
|
|
32
|
+
title?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
package/src/core/types/search.ts
CHANGED
|
@@ -15,7 +15,8 @@ export type OperationParameter = {
|
|
|
15
15
|
enum: string[] | undefined;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// TODO: review SearchHit type as it might contain properties that are not in the search results
|
|
19
|
+
export type SearchHit = {
|
|
19
20
|
id: string;
|
|
20
21
|
url: string;
|
|
21
22
|
title: string | string[];
|
|
@@ -26,7 +27,6 @@ export type SearchDocument = {
|
|
|
26
27
|
deprecated?: boolean;
|
|
27
28
|
security?: string[];
|
|
28
29
|
parameters?: OperationParameter[];
|
|
29
|
-
metadata?: Record<string, any>;
|
|
30
30
|
version?: string;
|
|
31
31
|
versionFolderId?: string;
|
|
32
32
|
isDefaultVersion?: boolean;
|
|
@@ -47,7 +47,7 @@ export type ParameterHighlight = {
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
export type SearchItemData = {
|
|
50
|
-
document:
|
|
50
|
+
document: SearchHit;
|
|
51
51
|
highlight: Record<string, string> & { parameters?: ParameterHighlight[]; path?: string[] };
|
|
52
52
|
};
|
|
53
53
|
|
package/src/core/utils/urls.ts
CHANGED
|
@@ -54,8 +54,9 @@ export function addLeadingSlash(url: string): string {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function removeTrailingSlash(url: string): string {
|
|
57
|
-
return url.endsWith('/') ? url.substring(0, url.length - 1) : url;
|
|
57
|
+
return url.endsWith('/') && url !== '/' ? url.substring(0, url.length - 1) : url;
|
|
58
58
|
}
|
|
59
|
+
|
|
59
60
|
export function removeLeadingSlash(url: string): string {
|
|
60
61
|
return url.startsWith('/') ? url.substring(1) : url;
|
|
61
62
|
}
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
ConfigureRequestValues,
|
|
5
5
|
ConfigureServerRequestValues,
|
|
6
6
|
} from '@redocly/theme/ext/configure';
|
|
7
|
-
import type { UserClaims, OpenAPIServer } from '@redocly/theme/core/types';
|
|
7
|
+
import type { UserClaims, OpenAPIServer, OpenAPIInfo } from '@redocly/theme/core/types';
|
|
8
8
|
|
|
9
9
|
type ContextProps = {
|
|
10
10
|
operation: {
|
|
@@ -14,6 +14,7 @@ type ContextProps = {
|
|
|
14
14
|
href: string;
|
|
15
15
|
method: string;
|
|
16
16
|
};
|
|
17
|
+
info: OpenAPIInfo;
|
|
17
18
|
servers: OpenAPIServer[];
|
|
18
19
|
userClaims: UserClaims;
|
|
19
20
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { IconProps } from '@redocly/theme/icons/types';
|
|
5
|
+
|
|
6
|
+
const Icon = (props: IconProps) => (
|
|
7
|
+
<svg
|
|
8
|
+
width="16"
|
|
9
|
+
height="16"
|
|
10
|
+
viewBox="0 0 16 16"
|
|
11
|
+
fill="none"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
{...props}
|
|
14
|
+
>
|
|
15
|
+
<path d="M7.99956 15V8.0001L2 11.4999L7.99956 15Z" fill="#939393" />
|
|
16
|
+
<path d="M14 4.49979L7.99956 15V8.0001L14 4.49979Z" fill="#E3E3E3" />
|
|
17
|
+
<path d="M2 4.49979H14L7.99956 8.0001L2 4.49979Z" fill="white" />
|
|
18
|
+
<path d="M8.00025 1V4.49995L14 4.49979L8.00025 1Z" fill="#444444" />
|
|
19
|
+
<path
|
|
20
|
+
d="M2 4.49979L8.00025 4.49995V1L2 4.49979ZM13.9999 11.4998L10.9999 9.74987L7.99956 15L13.9999 11.4998Z"
|
|
21
|
+
fill="#939393"
|
|
22
|
+
/>
|
|
23
|
+
<path
|
|
24
|
+
d="M14 4.49979L10.9999 9.74987L13.9999 11.4998L14 4.49979ZM7.99956 8.0001L2 11.4999V4.49979L7.99956 8.0001Z"
|
|
25
|
+
fill="#444444"
|
|
26
|
+
/>
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const CursorIcon = styled(Icon).attrs(() => ({
|
|
31
|
+
'data-component-name': 'icons/CursorIcon/CursorIcon',
|
|
32
|
+
}))<IconProps>`
|
|
33
|
+
height: ${({ size }) => size || '16px'};
|
|
34
|
+
width: ${({ size }) => size || '16px'};
|
|
35
|
+
`;
|
|
@@ -0,0 +1,32 @@
|
|
|
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 xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" {...props}>
|
|
10
|
+
<path
|
|
11
|
+
fillRule="evenodd"
|
|
12
|
+
clipRule="evenodd"
|
|
13
|
+
d="M5.0625 7.3125H15.1875C15.4858 7.31216 15.7717 7.19352 15.9826 6.98262C16.1935 6.77171 16.3122 6.48576 16.3125 6.1875V2.8125C16.3122 2.51424 16.1935 2.22829 15.9826 2.01738C15.7717 1.80648 15.4858 1.68784 15.1875 1.6875H2.8125C2.51424 1.68784 2.22829 1.80648 2.01738 2.01738C1.80648 2.22829 1.68784 2.51424 1.6875 2.8125V6.1875C1.68784 6.48576 1.80648 6.77171 2.01738 6.98262C2.22829 7.19352 2.51424 7.31216 2.8125 7.3125H3.9375H5.0625ZM15.1875 2.8125H2.8125V6.1875H15.1875V2.8125Z"
|
|
14
|
+
/>
|
|
15
|
+
<path
|
|
16
|
+
fillRule="evenodd"
|
|
17
|
+
clipRule="evenodd"
|
|
18
|
+
d="M15.1875 10.6875H9.5625C9.26424 10.6878 8.97829 10.8065 8.76738 11.0174C8.55648 11.2283 8.43784 11.5142 8.4375 11.8125V12.9375H5.0625V10.4546V9.5625V7.3125H3.9375V10.4546V12.9375C3.93784 13.2358 4.05648 13.5217 4.26738 13.7326C4.47829 13.9435 4.76424 14.0622 5.0625 14.0625H8.4375V15.1875C8.43784 15.4858 8.55648 15.7717 8.76738 15.9826C8.97829 16.1935 9.26424 16.3122 9.5625 16.3125H15.1875C15.4858 16.3122 15.7717 16.1935 15.9826 15.9826C16.1935 15.7717 16.3122 15.4858 16.3125 15.1875V11.8125C16.3122 11.5142 16.1935 11.2283 15.9826 11.0174C15.7717 10.8065 15.4858 10.6878 15.1875 10.6875ZM9.5625 11.8125V15.1875H15.1875V11.8125H9.5625Z"
|
|
19
|
+
/>
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const HierarchyIcon = styled(Icon).attrs(() => ({
|
|
24
|
+
'data-component-name': 'icons/HierarchyIcon/HierarchyIcon',
|
|
25
|
+
}))<IconProps>`
|
|
26
|
+
path {
|
|
27
|
+
fill: ${({ color }) => getCssColorVariable(color)};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
height: ${({ size }) => size || '16px'};
|
|
31
|
+
width: ${({ size }) => size || '16px'};
|
|
32
|
+
`;
|