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);
`;