diff --git a/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx b/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx index 5d195732..7eb4b036 100644 --- a/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx +++ b/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx @@ -7,7 +7,6 @@ import TetherLayer from './TetherLayer'; import DashboardCardLayer from './DashboardCardLayer'; import DashboardOverlays from './DashboardOverlays'; import DashboardEmptyState from './DashboardEmptyState'; -import SnapZonePreview from './SnapZonePreview'; import '../desktop/desktop.css'; import DesktopDock from '../desktop/DesktopDock'; import MinimizedStack from '../desktop/MinimizedStack'; @@ -62,7 +61,6 @@ interface DashboardCanvasProps { focusedCardId: string | null; pendingFocusNoteId: string | null; multiDragDelta: { dx: number; dy: number } | null; - snapZone: string | null; shakeDirection: Direction | null; neighborDirections: NeighborDirections; toolbarOpen: boolean; @@ -126,7 +124,6 @@ const DashboardCanvas: React.FC = ({ focusedCardId, pendingFocusNoteId, multiDragDelta, - snapZone, shakeDirection, neighborDirections, toolbarOpen, @@ -268,8 +265,6 @@ const DashboardCanvas: React.FC = ({ /> )} - - {!anyFullscreen && ( = ({ zone }) => { - const c = useClaudeTokens(); - if (!zone) return null; - - const vp = document.querySelector('[data-canvas-viewport]'); - const rect = vp ? vp.getBoundingClientRect() : { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight }; - const frac = zone === 'fullscreen' ? { x: 0, y: 0, w: 1, h: 1 } : TILE_ZONES[zone]; - if (!frac) return null; - - return ( -
- ); -}; - -export default SnapZonePreview; diff --git a/frontend/src/app/pages/Dashboard/hooks/interaction/useCardDrag.ts b/frontend/src/app/pages/Dashboard/hooks/interaction/useCardDrag.ts index 1c609173..c01850e7 100644 --- a/frontend/src/app/pages/Dashboard/hooks/interaction/useCardDrag.ts +++ b/frontend/src/app/pages/Dashboard/hooks/interaction/useCardDrag.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState, type RefObject } from 'react'; import { report } from '@/shared/serviceClient'; import { useAppDispatch } from '@/shared/hooks'; -import { moveCards, setTiledCard } from '@/shared/state/dashboardLayoutSlice'; +import { moveCards } from '@/shared/state/dashboardLayoutSlice'; import type { CardType, useDashboardSelection } from '../state/useDashboardSelection'; import type { CanvasActions } from './useCanvasControls'; @@ -15,25 +15,6 @@ interface UseCardDragArgs { const EDGE_ZONE = 60; const EDGE_MAX_SPEED = 8; -// Jam a dragged card into the very edge (inside the pan zone) to snap-tile it. Grazing the 60px -// edge still pans the infinite canvas; only the inner 24px band arms a snap and pauses the pan, so -// the two never fight. Top = fullscreen (macOS drag-to-top), sides = halves, corners = quarters. -const SNAP_BAND = 24; - -function snapZoneFor(mx: number, my: number, rect: DOMRect): string | null { - const nearL = mx <= rect.left + SNAP_BAND; - const nearR = mx >= rect.right - SNAP_BAND; - const nearT = my <= rect.top + SNAP_BAND; - const nearB = my >= rect.bottom - SNAP_BAND; - if (nearT && nearL) return 'tl'; - if (nearT && nearR) return 'tr'; - if (nearB && nearL) return 'bl'; - if (nearB && nearR) return 'br'; - if (nearT) return 'fullscreen'; - if (nearL) return 'left'; - if (nearR) return 'right'; - return null; // bottom-center is left alone: the composer + dock live there. -} // Clamped: an infinite canvas lets the cursor sit arbitrarily far outside the viewport, where an unclamped ramp would scale pan speed with distance instead of saturating. function axisIntensity(pos: number, lo: number, hi: number): number { @@ -51,10 +32,6 @@ export function useCardDrag({ const [multiDragDelta, setMultiDragDelta] = useState<{ dx: number; dy: number } | null>(null); const [liveDragInfo, setLiveDragInfo] = useState<{ cardId: string; dx: number; dy: number } | null>(null); - const [snapZone, setSnapZone] = useState(null); - const snapZoneRef = useRef(null); - // Snap only a lone card: dragging one of several selected cards to the edge shouldn't tile just it. - const snapEligibleRef = useRef(true); const activeDragCardRef = useRef(null); const isMultiDragRef = useRef(false); @@ -80,8 +57,7 @@ export function useCardDrag({ const dx = EDGE_MAX_SPEED * axisIntensity(mx, rect.left, rect.right); const dy = EDGE_MAX_SPEED * axisIntensity(my, rect.top, rect.bottom); - // Snap armed = the card is about to tile at this edge, so freeze the canvas instead of panning. - if ((dx !== 0 || dy !== 0) && !snapZoneRef.current) { + if (dx !== 0 || dy !== 0) { // Live-only write (no React commit per frame); clearDrag commits once when the drag ends. canvasActions.panBy(dx, dy); } @@ -91,7 +67,6 @@ export function useCardDrag({ const handleCardDragStart = useCallback((id: string, type: CardType) => { activeDragCardRef.current = id; - snapEligibleRef.current = selection.selectedArray().filter((s) => s.id !== id).length === 0; if (selection.isSelected(id)) { isMultiDragRef.current = true; } else { @@ -105,16 +80,6 @@ export function useCardDrag({ if (mouseX !== undefined && mouseY !== undefined) { lastMousePosRef.current = { x: mouseX, y: mouseY }; } - // Arm/clear the snap target from the live cursor. Single-card drags only: snapping one card of a - // multi-selection while the rest move is incoherent. - const vp = viewportRef.current; - const nextSnap = (vp && snapEligibleRef.current && mouseX !== undefined && mouseY !== undefined) - ? snapZoneFor(mouseX, mouseY, vp.getBoundingClientRect()) - : null; - if (nextSnap !== snapZoneRef.current) { - snapZoneRef.current = nextSnap; - setSnapZone(nextSnap); - } // Arm the webview shield on the first real MOVE, not on pointerdown: a plain click also arms the drag machinery, and shielding then made the click-to-focus camera fit skip (it saw a "drag in progress"), so focusing a card took two clicks. On a real drag the shield still goes up before the pointer travels, so the webview neutralization + no-nudge + release-over-webview fixes all hold. Idempotent add. document.body.classList.add('dashboard-marquee-active'); // Start edge panning only once actual dragging begins; a live frame handle means the loop is already running. @@ -134,8 +99,6 @@ export function useCardDrag({ // Reconcile React with whatever edge-pan wrote live during the drag. canvasActions.commit(); activeDragCardRef.current = null; - snapZoneRef.current = null; - setSnapZone(null); document.body.classList.remove('dashboard-marquee-active'); isMultiDragRef.current = false; setMultiDragDelta(null); @@ -144,12 +107,7 @@ export function useCardDrag({ const handleCardDragEnd = useCallback((dx: number, dy: number, didDrag: boolean) => { if (didDrag) report('dashboard', 'card_dragged'); - const snap = snapZoneRef.current; - const activeId = activeDragCardRef.current; - if (snap && didDrag && activeId) { - // Released against the edge: tile the card there instead of leaving it at the drop position. - dispatch(setTiledCard({ cardId: activeId, zone: snap })); - } else if (isMultiDragRef.current && didDrag) { + if (isMultiDragRef.current && didDrag) { const items = selection.selectedArray() .filter((s) => s.id !== activeDragCardRef.current); if (items.length > 0) { @@ -176,7 +134,6 @@ export function useCardDrag({ return { multiDragDelta, liveDragInfo, - snapZone, handleCardDragStart, handleCardDragMove, handleCardDragEnd, diff --git a/frontend/src/app/pages/Dashboard/hooks/state/useDashboardController.ts b/frontend/src/app/pages/Dashboard/hooks/state/useDashboardController.ts index 7a1db232..7a06e8ba 100644 --- a/frontend/src/app/pages/Dashboard/hooks/state/useDashboardController.ts +++ b/frontend/src/app/pages/Dashboard/hooks/state/useDashboardController.ts @@ -103,7 +103,6 @@ export function useDashboardController(dashboardId: string, isActive: boolean) { const { multiDragDelta, liveDragInfo, - snapZone, handleCardDragStart, handleCardDragMove, handleCardDragEnd, @@ -333,7 +332,7 @@ export function useDashboardController(dashboardId: string, isActive: boolean) { cards, viewCards, browserCards, keepAliveBrowserCards, notes, outputs, glowingAgentCards, workflowCards, workflowsHub, expandedSessionIds, tethers, highlightedCardId, autoFocusSessionId, - focusedCardId, pendingFocusNoteId, multiDragDelta, snapZone, shakeDirection, + focusedCardId, pendingFocusNoteId, multiDragDelta, shakeDirection, neighborDirections, toolbarOpen, searchPaletteOpen, newAgentBounce, toolbarRef, spawnOriginsRef, revealSpawnedRef, measuredHeightsRef, getCanvasState, toolbarPrefill,