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; fontSize: number; onFontSizeChange: (size: 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; onMmImport?: () => void; onExport?: () => void; onToggleReview?: () => void; reviewMode?: boolean; boardName?: string; } // SVG icon components function IconSelect() { return ( ); } function IconPan() { return ( ); } function IconPen() { return ( ); } function IconText() { 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.PAN, label: 'Pan', shortcut: 'H', numKey: '2', Icon: IconPan, hint: 'Click and drag to pan the canvas' }, { 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' }, ]; const REVIEW_HINT = 'Click an image to leave a comment. Press . to toggle.'; export default function Toolbar({ activeTool, onToolChange, color, onColorChange, strokeWidth, onStrokeWidthChange, fontSize, onFontSizeChange, zoom, onFitAll, onZoomIn, onZoomOut, canUndo, canRedo, onUndo, onRedo, onlineUsers, onUserClick, followingUserId, onShareClick, onToggleLayers, showLayers, onToggleHelp, onMmImport, onExport, onToggleReview, reviewMode, }: ToolbarProps) { const showStroke = activeTool === ToolType.PEN; const showFontSize = activeTool === ToolType.TEXT; // 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 && !reviewMode; return ( ); })} {/* Review mode — in tool group */} {onToggleReview && ( )}
{/* Color */} {/* Stroke width (pen) */} {showStroke && ( <> Width onStrokeWidthChange(Number(e.target.value))} style={{ width: '60px', height: '3px', accentColor: '#4a9eff', cursor: 'pointer' }} /> {strokeWidth} )} {/* Font size (text) */} {showFontSize && ( <> Size onFontSizeChange(Number(e.target.value))} style={{ width: '60px', height: '3px', accentColor: '#4a9eff', cursor: 'pointer' }} /> {fontSize} )} {/* Undo/Redo */} {/* Zoom */} {onZoomOut && ( )} {Math.round(zoom * 100)}% {onZoomIn && ( )} {/* Layers toggle */} {onToggleLayers && ( )} {/* Help / shortcuts */} {onToggleHelp && ( )} {/* Mattermost import */} {onMmImport && ( )} {/* Export */} {onExport && ( )} {/* 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 ( ); }