From 82b33a4d5075919e45b5e8d820156d9dd4dc0e01 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 4 Nov 2025 14:18:41 +0100 Subject: [PATCH] style --- frontend/src/DesktopWorkspace.jsx | 107 +++++++++++++++++------- frontend/src/app/DocumentsRoute.jsx | 9 +- frontend/src/desktop/useDocumentDrag.js | 6 +- frontend/src/styles.css | 13 ++- 4 files changed, 100 insertions(+), 35 deletions(-) diff --git a/frontend/src/DesktopWorkspace.jsx b/frontend/src/DesktopWorkspace.jsx index ea34251..01e2899 100644 --- a/frontend/src/DesktopWorkspace.jsx +++ b/frontend/src/DesktopWorkspace.jsx @@ -44,6 +44,47 @@ const DEBUG_DRAG = false; const DEBUG_FOCUS = true; const DEBUG_DROP = true; +const resolveDeskPointerIntent = ({ + alreadySelected = false, + selectedCount = 0, + stackDocIds = null, + metaOrCtrl = false, + pointerButton = 0, +}) => { + const stackList = Array.isArray(stackDocIds) && stackDocIds.length > 0 ? [...stackDocIds] : null; + + if (!metaOrCtrl) { + return { + callEntryPointer: true, + skipSelection: false, + stackDragDocIds: null, + stackClickDocIds: null, + stackReplace: false, + openDetailOnRelease: alreadySelected && pointerButton === 0 && selectedCount > 0, + }; + } + + if (alreadySelected) { + return { + callEntryPointer: false, + skipSelection: true, + stackDragDocIds: stackList, + stackClickDocIds: stackList, + stackReplace: Boolean(stackList), + openDetailOnRelease: false, + }; + } + + return { + callEntryPointer: true, + skipSelection: false, + stackDragDocIds: stackList, + stackClickDocIds: null, + stackReplace: Boolean(stackList), + openDetailOnRelease: false, + }; +}; + const signedDistance = (ax, ay, bx, by, px, py) => (bx - ax) * (py - ay) - (by - ay) * (px - ax); const clipPolygonWithEdge = (subject, edgeStart, edgeEnd) => { @@ -2259,29 +2300,24 @@ const DesktopWorkspaceView = () => { const metaOrCtrlOnly = (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; - let stackDocIds = null; - let appliedStackSelection = false; + const modifierActive = + Boolean(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey); + const pointerButton = typeof event.button === 'number' ? event.button : 0; + const stackHits = metaOrCtrlOnly ? resolveStackDocIds(event, doc.id) : null; + const pointerIntent = resolveDeskPointerIntent({ + alreadySelected, + selectedCount: selectionCountAtDown, + stackDocIds: stackHits, + metaOrCtrl: metaOrCtrlOnly, + pointerButton, + }); - if (metaOrCtrlOnly) { - const hits = resolveStackDocIds(event, doc.id); - if (Array.isArray(hits) && hits.length > 0) { - stackDocIds = hits; - const hasStack = hits.length > 1; - if (hasStack && alreadySelected && typeof onDocumentStackSelect === 'function') { - onDocumentStackSelect(hits, event); - appliedStackSelection = true; - deferredSelectionRef.current = null; - } - } - } + const stackDragDocIds = pointerIntent.stackDragDocIds; + const stackClickDocIds = pointerIntent.stackClickDocIds; if (alreadySelected && typeof onPromoteSelection === 'function') { onPromoteSelection(doc.id, event); } - - const modifierActive = - Boolean(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey); - const pointerButton = typeof event.button === 'number' ? event.button : 0; pointerIntentRef.current = { docId: doc.id, selectedAtDown: alreadySelected, @@ -2289,10 +2325,10 @@ const DesktopWorkspaceView = () => { modifierActive, pointerButton, openDetailOnRelease: - !modifierActive - && alreadySelected - && pointerButton === 0 - && typeof onDocumentOpen === 'function', + pointerIntent.openDetailOnRelease && typeof onDocumentOpen === 'function', + stackDragDocIds, + stackClickDocIds, + stackClickApplied: false, }; const deferSelection = @@ -2301,12 +2337,7 @@ const DesktopWorkspaceView = () => { && Array.isArray(selectedDocumentIds) && selectedDocumentIds.length > 1; - const skipPointerSelection = - appliedStackSelection - || (metaOrCtrlOnly - && alreadySelected - && Array.isArray(stackDocIds) - && stackDocIds.length > 1); + const skipPointerSelection = pointerIntent.skipSelection; if (skipPointerSelection) { deferredSelectionRef.current = null; @@ -2317,7 +2348,7 @@ const DesktopWorkspaceView = () => { }; } else { deferredSelectionRef.current = null; - if (typeof onEntryPointer === 'function') { + if (pointerIntent.callEntryPointer && typeof onEntryPointer === 'function') { onEntryPointer( { type: 'document', id: doc.id, key: `document:${doc.id}` }, event, @@ -2326,10 +2357,11 @@ const DesktopWorkspaceView = () => { } handlePointerDown(event, doc.id, { - stackDocIds, - stackSelectionApplied: appliedStackSelection, + stackDocIds: stackDragDocIds, + stackSelectionApplied: false, wasSelected: alreadySelected, modifierActive, + stackReplace: pointerIntent.stackReplace, }); }} onPointerMove={(event) => { @@ -2356,6 +2388,19 @@ const DesktopWorkspaceView = () => { } } + if ( + !pointerMoved + && pointerState + && pointerState.selectedAtDown + && Array.isArray(pointerState.stackClickDocIds) + && pointerState.stackClickDocIds.length > 0 + && !pointerState.stackClickApplied + && typeof onDocumentStackSelect === 'function' + ) { + onDocumentStackSelect(pointerState.stackClickDocIds, event, { replace: false }); + pointerState.stackClickApplied = true; + } + if ( !pointerMoved && pointerState diff --git a/frontend/src/app/DocumentsRoute.jsx b/frontend/src/app/DocumentsRoute.jsx index 5778ac3..6fcc108 100644 --- a/frontend/src/app/DocumentsRoute.jsx +++ b/frontend/src/app/DocumentsRoute.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAppShell } from '../appShellContext'; import DocumentsLayout from './DocumentsLayout'; @@ -88,6 +88,13 @@ const DocumentsRouteContent = () => { onNavigateParent: handleNavigateParent, }); + useEffect(() => { + document.body.classList.add('has-main-content'); + return () => { + document.body.classList.remove('has-main-content'); + }; + }, []); + if (!surface) { return ( diff --git a/frontend/src/desktop/useDocumentDrag.js b/frontend/src/desktop/useDocumentDrag.js index 4cd3722..d982bf6 100644 --- a/frontend/src/desktop/useDocumentDrag.js +++ b/frontend/src/desktop/useDocumentDrag.js @@ -154,6 +154,7 @@ const useDocumentDrag = () => { const pointerModifierActive = typeof options?.modifierActive === 'boolean' ? options.modifierActive : Boolean(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey); + const stackReplace = Boolean(options?.stackReplace); let selectionIds = Array.isArray(selectedDocumentIds) ? selectedDocumentIds.map((id) => String(id)) @@ -330,6 +331,7 @@ const useDocumentDrag = () => { groupElevated: !isGroupDrag, stackDocIds: hasStackSource ? stackDocIdsOption : null, stackSelectionApplied: stackSelectionAppliedInitial || !hasStackSource, + stackReplace, }; setDraggingId(docId); @@ -412,10 +414,10 @@ const useDocumentDrag = () => { state.isGroup && !state.stackSelectionApplied && Array.isArray(state.stackDocIds) - && state.stackDocIds.length > 1 + && state.stackDocIds.length > 0 ) { if (typeof onDocumentStackSelect === 'function') { - onDocumentStackSelect(state.stackDocIds); + onDocumentStackSelect(state.stackDocIds, event, { replace: state.stackReplace }); } state.stackSelectionApplied = true; } diff --git a/frontend/src/styles.css b/frontend/src/styles.css index e527fe4..6ca24e0 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -266,6 +266,10 @@ body { overflow: hidden; } +body.has-main-content { + background: var(--surface); +} + a { color: var(--accent); text-decoration: underline; @@ -1524,6 +1528,10 @@ button.danger:hover:not([disabled]) { width: 20em; max-width: 20em; flex: 0 0 20em; + background: var(--bg); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + padding-top: -1px; } .sidebar__body { @@ -2715,9 +2723,12 @@ button.danger:hover:not([disabled]) { min-height: 100vh; height: 100%; height: 100%; - background: var(--surface); + background: var(--bg); box-shadow: 0 0 24px var(--shadow-soft); border-left: 1px solid var(--border); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + padding-top: -1px; display: flex; flex-direction: column; z-index: 1000000;