feat(refboard): canvas polish — transform box sync, dot grid, snap tuning, perf fixes

- Fix transform box not updating after alignment/arrangement/normalize/flip operations
  (shortcuts, context menu, and selection toolbar all fixed with DRY _opUpdate helper)
- Replace 100ms polling loop with event-driven viewport updates (moved + wheel-scroll)
- Add adaptive dot grid background that responds to zoom/pan
- Reduce snap guide threshold from 8px to 4px for subtler snapping
- Remove PresenceOverlay (remote selection highlighting) — too heavy for minimal benefit
- Offset multiple dropped images so they don't overlap
- Add new canvas modules: SnapGuides, clipboard, grouping, FrameSprite, DrawingSprite,
  LaserPointer, context-menu-items, SelectionToolbar, Minimap
- Extract Editor hooks into dedicated files (useBoardLoader, useCanvasSetup,
  useShortcutHandler, useLayerPanel, useSaveManager, useFollowMode)
- Sync improvements: real-time transform broadcast, board rooms, viewport sync
This commit is contained in:
Hiren Kangad
2026-03-10 03:58:53 +05:30
parent cfd7adf73d
commit e9509ef7b0
41 changed files with 4171 additions and 705 deletions
+12 -3
View File
@@ -26,6 +26,8 @@ interface ToolbarProps {
onUndo: () => void;
onRedo: () => void;
onlineUsers: OnlineUser[];
onUserClick?: (userId: string, displayName: string) => void;
followingUserId?: string | null;
onShareClick?: () => void;
onToggleLayers?: () => void;
showLayers?: boolean;
@@ -139,6 +141,8 @@ export default function Toolbar({
onUndo,
onRedo,
onlineUsers,
onUserClick,
followingUserId,
onShareClick,
onToggleLayers,
showLayers,
@@ -306,11 +310,16 @@ export default function Toolbar({
background: `linear-gradient(135deg, ${u.color}, ${u.color}dd)`,
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: '10px', fontWeight: 700, color: '#fff',
border: '2px solid #1a1a1a',
border: followingUserId === u.userId ? '2px solid #4a9eff' : '2px solid #1a1a1a',
marginLeft: i > 0 ? '-6px' : '0',
zIndex: 5 - i,
boxShadow: '0 1px 3px rgba(0,0,0,0.3)',
}}>
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()}
</div>
))}