diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.jsx b/services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.jsx index e335004faf..e3b0c97117 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.jsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.jsx @@ -1,6 +1,5 @@ import { useRef } from 'react' import PropTypes from 'prop-types' -import { useDragLayer } from 'react-dnd' import classNames from 'classnames' // a custom component rendered on top of a draggable area that renders the @@ -8,12 +7,12 @@ import classNames from 'classnames' // https://react-dnd.github.io/react-dnd/examples/drag-around/custom-drag-layer // for more details. // Also used to display a container border when hovered. -function FileTreeDraggablePreviewLayer({ isOver }) { - const { isDragging, item, clientOffset } = useDragLayer(monitor => ({ - isDragging: monitor.isDragging(), - item: monitor.getItem(), - clientOffset: monitor.getClientOffset(), - })) +function FileTreeDraggablePreviewLayer({ + isOver, + isDragging, + item, + clientOffset, +}) { const ref = useRef() return ( @@ -39,6 +38,11 @@ function FileTreeDraggablePreviewLayer({ isOver }) { FileTreeDraggablePreviewLayer.propTypes = { isOver: PropTypes.bool.isRequired, + isDragging: PropTypes.bool.isRequired, + item: PropTypes.shape({ + title: PropTypes.string.isRequired, + }), + clientOffset: PropTypes.number, } function DraggablePreviewItem({ title }) { diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.jsx b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.jsx index 6f8db60910..ce497963ab 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.jsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-inner.jsx @@ -11,6 +11,7 @@ import FileTreeItemName from './file-tree-item-name' import FileTreeItemMenu from './file-tree-item-menu' import { useFileTreeSelectable } from '../../contexts/file-tree-selectable' import { useFileTreeActionable } from '../../contexts/file-tree-actionable' +import { useDragDropManager } from 'react-dnd' function FileTreeItemInner({ id, name, isSelected, icons }) { const { permissionsLevel } = useEditorContext(editorContextPropTypes) @@ -24,7 +25,9 @@ function FileTreeItemInner({ id, name, isSelected, icons }) { isSelected && selectedEntityIds.size === 1 - const { isDragging, dragRef, setIsDraggable } = useDraggable(id) + const { dragRef, setIsDraggable } = useDraggable(id) + + const dragDropItem = useDragDropManager().getMonitor().getItem() const itemRef = useRef() @@ -58,7 +61,7 @@ function FileTreeItemInner({ id, name, isSelected, icons }) { return (
({ + isDragging: monitor.isDragging(), + item: monitor.getItem(), + clientOffset: monitor.getClientOffset(), + })) + return ( <> - + diff --git a/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.jsx b/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.jsx index b9d81e57a2..c92a0ef335 100644 --- a/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.jsx +++ b/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.jsx @@ -88,7 +88,7 @@ export function useDraggable(draggedEntityId) { const [isDraggable, setIsDraggable] = useState(true) const item = { type: DRAGGABLE_TYPE } - const [{ isDragging }, dragRef, preview] = useDrag({ + const [{ isDragging, draggedEntityIds }, dragRef, preview] = useDrag({ item, // required, but overwritten by the return value of `begin` begin: () => { const draggedEntityIds = getDraggedEntityIds( @@ -104,6 +104,7 @@ export function useDraggable(draggedEntityId) { isDragging: !!monitor.isDragging(), }), canDrag: () => permissionsLevel !== 'readOnly' && isDraggable, + end: () => item, }) // remove the automatic preview as we're using a custom preview via @@ -116,6 +117,7 @@ export function useDraggable(draggedEntityId) { dragRef, isDragging, setIsDraggable, + draggedEntityIds, } } diff --git a/services/web/frontend/stylesheets/app/editor/file-tree.less b/services/web/frontend/stylesheets/app/editor/file-tree.less index 689f456bc5..cea955c581 100644 --- a/services/web/frontend/stylesheets/app/editor/file-tree.less +++ b/services/web/frontend/stylesheets/app/editor/file-tree.less @@ -67,22 +67,6 @@ } } - li.dnd-droppable-hover .entity-name, - li .entity-name.droppable-hover { - font-weight: bold; - background-color: @file-tree-item-hover-bg; - .fake-full-width-bg(@file-tree-item-hover-bg); - } - - ul.droppable-hover li div.entity-name:hover { - background-color: transparent; - .fake-full-width-bg(transparent); - &.droppable-hover { - background-color: @file-tree-item-hover-bg; - .fake-full-width-bg(@file-tree-item-hover-bg); - } - } - ul.file-tree-list { margin: 0; overflow-x: hidden; @@ -144,10 +128,10 @@ &:focus { outline: none; } + background-color: transparent; &:hover { background-color: @file-tree-item-hover-bg; - } - &:hover { + // When the entity is a subfolder, the DOM element is "indented" via margin-left. This makes the // element not fill the entire file-tree width (as it's spaced from the left-hand side via margin) // and, in consequence, the background gets clipped. The ::before pseudo-selector is used to fill @@ -163,13 +147,6 @@ } } - .entity.dnd-draggable-dragging { - .entity-name:hover { - background-color: transparent; - .fake-full-width-bg(transparent); - } - } - i.fa { color: @file-tree-item-icon-color; font-size: 14px; @@ -309,15 +286,18 @@ > .entity { > .entity-name { color: @file-tree-item-selected-color; + > div > i.fa, > button > i.fa, > i.fa, .entity-menu-toggle i.fa { color: @file-tree-item-selected-color; } + > i.linked-file-highlight { color: @blue; } + background-color: @file-tree-item-selected-bg; font-weight: bold; padding-right: 32px; @@ -332,13 +312,43 @@ } } } - ul.file-tree-list li.selected.dnd-droppable-hover { - > .entity { - > .entity-name { - background-color: @file-tree-item-hover-bg; - .fake-full-width-bg(@file-tree-item-hover-bg); - } - } + } + + // while dragging, the previously selected item gets no highlight + ul.file-tree-list.file-tree-dragging li.selected .entity .entity-name { + font-weight: normal; + + background-color: transparent; + .fake-full-width-bg(transparent); + color: @file-tree-item-color; + i.fa { + color: @file-tree-item-icon-color !important; + } + } + + // the items being dragged get the full "hover" colour + ul.file-tree-list.file-tree-dragging + li + .entity.file-tree-entity-dragging + .entity-name { + background-color: fade(@file-tree-item-hover-bg, 90%); + .fake-full-width-bg(fade(@file-tree-item-hover-bg, 90%)); + color: @file-tree-item-color; + i.fa { + color: @file-tree-item-icon-color !important; + } + } + + // the drop target gets the "selected" colour + ul.file-tree-list.file-tree-dragging + li.dnd-droppable-hover + .entity + .entity-name { + background-color: @file-tree-item-selected-bg; + .fake-full-width-bg(@file-tree-item-selected-bg); + color: @file-tree-item-selected-color; + i.fa { + color: @file-tree-item-selected-color !important; } } @@ -355,8 +365,7 @@ } } - .dnd-draggable-preview-item, - .ui-draggable-dragging { + .dnd-draggable-preview-item { background-color: fade(@file-tree-item-selected-bg, 60%); color: @file-tree-item-selected-color; width: 75%;