From 18558ab087f548415a0c6180f8c9fcb11c539f11 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Thu, 13 Nov 2025 13:32:26 +0100 Subject: [PATCH] fix --- frontend/src/desktop/DesktopWorkspace.tsx | 3 - .../desktop/tags/useDeskTagInteractions.js | 176 +++--------------- frontend/src/desktop/useDeskWorkspaceProps.ts | 4 - frontend/src/styles/documents/listing.css | 6 +- 4 files changed, 28 insertions(+), 161 deletions(-) diff --git a/frontend/src/desktop/DesktopWorkspace.tsx b/frontend/src/desktop/DesktopWorkspace.tsx index 1d9ade1..b33c0e1 100644 --- a/frontend/src/desktop/DesktopWorkspace.tsx +++ b/frontend/src/desktop/DesktopWorkspace.tsx @@ -124,7 +124,6 @@ interface DesktopWorkspaceProps { onDocumentStackSelect?: (docIds: Identifier[]) => void; onPromoteSelection?: (...args: unknown[]) => void; onAssignTagToDocument?: (...args: unknown[]) => void; - onRemoveTagFromDocument?: (...args: unknown[]) => void; ensureAssetUrl?: (...args: unknown[]) => Promise | unknown; getDocumentAsset?: (...args: unknown[]) => unknown; activeTagIds?: Array; @@ -202,7 +201,6 @@ const DesktopWorkspace: React.FC = ({ onDocumentStackSelect = null, onPromoteSelection = null, onAssignTagToDocument = null, - onRemoveTagFromDocument = null, ensureAssetUrl = null, getDocumentAsset = () => null, activeTagIds = [], @@ -489,7 +487,6 @@ const DesktopWorkspace: React.FC = ({ const tagInteractions = useDeskTagInteractions({ engine, onAssignTagToDocument, - onRemoveTagFromDocument, requestCanvasFocus, }); diff --git a/frontend/src/desktop/tags/useDeskTagInteractions.js b/frontend/src/desktop/tags/useDeskTagInteractions.js index 674c16b..e5fa6d6 100644 --- a/frontend/src/desktop/tags/useDeskTagInteractions.js +++ b/frontend/src/desktop/tags/useDeskTagInteractions.js @@ -11,7 +11,6 @@ import { } from '../../documents/tagTransfer'; const TAG_REMOVE_DISTANCE = 160; -const DEBUG_DROP = false; const createDragPreview = (node, clientX, clientY) => { if (!(node instanceof HTMLElement)) { @@ -42,145 +41,22 @@ const cleanupPreview = (previewNode) => { export const useDeskTagInteractions = ({ engine, onAssignTagToDocument, - onRemoveTagFromDocument, requestCanvasFocus, }) => { - const draggingTagRef = useRef(null); - const pendingDocTagDragRef = useRef(null); - const removalCursorActiveRef = useRef(false); - - const updateRemovalCursor = useCallback((active) => { - if (removalCursorActiveRef.current === active) { - return; - } - const body = document.body; - if (!body) { - return; - } - removalCursorActiveRef.current = active; - if (active) { - body.classList.add('desk-cursor-remove'); - } else { - body.classList.remove('desk-cursor-remove'); - } - }, []); - - useEffect( - () => () => { - updateRemovalCursor(false); - }, - [updateRemovalCursor], - ); const isTagTransfer = useCallback((event) => isTagTransferEvent(event), []); - const handleTagDragEnd = useCallback(() => { - updateRemovalCursor(false); - engine.setTagDropTargetId(null); - }, [engine, updateRemovalCursor]); - - const finalizeTagDrag = useCallback( - (dropEffect = 'none') => { - const state = draggingTagRef.current; - if (!state) { - updateRemovalCursor(false); - return; - } - - draggingTagRef.current = null; - - const node = state.element; - const showNode = () => { - if (node instanceof HTMLElement) { - node.classList.remove('is-drag-hidden'); - } - }; - const scheduleShowNode = () => { - const raf = window.requestAnimationFrame; - if (raf) { - raf(showNode); - } else { - setTimeout(showNode, 0); - } - }; - - cleanupPreview(state.previewClone); - - const shouldRemove = - !state.dropHandled - && dropEffect === 'none' - && state.sourceDocId - && (state.distance || 0) >= TAG_REMOVE_DISTANCE; - - if (!shouldRemove) { - scheduleShowNode(); - updateRemovalCursor(false); - return; - } - - updateRemovalCursor(false); - engine.setPendingRemovalTag({ docId: state.sourceDocId, tagId: state.tagId }); - const removePromise = safeInvoke(onRemoveTagFromDocument, state.sourceDocId, state.tagId); - if (!removePromise || typeof removePromise.then !== 'function') { - scheduleShowNode(); - engine.setPendingRemovalTag(null); - updateRemovalCursor(false); - return; - } - void (async () => { - try { - await removePromise; - void DEBUG_DROP; - } catch (error) { - console.error('Failed to remove tag after drag', error); - scheduleShowNode(); - } finally { - engine.setPendingRemovalTag(null); - } - })(); - }, - [engine, onRemoveTagFromDocument, updateRemovalCursor], - ); - - const handleDocTagPointerDown = useCallback((event, doc, tag) => { - if (!doc || !tag) { - pendingDocTagDragRef.current = null; - return; - } - const { x: startX, y: startY } = getPointerPosition(event); - pendingDocTagDragRef.current = { - docId: doc.id, - tagId: tag.id, - startX, - startY, - }; - updateRemovalCursor(false); - }, [updateRemovalCursor]); - - const markActiveTagDropHandled = useCallback((tagId, sourceDocId = null) => { - const state = draggingTagRef.current; - if (!state) { - return; - } - if (state.tagId !== tagId) { - return; - } - if (sourceDocId && state.sourceDocId !== sourceDocId) { - return; - } - state.dropHandled = true; - }, []); + const handleDocTagPointerDown = useCallback(() => { + engine.setPendingRemovalTag(null); + }, [engine]); const runTagHoverTransition = useCallback( - (event, docId, { applyTarget = false, applyPending = false, updateCursor = true } = {}) => { + (event, docId, { applyTarget = false, applyPending = false } = {}) => { if (!isTagTransfer(event)) { return; } preventAll(event); - if (updateCursor) { - updateRemovalCursor(false); - } const stringId = docId != null ? String(docId) : null; if (applyTarget) { engine.setTagDropTargetId(stringId); @@ -189,7 +65,7 @@ export const useDeskTagInteractions = ({ engine.setPendingTagDocId(stringId); } }, - [engine, isTagTransfer, updateRemovalCursor], + [engine, isTagTransfer], ); const handleTagDragEnterDoc = useCallback( @@ -238,7 +114,7 @@ export const useDeskTagInteractions = ({ if (!payload || !payload.id) { return; } - markActiveTagDropHandled(payload.id, payload.sourceDocId); + engine.setPendingRemovalTag(null); if (payload.sourceDocId === doc.id) { return; @@ -252,7 +128,7 @@ export const useDeskTagInteractions = ({ sourceDocId: payload.sourceDocId ?? null, }); }, - [engine, isTagTransfer, markActiveTagDropHandled, onAssignTagToDocument, requestCanvasFocus], + [engine, isTagTransfer, onAssignTagToDocument, requestCanvasFocus], ); const handleDocTagDragStart = useCallback( @@ -282,12 +158,11 @@ export const useDeskTagInteractions = ({ initialX: pointerX, initialY: pointerY, distance: 0, - dropHandled: false, }; - updateRemovalCursor(false); + engine.setPendingRemovalTag(null); }, - [updateRemovalCursor], + [engine], ); const handleDocTagDrag = useCallback((event) => { @@ -300,35 +175,36 @@ export const useDeskTagInteractions = ({ const dy = y - (state.initialY || 0); state.distance = Math.sqrt(dx * dx + dy * dy); if (state.distance >= TAG_REMOVE_DISTANCE) { - updateRemovalCursor(true); + engine.setPendingRemovalTag({ docId: state.sourceDocId, tagId: state.tagId }); } else { - updateRemovalCursor(false); + engine.setPendingRemovalTag(null); } - }, [updateRemovalCursor]); + }, [engine]); const handleDocTagDragEnd = useCallback( - (event) => { - finalizeTagDrag(event?.dataTransfer?.dropEffect || 'none'); + () => { const state = draggingTagRef.current; - if (!state) { - return; + if (state) { + const element = state.element; + if (element) { + element.classList.remove('is-drag-hidden'); + } + cleanupPreview(state.previewClone); } - const element = state.element; - if (element) { - element.classList.remove('is-drag-hidden'); - } - cleanupPreview(state.previewClone); draggingTagRef.current = null; + engine.setPendingRemovalTag(null); + engine.setTagDropTargetId(null); + engine.setPendingTagDocId(null); }, - [finalizeTagDrag], + [engine], ); useEffect(() => { return () => { draggingTagRef.current = null; - pendingDocTagDragRef.current = null; + engine.setPendingRemovalTag(null); }; - }, []); + }, [engine]); return { handleTagDragEnterDoc, @@ -339,8 +215,6 @@ export const useDeskTagInteractions = ({ handleDocTagDragStart, handleDocTagDrag, handleDocTagDragEnd, - handleTagDragEnd, - markActiveTagDropHandled, handleCanvasDragOver, handleCanvasDragLeave, handleCanvasDrop, diff --git a/frontend/src/desktop/useDeskWorkspaceProps.ts b/frontend/src/desktop/useDeskWorkspaceProps.ts index 01cd3e4..d9686fb 100644 --- a/frontend/src/desktop/useDeskWorkspaceProps.ts +++ b/frontend/src/desktop/useDeskWorkspaceProps.ts @@ -36,7 +36,6 @@ interface UseDeskWorkspacePropsArgs { handleDetailPanelClose?: () => void; resolveThumbnailUrlForDoc?: (doc: DocumentEntry) => string | null; handleDocumentTagDrop?: (...args: unknown[]) => void; - handleTagRemove?: (...args: unknown[]) => void; ensureAssetUrl?: (...args: unknown[]) => void; getDocumentAsset?: (...args: unknown[]) => unknown; activeTagFilters?: Identifier[]; @@ -84,7 +83,6 @@ const useDeskWorkspaceProps = ({ handleDetailPanelClose, resolveThumbnailUrlForDoc, handleDocumentTagDrop, - handleTagRemove, ensureAssetUrl, getDocumentAsset, activeTagFilters = [], @@ -185,7 +183,6 @@ const useDeskWorkspaceProps = ({ onCloseDetailPanel: handleDetailPanelClose, resolveThumbnailUrl: resolveThumbnailUrlForDoc, onAssignTagToDocument: handleDocumentTagDrop, - onRemoveTagFromDocument: handleTagRemove, ensureAssetUrl, getDocumentAsset, activeTagIds: activeTagFilters, @@ -226,7 +223,6 @@ const useDeskWorkspaceProps = ({ handleDetailPanelClose, resolveThumbnailUrlForDoc, handleDocumentTagDrop, - handleTagRemove, ensureAssetUrl, getDocumentAsset, activeTagFilters, diff --git a/frontend/src/styles/documents/listing.css b/frontend/src/styles/documents/listing.css index 0f4c592..415b76b 100644 --- a/frontend/src/styles/documents/listing.css +++ b/frontend/src/styles/documents/listing.css @@ -97,7 +97,7 @@ max-width: min(640px, calc(100% - 2rem)); margin: 0 auto; min-width: 0; - overflow: hidden; + overflow: visible; } .panel-floating__buttons { @@ -153,7 +153,7 @@ pointer-events: auto; min-width: 0; flex: 1 1 auto; - overflow: hidden; + overflow: visible; } .panel-floating-actions--assignments { @@ -163,7 +163,7 @@ min-width: 0; white-space: nowrap; justify-content: flex-start; - overflow: hidden; + overflow: visible; } .panel-floating-actions .quick-add {