Skip to main content
Glama

Convex MCP server

Official
by get-convex
Menu.tsx4.34 kB
import { Fragment, ReactNode, useState } from "react"; import { Menu as HeadlessMenu, Portal } from "@headlessui/react"; import { PopperChildrenProps, usePopper } from "react-popper"; import classNames from "classnames"; import { Button, ButtonProps } from "@ui/Button"; import { Key, KeyboardShortcut } from "@ui/KeyboardShortcut"; import { TooltipSide } from "@ui/Tooltip"; export type MenuProps = { children: React.ReactElement | (React.ReactElement | null)[]; buttonProps: ButtonProps; placement?: PopperChildrenProps["placement"]; offset?: number; }; export function Menu({ children, buttonProps, placement = "bottom", offset = 4, }: MenuProps) { const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null); const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(); const { styles, attributes } = usePopper(referenceElement, popperElement, { placement, modifiers: offset ? [ { name: "offset", options: { offset: [0, offset] }, }, ] : [], }); return ( <HeadlessMenu> {({ open }) => ( <> <HeadlessMenu.Button ref={setReferenceElement} as={Fragment} data-testid="open-menu" > <Button {...buttonProps} focused={open} /> </HeadlessMenu.Button> <Portal> <HeadlessMenu.Items ref={setPopperElement} style={styles.popper} {...attributes.popper} className="z-50 flex max-h-[20rem] flex-col gap-1 overflow-auto rounded-lg border bg-background-secondary py-2 text-sm whitespace-nowrap shadow-md" > {children} </HeadlessMenu.Items> </Portal> </> )} </HeadlessMenu> ); } export function MenuItem({ variant = "default", children, action, href, disabled = false, tip, tipSide, shortcut, }: { variant?: "default" | "danger"; children: ReactNode; disabled?: boolean; tip?: ReactNode; tipSide?: TooltipSide; shortcut?: Key[]; } & ( | { action: () => void; href?: never; } | { action?: never; href: string; } )) { const actionProp = href ? { href } : { onClick: action }; return ( <HeadlessMenu.Item> {({ active }) => ( <Button tip={tip} tipSide={tipSide} variant="unstyled" className={classNames( "mx-1 flex gap-2 items-center p-2 rounded-xs", disabled ? "cursor-not-allowed fill-content-tertiary text-content-tertiary" : "hover:bg-background-tertiary", active && "bg-background-primary", !disabled && variant === "danger" ? "text-content-errorSecondary" : "text-content-primary", )} disabled={disabled} {...actionProp} > {children} {shortcut && ( <KeyboardShortcut value={shortcut} className="ml-auto pl-6 text-content-tertiary" /> )} </Button> )} </HeadlessMenu.Item> ); } export function MenuLink({ children, href, disabled = false, selected = false, shortcut, }: { children: React.ReactChild | React.ReactChild[]; href: string; disabled?: boolean; selected?: boolean; shortcut?: Key[]; }) { return ( <HeadlessMenu.Item disabled={disabled}> {({ active, close }) => ( <a href={href} aria-disabled={disabled} onClick={disabled ? (e) => e.preventDefault() : () => close()} className={classNames( "rounded-xs flex gap-2 items-center mx-1 px-2 py-2 text-content-primary", disabled && "cursor-not-allowed fill-content-secondary bg-background-tertiary text-content-secondary", active || selected ? "bg-background-primary" : "hover:bg-background-tertiary", )} > {children} {shortcut && ( <KeyboardShortcut value={shortcut} className="ml-auto pl-6 text-content-tertiary" /> )} </a> )} </HeadlessMenu.Item> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server