Skip to main content
Glama
menu.tsx9.03 kB
"use client"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { ChevronRightIcon } from "lucide-react"; import type * as React from "react"; import { cn } from "@/lib/utils"; const Menu = MenuPrimitive.Root; const MenuPortal = MenuPrimitive.Portal; function MenuTrigger(props: MenuPrimitive.Trigger.Props) { return <MenuPrimitive.Trigger data-slot="menu-trigger" {...props} />; } function MenuPopup({ children, className, sideOffset = 4, align = "center", alignOffset, side = "bottom", ...props }: MenuPrimitive.Popup.Props & { align?: MenuPrimitive.Positioner.Props["align"]; sideOffset?: MenuPrimitive.Positioner.Props["sideOffset"]; alignOffset?: MenuPrimitive.Positioner.Props["alignOffset"]; side?: MenuPrimitive.Positioner.Props["side"]; }) { return ( <MenuPrimitive.Portal> <MenuPrimitive.Positioner align={align} alignOffset={alignOffset} className="z-50" data-slot="menu-positioner" side={side} sideOffset={sideOffset} > <MenuPrimitive.Popup className={cn( "relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover bg-clip-padding shadow-lg outline-none transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] focus:outline-none has-data-starting-style:scale-98 has-data-starting-style:opacity-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]", className, )} data-slot="menu-popup" {...props} > <div className="max-h-(--available-height) w-full overflow-y-auto p-1"> {children} </div> </MenuPrimitive.Popup> </MenuPrimitive.Positioner> </MenuPrimitive.Portal> ); } function MenuGroup(props: MenuPrimitive.Group.Props) { return <MenuPrimitive.Group data-slot="menu-group" {...props} />; } function MenuItem({ className, inset, variant = "default", ...props }: MenuPrimitive.Item.Props & { inset?: boolean; variant?: "default" | "destructive"; }) { return ( <MenuPrimitive.Item className={cn( "[&_svg]:-mx-0.5 flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className, )} data-inset={inset} data-slot="menu-item" data-variant={variant} {...props} /> ); } function MenuCheckboxItem({ className, children, checked, ...props }: MenuPrimitive.CheckboxItem.Props) { return ( <MenuPrimitive.CheckboxItem checked={checked} className={cn( "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className, )} data-slot="menu-checkbox-item" {...props} > <MenuPrimitive.CheckboxItemIndicator className="col-start-1"> <svg fill="none" height="24" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" > <path d="M5.252 12.7 10.2 18.63 18.748 5.37" /> </svg> </MenuPrimitive.CheckboxItemIndicator> <span className="col-start-2">{children}</span> </MenuPrimitive.CheckboxItem> ); } function MenuRadioGroup(props: MenuPrimitive.RadioGroup.Props) { return <MenuPrimitive.RadioGroup data-slot="menu-radio-group" {...props} />; } function MenuRadioItem({ className, children, ...props }: MenuPrimitive.RadioItem.Props) { return ( <MenuPrimitive.RadioItem className={cn( "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className, )} data-slot="menu-radio-item" {...props} > <MenuPrimitive.RadioItemIndicator className="col-start-1"> <svg fill="none" height="24" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" > <path d="M5.252 12.7 10.2 18.63 18.748 5.37" /> </svg> </MenuPrimitive.RadioItemIndicator> <span className="col-start-2">{children}</span> </MenuPrimitive.RadioItem> ); } function MenuGroupLabel({ className, inset, ...props }: MenuPrimitive.GroupLabel.Props & { inset?: boolean; }) { return ( <MenuPrimitive.GroupLabel className={cn( "px-2 py-1.5 font-medium text-muted-foreground text-xs data-inset:ps-9 sm:data-inset:ps-8", className, )} data-inset={inset} data-slot="menu-label" {...props} /> ); } function MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) { return ( <MenuPrimitive.Separator className={cn("mx-2 my-1 h-px bg-border", className)} data-slot="menu-separator" {...props} /> ); } function MenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( <span className={cn( "ms-auto font-medium text-muted-foreground/72 text-xs tracking-widest", className, )} data-slot="menu-shortcut" {...props} /> ); } function MenuSub(props: MenuPrimitive.SubmenuRoot.Props) { return <MenuPrimitive.SubmenuRoot data-slot="menu-sub" {...props} />; } function MenuSubTrigger({ className, inset, children, ...props }: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean; }) { return ( <MenuPrimitive.SubmenuTrigger className={cn( "flex min-h-8 items-center gap-2 rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className, )} data-inset={inset} data-slot="menu-sub-trigger" {...props} > {children} <ChevronRightIcon className="-me-0.5 ms-auto opacity-80" /> </MenuPrimitive.SubmenuTrigger> ); } function MenuSubPopup({ className, sideOffset = 0, alignOffset, align = "start", ...props }: MenuPrimitive.Popup.Props & { align?: MenuPrimitive.Positioner.Props["align"]; sideOffset?: MenuPrimitive.Positioner.Props["sideOffset"]; alignOffset?: MenuPrimitive.Positioner.Props["alignOffset"]; }) { const defaultAlignOffset = align !== "center" ? -5 : undefined; return ( <MenuPopup align={align} alignOffset={alignOffset ?? defaultAlignOffset} className={className} data-slot="menu-sub-content" side="inline-end" sideOffset={sideOffset} {...props} /> ); } export { Menu, Menu as DropdownMenu, MenuPortal, MenuPortal as DropdownMenuPortal, MenuTrigger, MenuTrigger as DropdownMenuTrigger, MenuPopup, MenuPopup as DropdownMenuContent, MenuGroup, MenuGroup as DropdownMenuGroup, MenuItem, MenuItem as DropdownMenuItem, MenuCheckboxItem, MenuCheckboxItem as DropdownMenuCheckboxItem, MenuRadioGroup, MenuRadioGroup as DropdownMenuRadioGroup, MenuRadioItem, MenuRadioItem as DropdownMenuRadioItem, MenuGroupLabel, MenuGroupLabel as DropdownMenuLabel, MenuSeparator, MenuSeparator as DropdownMenuSeparator, MenuShortcut, MenuShortcut as DropdownMenuShortcut, MenuSub, MenuSub as DropdownMenuSub, MenuSubTrigger, MenuSubTrigger as DropdownMenuSubTrigger, MenuSubPopup, MenuSubPopup as DropdownMenuSubContent, };

Latest Blog Posts

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/bytebase/dbhub'

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