import React from 'react'; import { ToolType } from '../canvas/tools'; import ColorPicker from './ColorPicker'; interface OnlineUser { userId: string; displayName: string; color: string; } interface ToolbarProps { activeTool: ToolType; onToolChange: (tool: ToolType) => void; color: string; onColorChange: (color: string) => void; strokeWidth: number; onStrokeWidthChange: (width: number) => void; zoom: number; onFitAll: () => void; onZoomIn?: () => void; onZoomOut?: () => void; canUndo: boolean; canRedo: boolean; onUndo: () => void; onRedo: () => void; onlineUsers: OnlineUser[]; onUserClick?: (userId: string, displayName: string) => void; followingUserId?: string | null; onShareClick?: () => void; onToggleLayers?: () => void; showLayers?: boolean; onToggleHelp?: () => void; onToggleActivity?: () => void; showActivity?: boolean; onExport?: () => void; onRefreshPreview?: () => void; previewRefreshing?: boolean; onToggleReview?: () => void; reviewMode?: boolean; boardName?: string; } // SVG icon components function IconSelect() { return ( ); } function IconPen() { return ( ); } function IconText() { return ( ); } function IconSticky() { return ( ); } function IconMarkdown() { return ( ); } function IconReview() { return ( ); } function IconUndo() { return ( ); } function IconRedo() { return ( ); } function IconFit() { return ( ); } function IconLayers() { return ( ); } const toolButtons: { tool: ToolType; label: string; shortcut: string; numKey: string; Icon: React.FC; hint?: string }[] = [ { tool: ToolType.SELECT, label: 'Select', shortcut: 'V', numKey: '1', Icon: IconSelect, hint: 'Click to select, drag to move, Shift+click for multi-select' }, { tool: ToolType.PEN, label: 'Draw', shortcut: 'P', numKey: '3', Icon: IconPen, hint: 'Click and drag to draw freehand' }, { tool: ToolType.TEXT, label: 'Text', shortcut: 'T', numKey: '4', Icon: IconText, hint: 'Click on the canvas to place text' }, { tool: ToolType.STICKY, label: 'Sticky', shortcut: 'S', numKey: '5', Icon: IconSticky, hint: 'Click on the canvas to place a sticky note' }, { tool: ToolType.MARKDOWN, label: 'Markdown', shortcut: 'M', numKey: '6', Icon: IconMarkdown, hint: 'Click on the canvas to place a markdown card' }, ]; const REVIEW_HINT = 'Click an object to place a comment pin. Press . to toggle.'; export default function Toolbar({ activeTool, onToolChange, color, onColorChange, strokeWidth, onStrokeWidthChange, zoom, onFitAll, onZoomIn, onZoomOut, canUndo, canRedo, onUndo, onRedo, onlineUsers, onUserClick, followingUserId, onShareClick, onToggleLayers, showLayers, onToggleHelp, onToggleActivity, showActivity, onExport, onRefreshPreview, previewRefreshing, onToggleReview, reviewMode, }: ToolbarProps) { const showStroke = activeTool === ToolType.PEN; // Determine active hint const activeToolDef = toolButtons.find((t) => t.tool === activeTool); const activeHint = reviewMode ? REVIEW_HINT : activeToolDef?.hint || ''; return (
{/* Tool buttons */}
{toolButtons.map(({ tool, label, shortcut, numKey, Icon }) => { const active = activeTool === tool; return ( ); })}
{/* Review mode — independent toggle, separated from tools */} {onToggleReview && (<> )} {/* Color */} {/* Stroke width (pen) */} {showStroke && ( <> Width onStrokeWidthChange(Number(e.target.value))} style={{ width: '60px', height: '3px', accentColor: '#4a9eff', cursor: 'pointer' }} /> {strokeWidth} )} {/* Undo/Redo */} {/* Zoom */} {onZoomOut && ( )} {Math.round(zoom * 100)}% {onZoomIn && ( )} {/* Layers toggle */} {onToggleLayers && ( )} {/* Activity log */} {onToggleActivity && ( )} {/* Help / shortcuts */} {onToggleHelp && ( )} {/* Export */} {onExport && ( )} {/* Refresh board preview */} {onRefreshPreview && ( )} {/* Spacer */}
{/* Online users */} {onlineUsers.length > 0 && (
u.displayName).join(', ')}> {onlineUsers.slice(0, 5).map((u, i) => (
0 ? '-6px' : '0', zIndex: 5 - i, boxShadow: followingUserId === u.userId ? '0 0 6px rgba(74,144,217,0.6)' : '0 1px 3px rgba(0,0,0,0.3)', cursor: 'pointer', transition: 'border-color 0.15s, box-shadow 0.15s', }} onClick={() => onUserClick?.(u.userId, u.displayName)} title={`${u.displayName}${followingUserId === u.userId ? ' (following)' : ' — click to follow'}`} > {(u.displayName || '?')[0].toUpperCase()}
))} {onlineUsers.length > 5 && ( +{onlineUsers.length - 5} )}
)} {/* Share */} {onShareClick && ( )}
{/* Tool hint bar */} {activeHint && (
{activeHint}
)}
); } function Divider() { return
; } function ActionBtn({ onClick, disabled, title, children, active }: { onClick: () => void; disabled?: boolean; title: string; children: React.ReactNode; active?: boolean; }) { return ( ); }