UNPKG

@redocly/theme

Version:

Shared UI components lib

223 lines 12.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.usePageActions = usePageActions; const react_1 = require("react"); const CopyIcon_1 = require("../../icons/CopyIcon/CopyIcon"); const ChatGptIcon_1 = require("../../icons/ChatGptIcon/ChatGptIcon"); const ClaudeIcon_1 = require("../../icons/ClaudeIcon/ClaudeIcon"); const MarkdownFullIcon_1 = require("../../icons/MarkdownFullIcon/MarkdownFullIcon"); const VSCodeIcon_1 = require("../../icons/VSCodeIcon/VSCodeIcon"); const CursorIcon_1 = require("../../icons/CursorIcon/CursorIcon"); const use_theme_hooks_1 = require("./use-theme-hooks"); const use_theme_config_1 = require("./use-theme-config"); const use_mcp_config_1 = require("./use-mcp-config"); const clipboard_service_1 = require("../utils/clipboard-service"); const dom_1 = require("../utils/dom"); const mcp_1 = require("../utils/mcp"); const urls_1 = require("../utils/urls"); function createPageActionResource(pageSlug, pageUrl) { return { id: pageSlug, object: 'page', uri: pageUrl, }; } const DEFAULT_ENABLED_ACTIONS = [ 'copy', 'view', 'chatgpt', 'claude', 'docs-mcp-cursor', 'docs-mcp-vscode', ]; function usePageActions(pageSlug, mcpUrl, actions) { var _a, _b, _c; const { useTranslate, usePageData, usePageProps, usePageSharedData, useTelemetry } = (0, use_theme_hooks_1.useThemeHooks)(); const { translate } = useTranslate(); const themeConfig = (0, use_theme_config_1.useThemeConfig)(); const pageProps = usePageProps(); const telemetry = useTelemetry(); const openApiSharedData = usePageSharedData('openAPIDocsStore'); const mcpConfig = (0, use_mcp_config_1.useMCPConfig)(); const shouldHideAllActions = shouldHidePageActions(pageProps, themeConfig, (_a = openApiSharedData === null || openApiSharedData === void 0 ? void 0 : openApiSharedData.options) === null || _a === void 0 ? void 0 : _a.excludeFromSearch); const { isPublic } = usePageData() || {}; const createMCPHandler = (0, react_1.useCallback)((clientType, requiresMcpUrl = false) => () => { if (requiresMcpUrl && !mcpUrl) return null; if (!requiresMcpUrl && (mcpUrl || mcpConfig.isMcpDisabled)) return null; const config = requiresMcpUrl ? { serverName: mcpConfig.serverName, url: mcpUrl || '' } : { serverName: mcpConfig.serverName, url: mcpConfig.serverUrl || '' }; const isDocsMcp = !requiresMcpUrl; const origin = dom_1.IS_BROWSER ? window.location.origin : ''; const pageUrl = `${origin}${pageSlug}`; return createMCPAction({ clientType, mcpConfig: config, translate, onClickCallback: isDocsMcp ? () => telemetry.sendPageActionsButtonClickedMessage([ Object.assign(Object.assign({}, createPageActionResource(pageSlug, pageUrl)), { action_type: `docs-mcp-${clientType}` }), ]) : undefined, }); }, [mcpUrl, mcpConfig, translate, telemetry, pageSlug]); const result = (0, react_1.useMemo)(() => { var _a, _b, _c; if (shouldHideAllActions) { return []; } const origin = dom_1.IS_BROWSER ? window.location.origin : ((_a = globalThis['SSR_HOSTNAME']) !== null && _a !== void 0 ? _a : ''); const pathname = (0, urls_1.addTrailingSlash)(pageSlug); const pageUrl = (0, urls_1.combineUrls)(origin, pathname); const isRoot = (0, urls_1.withoutPathPrefix)(pathname) === '/'; const mdPageUrl = isRoot ? (0, urls_1.combineUrls)(origin, pathname, 'index.html.md') : (0, urls_1.combineUrls)(origin, (0, urls_1.removeTrailingSlash)(pathname) + '.md'); const actionHandlers = { 'docs-mcp-cursor': createMCPHandler('cursor', false), 'docs-mcp-vscode': createMCPHandler('vscode', false), 'mcp-cursor': createMCPHandler('cursor', true), 'mcp-vscode': createMCPHandler('vscode', true), copy: () => ({ buttonText: translate('page.actions.copyButtonText', 'Copy'), title: translate('page.actions.copyTitle', 'Copy for LLM'), description: translate('page.actions.copyDescription', 'Copy page as Markdown for LLMs'), iconComponent: CopyIcon_1.CopyIcon, onClick: () => __awaiter(this, void 0, void 0, function* () { try { const result = yield fetch(mdPageUrl); if (result.status !== 200) { return; } const text = yield result.text(); clipboard_service_1.ClipboardService.copyCustom(text); telemetry.sendPageActionsButtonClickedMessage([ Object.assign(Object.assign({}, createPageActionResource(pageSlug, pageUrl)), { action_type: 'copy' }), ]); } catch (error) { console.error(error); } }), }), view: () => ({ buttonText: translate('page.actions.viewAsMdButtonText', 'View as Markdown'), title: translate('page.actions.viewAsMdTitle', 'View as Markdown'), description: translate('page.actions.viewAsMdDescription', 'Open this page as Markdown'), iconComponent: MarkdownFullIcon_1.MarkdownFullIcon, link: mdPageUrl, onClick: () => { telemetry.sendPageActionsButtonClickedMessage([ Object.assign(Object.assign({}, createPageActionResource(pageSlug, pageUrl)), { action_type: 'view' }), ]); }, }), chatgpt: () => { if (!isPublic) { return null; } const link = getExternalAiPromptLink('https://chat.openai.com', mdPageUrl); return { buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'), title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'), description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'), iconComponent: ChatGptIcon_1.ChatGptIcon, link, onClick: () => { telemetry.sendPageActionsButtonClickedMessage([ Object.assign(Object.assign({}, createPageActionResource(pageSlug, pageUrl)), { action_type: 'chatgpt' }), ]); window.location.href = link; }, }; }, claude: () => { if (!isPublic) { return null; } const link = getExternalAiPromptLink('https://claude.ai/new', mdPageUrl); return { buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'), title: translate('page.actions.claudeTitle', 'Open in Claude'), description: translate('page.actions.claudeDescription', 'Get insights from Claude'), iconComponent: ClaudeIcon_1.ClaudeIcon, link, onClick: () => { telemetry.sendPageActionsButtonClickedMessage([ Object.assign(Object.assign({}, createPageActionResource(pageSlug, pageUrl)), { action_type: 'claude' }), ]); window.location.href = link; }, }; }, }; return (((_c = (_b = themeConfig.navigation) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.items) || actions || DEFAULT_ENABLED_ACTIONS) .map((action) => { var _a; return (_a = actionHandlers[action]) === null || _a === void 0 ? void 0 : _a.call(actionHandlers); }) .filter((action) => action !== null); }, [ shouldHideAllActions, pageSlug, (_c = (_b = themeConfig.navigation) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.items, actions, translate, isPublic, createMCPHandler, telemetry, ]); return result; } function getExternalAiPromptLink(baseUrl, mdPageUrl) { const externalAiPrompt = `Read ${mdPageUrl} and answer questions based on the content.`; const url = new URL(baseUrl); url.searchParams.set('q', externalAiPrompt); return url.toString(); } function createMCPAction({ clientType, mcpConfig, translate, onClickCallback, }) { const url = (0, mcp_1.generateMCPDeepLink)(clientType, mcpConfig); const sharedProps = { onClick: () => { onClickCallback === null || onClickCallback === void 0 ? void 0 : onClickCallback(); window.open(url, '_blank'); }, }; if (clientType === 'cursor') { return Object.assign(Object.assign({}, sharedProps), { buttonText: translate('page.actions.connectMcp.cursor', 'Connect to Cursor'), title: translate('page.actions.connectMcp.cursor', 'Connect to Cursor'), description: translate('page.actions.connectMcp.cursorDescription', 'Install MCP server on Cursor'), iconComponent: CursorIcon_1.CursorIcon }); } return Object.assign(Object.assign({}, sharedProps), { buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'), title: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'), description: translate('page.actions.connectMcp.vscodeDescription', 'Install MCP server on VS Code'), iconComponent: VSCodeIcon_1.VSCodeIcon }); } function shouldHidePageActions(pageProps, themeConfig, openapiExcludeFromSearch) { var _a, _b, _c, _d, _e, _f, _g, _h; // Can't use any actions if search is globally disabled (markdown files are not generated) if ((_a = themeConfig.search) === null || _a === void 0 ? void 0 : _a.hide) { return true; } // Can't use any actions if no markdown files are generated for LLMs if ((_c = (_b = pageProps === null || pageProps === void 0 ? void 0 : pageProps.seo) === null || _b === void 0 ? void 0 : _b.llmstxt) === null || _c === void 0 ? void 0 : _c.hide) { return true; } // Page actions are explicitly disabled in config if ((_e = (_d = themeConfig.navigation) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.hide) { return true; } // Page is excluded from search const isOpenApiPage = ((_f = pageProps === null || pageProps === void 0 ? void 0 : pageProps.metadata) === null || _f === void 0 ? void 0 : _f.type) === 'openapi' || ((_g = pageProps === null || pageProps === void 0 ? void 0 : pageProps.metadata) === null || _g === void 0 ? void 0 : _g.subType) === 'openapi-operation'; const isPageExcludedFromSearch = ((_h = pageProps === null || pageProps === void 0 ? void 0 : pageProps.frontmatter) === null || _h === void 0 ? void 0 : _h.excludeFromSearch) || (isOpenApiPage && openapiExcludeFromSearch); if (isPageExcludedFromSearch) { return true; } return false; } //# sourceMappingURL=use-page-actions.js.map