import React, { useMemo } from 'react'; import styled from 'styled-components'; import type { JSX } from 'react'; import type { MCPOption } from '@redocly/theme/core/types'; import { Dropdown } from '@redocly/theme/components/Dropdown/Dropdown'; import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu'; import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem'; import { Button } from '@redocly/theme/components/Button/Button'; import { CursorIcon } from '@redocly/theme/icons/CursorIcon/CursorIcon'; import { VSCodeIcon } from '@redocly/theme/icons/VSCodeIcon/VSCodeIcon'; import { CopyIcon } from '@redocly/theme/icons/CopyIcon/CopyIcon'; import { CheckmarkFilledIcon } from '@redocly/theme/icons/CheckmarkFilledIcon/CheckmarkFilledIcon'; import { ConnectIcon } from '@redocly/theme/icons/ConnectIcon/ConnectIcon'; import { useConnectMCPButton } from '@redocly/theme/core/hooks'; import { useThemeHooks } from '@redocly/theme/core/hooks'; type TriggerButtonProps = { text: string; }; const TriggerButton = React.memo(({ text }: TriggerButtonProps): JSX.Element => { return ( }> {text} ); }); type MenuOption = { key: MCPOption; icon: React.ComponentType; titleTranslationKey: string; titleDefault: string; descriptionTranslationKey: string; descriptionDefault: string; }; const MENU_OPTIONS: MenuOption[] = [ { key: 'cursor', icon: CursorIcon, titleTranslationKey: 'page.actions.connectMcp.cursor', titleDefault: 'Connect to Cursor', descriptionTranslationKey: 'page.actions.connectMcp.cursorDescription', descriptionDefault: 'Install MCP server on Cursor', }, { key: 'vscode', icon: VSCodeIcon, titleTranslationKey: 'page.actions.connectMcp.vscode', titleDefault: 'Connect to VS Code', descriptionTranslationKey: 'page.actions.connectMcp.vscodeDescription', descriptionDefault: 'Install MCP server on VS Code', }, { key: 'copy', icon: CopyIcon, titleTranslationKey: 'page.actions.connectMcp.copyConfig', titleDefault: 'Copy MCP Configuration', descriptionTranslationKey: 'page.actions.connectMcp.copyConfigDescription', descriptionDefault: 'Copy MCP JSON Configuration', }, ]; export type ConnectMCPButtonProps = { placement?: 'top' | 'bottom'; alignment?: 'start' | 'end'; options?: MCPOption[]; }; export function ConnectMCPButton({ placement = 'bottom', alignment = 'end', options = ['cursor', 'vscode', 'copy'], }: ConnectMCPButtonProps): JSX.Element { const { useTranslate } = useThemeHooks(); const { translate } = useTranslate(); const { isCopied, triggerButtonText, visibleOptions, handleAction } = useConnectMCPButton({ options, }); const menuOptions = useMemo( () => MENU_OPTIONS.filter((option) => visibleOptions.includes(option.key)), [visibleOptions], ); return ( } triggerEvent="hover" placement={placement} alignment={alignment} closeOnClick={false} > {menuOptions.map((option) => { const Icon = option.icon; const showCheckmark = option.key === 'copy' && isCopied; return ( handleAction(option.key)}> {showCheckmark ? ( ) : ( )} {translate(option.titleTranslationKey, option.titleDefault)} {translate(option.descriptionTranslationKey, option.descriptionDefault)} ); })} ); } const ConnectMCPButtonWrapper = styled.div` display: inline-block; position: relative; `; const StyledButton = styled(Button)` --button-gap: var(--connect-mcp-button-gap); `; const MenuItemContent = styled.div` display: flex; align-items: center; gap: var(--connect-mcp-button-menu-item-gap); padding: var(--connect-mcp-button-menu-item-padding-block) var(--connect-mcp-button-menu-item-padding-inline); `; const MenuItemIcon = styled.div` display: flex; align-items: center; justify-content: center; width: var(--connect-mcp-button-menu-item-icon-size); height: var(--connect-mcp-button-menu-item-icon-size); flex-shrink: 0; border: var(--connect-mcp-button-menu-item-icon-border); border-radius: var(--connect-mcp-button-menu-item-icon-border-radius); color: var(--connect-mcp-button-menu-item-icon-color); `; const MenuItemText = styled.div` display: flex; flex-direction: column; gap: var(--connect-mcp-button-menu-item-text-gap); flex: 1; `; const MenuItemTitle = styled.div` font-size: var(--connect-mcp-button-menu-item-title-font-size); font-weight: var(--connect-mcp-button-menu-item-title-font-weight); line-height: var(--connect-mcp-button-menu-item-title-line-height); color: var(--connect-mcp-button-menu-item-title-color); `; const MenuItemDescription = styled.div` font-size: var(--connect-mcp-button-menu-item-description-font-size); font-weight: var(--connect-mcp-button-menu-item-description-font-weight); line-height: var(--connect-mcp-button-menu-item-description-line-height); color: var(--connect-mcp-button-menu-item-description-color); `;