diff --git a/packages/ui/src/components/ToolbarOverflowMenu.tsx b/packages/ui/src/components/ToolbarOverflowMenu.tsx new file mode 100644 index 0000000..10d502d --- /dev/null +++ b/packages/ui/src/components/ToolbarOverflowMenu.tsx @@ -0,0 +1,66 @@ +/** + * ToolbarOverflowMenu Component + * + * 工具栏溢出菜单,用于在空间不足时收纳次要按钮 + */ + +import { Settings, type LucideIcon } from 'lucide-react'; +import { motion } from 'framer-motion'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '../primitives/DropdownMenu'; +import { cn } from '../utils/cn'; + +export interface ToolbarMenuItem { + /** 菜单项图标 */ + icon: LucideIcon; + /** 菜单项标签 */ + label: string; + /** 点击回调 */ + onClick?: () => void; +} + +interface ToolbarOverflowMenuProps { + /** 菜单项列表 */ + items: ToolbarMenuItem[]; + /** 自定义类名 */ + className?: string; +} + +export function ToolbarOverflowMenu({ items, className }: ToolbarOverflowMenuProps) { + // 过滤掉没有 onClick 的项 + const validItems = items.filter((item) => item.onClick); + + if (validItems.length === 0) { + return null; + } + + return ( + + + + + + + + {validItems.map((item) => ( + + + {item.label} + + ))} + + + ); +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index e7d2323..4164fc3 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -255,6 +255,7 @@ export { CodeEditor, getLanguageFromFilename, type EditorTab } from './component export { IDE } from './components/IDE.js'; export { StatusBar } from './components/StatusBar.js'; export { Resizer } from './components/Resizer.js'; +export { ToolbarOverflowMenu, type ToolbarMenuItem } from './components/ToolbarOverflowMenu.js'; // Toast function (re-export from sonner) export { toast } from 'sonner'; diff --git a/packages/ui/src/primitives/DropdownMenu.tsx b/packages/ui/src/primitives/DropdownMenu.tsx new file mode 100644 index 0000000..7c04e98 --- /dev/null +++ b/packages/ui/src/primitives/DropdownMenu.tsx @@ -0,0 +1,77 @@ +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; +import { forwardRef } from 'react'; +import { cn } from '../utils/cn'; + +export const DropdownMenu = DropdownMenuPrimitive.Root; +export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; +export const DropdownMenuGroup = DropdownMenuPrimitive.Group; +export const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +export const DropdownMenuContent = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +export const DropdownMenuItem = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +export const DropdownMenuLabel = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +export const DropdownMenuSeparator = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; diff --git a/packages/ui/src/primitives/index.ts b/packages/ui/src/primitives/index.ts index 2dcdcab..b589a12 100644 --- a/packages/ui/src/primitives/index.ts +++ b/packages/ui/src/primitives/index.ts @@ -32,3 +32,13 @@ export { TooltipTrigger, TooltipContent, } from './Tooltip'; +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuGroup, + DropdownMenuPortal, +} from './DropdownMenu'; diff --git a/packages/web/src/pages/Chat.tsx b/packages/web/src/pages/Chat.tsx index 684fba3..7c1c2d1 100644 --- a/packages/web/src/pages/Chat.tsx +++ b/packages/web/src/pages/Chat.tsx @@ -15,6 +15,7 @@ import { ContextUsage, SubagentProgress, DiagnosticsIndicator, + ToolbarOverflowMenu, } from '@ai-assistant/ui'; interface ChatPageProps { @@ -157,84 +158,6 @@ export function ChatPage({ /> )} - {/* Checkpoints 按钮 */} - {onOpenCheckpoints && ( - - - - )} - - {/* Providers 按钮 */} - {onOpenProviders && ( - - - - )} - - {/* Agents 按钮 */} - {onOpenAgents && ( - - - - )} - - {/* Hooks 按钮 */} - {onOpenHooks && ( - - - - )} - - {/* MCP 按钮 */} - {onOpenMCP && ( - - - - )} - - {/* 命令按钮 */} - {onOpenCommands && ( - - - - )} - {/* Sessions 按钮 */} {onOpenSessions && ( )} + + {/* 设置菜单 - 齿轮图标,放在最右侧 */} + )}