import { useEffect } from 'react'; import { Icon } from '@/app/Icon'; import type { MessageAction } from '@/lib/messages/actions'; interface MenuItem { action: MessageAction; label: string; icon: string; danger?: boolean; } const ITEMS: Record = { quote: { action: 'quote', label: '引用', icon: 'format_quote' }, copy: { action: 'copy', label: '复制', icon: 'content_copy' }, favorite: { action: 'favorite', label: '收藏', icon: 'inventory_2' }, forward: { action: 'forward', label: '转发', icon: 'reply' }, recall: { action: 'recall', label: '撤回', icon: 'undo' }, select: { action: 'select', label: '多选', icon: 'select_all' }, delete: { action: 'delete', label: '删除', icon: 'delete_outline', danger: true }, }; interface MessageContextMenuProps { x: number; y: number; actions: MessageAction[]; onAction: (action: MessageAction) => void; onClose: () => void; } /** README §3.5: 180px popup, divider before the destructive-leaning tail (recall/delete). */ export function MessageContextMenu({ x, y, actions, onAction, onClose }: MessageContextMenuProps) { useEffect(() => { const handler = () => onClose(); window.addEventListener('click', handler); window.addEventListener('scroll', handler, true); return () => { window.removeEventListener('click', handler); window.removeEventListener('scroll', handler, true); }; }, [onClose]); const leading = actions.filter((a) => a !== 'recall' && a !== 'delete'); const trailing = actions.filter((a) => a === 'recall' || a === 'delete'); return (
e.stopPropagation()} > {leading.map((action) => { const item = ITEMS[action]; return ( ); })} {trailing.length ?
: null} {trailing.map((action) => { const item = ITEMS[action]; return ( ); })}
); }