diff --git a/frontend/src/DesktopWorkspace.jsx b/frontend/src/DesktopWorkspace.jsx index abaa12a..4afc6fa 100644 --- a/frontend/src/DesktopWorkspace.jsx +++ b/frontend/src/DesktopWorkspace.jsx @@ -583,6 +583,7 @@ const DesktopWorkspace = ({ helpOpen = false, onHelpClose = null, tenantId = null, + viewId = 'default', }) => { const items = useMemo(() => (searchResults ? searchResults : documents), [documents, searchResults]); @@ -628,11 +629,12 @@ const DesktopWorkspace = ({ }, [documentLookup]); const storageKey = useMemo(() => { - if (!tenantId) { + if (!tenantId || !viewId) { return null; } - return `papercrate.desk-layout.${tenantId}`; - }, [tenantId]); + const normalizedViewId = encodeURIComponent(String(viewId)); + return `papercrate.desk-layout.${tenantId}.${normalizedViewId}`; + }, [tenantId, viewId]); const initialPersistedLayout = useMemo(() => { if (!storageKey || typeof window === 'undefined') { @@ -1173,7 +1175,7 @@ const recalcVisibleDocIds = useCallback(() => { return; } layoutDirtyRef.current = false; - const payload = {}; + const merged = new Map(persistedLayoutRef.current); snapshot.forEach((entry, docId) => { if (!docId || !entry) { return; @@ -1183,18 +1185,21 @@ const recalcVisibleDocIds = useCallback(() => { if (!Number.isFinite(centerX) || !Number.isFinite(centerY)) { return; } - payload[docId] = { - centerX, - centerY, - rotation: Number.isFinite(Number(entry.rotation)) ? Number(entry.rotation) : 0, - z: Number.isFinite(Number(entry.z)) ? Number(entry.z) : undefined, - }; + const rotation = Number.isFinite(Number(entry.rotation)) ? Number(entry.rotation) : 0; + const z = Number.isFinite(Number(entry.z)) ? Number(entry.z) : undefined; + merged.set(docId, { centerX, centerY, rotation, z }); + }); + + const payload = {}; + merged.forEach((entry, docId) => { + if (!docId || !entry) { + return; + } + payload[docId] = entry; }); try { window.localStorage.setItem(storageKey, JSON.stringify(payload)); - persistedLayoutRef.current = new Map( - Object.entries(payload).map(([id, value]) => [id, value]), - ); + persistedLayoutRef.current = merged; } catch (error) { console.warn('[desk] Failed to persist desk layout', error); } diff --git a/frontend/src/app/AppLayout.jsx b/frontend/src/app/AppLayout.jsx index a571aa2..e29488e 100644 --- a/frontend/src/app/AppLayout.jsx +++ b/frontend/src/app/AppLayout.jsx @@ -4865,6 +4865,23 @@ const AppLayout = () => { setDeskHelpOpen(false); }, []); + const deskViewId = useMemo(() => { + if (showingSearchResults) { + const trimmedQuery = searchQuery.trim(); + const tagsKey = [...activeTagFilters].sort().join(','); + const correspondentsKey = [...activeCorrespondentFilters].sort().join(','); + return `search:${trimmedQuery}|tags:${tagsKey}|corr:${correspondentsKey}`; + } + const folderKey = selectedFolder && selectedFolder !== '' ? selectedFolder : 'root'; + return `folder:${folderKey}`; + }, [ + showingSearchResults, + searchQuery, + activeTagFilters, + activeCorrespondentFilters, + selectedFolder, + ]); + const deskWorkspaceProps = useMemo( () => ({ documents, @@ -4883,6 +4900,7 @@ const AppLayout = () => { helpOpen: deskHelpOpen, onHelpClose: handleDeskHelpClose, tenantId: currentTenantId, + viewId: deskViewId, selectedDocumentIds, onClearSelection: clearDocumentSelection, detailPanelOpen, @@ -4910,6 +4928,7 @@ const AppLayout = () => { handleDeskHelpOpen, handleDeskHelpClose, currentTenantId, + deskViewId, deskHelpOpen, selectedDocumentIds, clearDocumentSelection, diff --git a/frontend/src/desktop/useDocumentDrag.js b/frontend/src/desktop/useDocumentDrag.js index 9aaa656..964b975 100644 --- a/frontend/src/desktop/useDocumentDrag.js +++ b/frontend/src/desktop/useDocumentDrag.js @@ -171,6 +171,7 @@ const useDocumentDrag = () => { const rotation = simulationState.rotation; layoutRef.current.set(docId, { ...entry, rotation }); + markLayoutDirty?.(); const node = itemRefs.current.get(docId); if (node) { @@ -185,7 +186,7 @@ const useDocumentDrag = () => { const isSettled = Math.abs(angularVelocity) < SETTLE_ANGULAR_VELOCITY; return isSettled; }, - [itemRefs, layoutRef], + [itemRefs, layoutRef, markLayoutDirty], ); const startInertiaAnimation = useCallback( @@ -627,6 +628,8 @@ const useDocumentDrag = () => { item.displayRotation += (item.targetRotation - item.displayRotation) * rotationBlend; } + markLayoutDirty?.(); + const entryItem = layoutRef.current.get(item.docId) || {}; layoutRef.current.set(item.docId, { ...entryItem, @@ -780,6 +783,8 @@ const useDocumentDrag = () => { const pointerInsideCard = Math.abs(pointerLocalX) <= halfWidth && Math.abs(pointerLocalY) <= halfHeight; + markLayoutDirty?.(); + const currentTimestamp = typeof event.timeStamp === 'number' && Number.isFinite(event.timeStamp) ? event.timeStamp @@ -829,6 +834,7 @@ const useDocumentDrag = () => { recalcVisibleDocIds, debugDrag, onDocumentStackSelect, + markLayoutDirty, ], );