import React from 'react'; import { usePluginToolbarStore, type ToolbarItem } from '@/store/pluginToolbarStore'; function ToolbarButton({ item }: { item: ToolbarItem }) { return ( {item.icon && {item.icon}} {!item.iconOnly && {item.label}} ); } function ToolbarSearch({ item }: { item: ToolbarItem }) { const [expanded, setExpanded] = React.useState(false); const [value, setValue] = React.useState(''); const inputRef = React.useRef(null); const handleToggle = () => { if (expanded) { // Collapse: clear and close setValue(''); item.onSearch?.(''); setExpanded(false); } else { setExpanded(true); setTimeout(() => inputRef.current?.focus(), 50); } }; const handleChange = (e: React.ChangeEvent) => { setValue(e.target.value); item.onSearch?.(e.target.value); }; if (!expanded) { return ( ); } return ( { if (!value) { setExpanded(false); } }} className="w-28 sm:w-40 px-2 py-1 text-xs border border-secondary-200 rounded focus:outline-none focus:border-primary-400 focus:ring-1 focus:ring-primary-300 placeholder:text-secondary-400" /> ); } function ToolbarDropdown({ item }: { item: ToolbarItem }) { const [open, setOpen] = React.useState(false); const ref = React.useRef(null); const menuRef = React.useRef(null); const [menuPos, setMenuPos] = React.useState({ top: 0, left: 0 }); React.useEffect(() => { if (!open) return; const handler = (e: MouseEvent) => { const target = e.target as Node; if (ref.current?.contains(target) || menuRef.current?.contains(target)) return; setOpen(false); }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [open]); const handleToggle = () => { if (!open && ref.current) { const rect = ref.current.getBoundingClientRect(); setMenuPos({ top: rect.bottom + 4, left: rect.left }); } setOpen(!open); }; const activeOption = item.menuOptions?.find((o) => o.active); let lastSection: string | undefined = undefined; return ( <> {item.icon && {item.icon}} {!item.iconOnly && {activeOption?.label || item.label}} {open && ( {item.menuOptions?.map((opt) => { const showSection = opt.section && opt.section !== lastSection; if (showSection) lastSection = opt.section; return ( {showSection && ( {opt.section} )} {opt.separator && } { opt.onClick(); setOpen(false); }} disabled={opt.disabled} className={` w-full flex items-center gap-2 px-3 py-1.5 text-xs text-left transition-colors ${opt.active ? 'bg-primary-50 text-primary-700 font-medium' : 'text-secondary-700 hover:bg-secondary-100'} ${opt.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'} `} > {opt.icon && {opt.icon}} {opt.label} {opt.active && ( )} ); })} )} > ); } function ToolbarSelect({ item }: { item: ToolbarItem }) { return ( item.onSelect?.(e.target.value)} className="px-1.5 sm:px-2 py-1 text-xs border border-secondary-200 rounded focus:outline-none focus:border-primary-400 focus:ring-1 focus:ring-primary-300 bg-white cursor-pointer flex-shrink-0 max-w-[120px] sm:max-w-none" > {item.selectOptions?.map((opt) => ( {opt.label} ))} ); } export function PluginToolbar() { const { items, activePlugin } = usePluginToolbarStore(); const visibleItems = items.filter((i) => i.plugin === activePlugin); if (visibleItems.length === 0) return null; // Group items by group field const groups: Record = {}; for (const item of visibleItems) { const g = item.group || 'default'; if (!groups[g]) groups[g] = []; groups[g].push(item); } const groupNames = Object.keys(groups); const rightGroupNames = groupNames.filter((g) => g.startsWith('zz-right')); const leftGroupNames = groupNames.filter((g) => !g.startsWith('zz-right')); const renderGroup = (groupName: string, gi: number) => ( {gi > 0 && } {groups[groupName].map((item) => { if (item.type === 'search') return ; if (item.type === 'select') return ; if (item.type === 'dropdown') return ; if (item.type === 'custom' && item.customComponent) return {item.customComponent}; return ; })} ); return ( {leftGroupNames.map((groupName, gi) => renderGroup(groupName, gi))} {rightGroupNames.length > 0 && } {rightGroupNames.map((groupName, gi) => renderGroup(groupName, gi))} ); }