Skip to content

Commit e350a9c

Browse files
committed
cahnged color, removed flicker on folder container
1 parent df54029 commit e350a9c

File tree

4 files changed

+102
-30
lines changed

4 files changed

+102
-30
lines changed

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
2929

3030
const logger = createLogger('FolderItem')
3131

32-
const EMPTY_DRAG_IMAGE = new Image(1, 1)
33-
EMPTY_DRAG_IMAGE.src =
34-
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
32+
let EMPTY_DRAG_IMAGE: HTMLImageElement | null = null
33+
function getEmptyDragImage(): HTMLImageElement {
34+
if (!EMPTY_DRAG_IMAGE && typeof window !== 'undefined') {
35+
EMPTY_DRAG_IMAGE = new Image(1, 1)
36+
EMPTY_DRAG_IMAGE.src =
37+
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
38+
}
39+
return EMPTY_DRAG_IMAGE!
40+
}
3541

3642
interface FolderItemProps {
3743
folder: FolderTreeNode
@@ -154,8 +160,9 @@ export function FolderItem({
154160
return
155161
}
156162

157-
if (EMPTY_DRAG_IMAGE.complete) {
158-
e.dataTransfer.setDragImage(EMPTY_DRAG_IMAGE, 0, 0)
163+
const emptyImg = getEmptyDragImage()
164+
if (emptyImg?.complete) {
165+
e.dataTransfer.setDragImage(emptyImg, 0, 0)
159166
}
160167

161168
e.dataTransfer.setData('folder-id', folder.id)

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ import { useFolderStore } from '@/stores/folders/store'
2424
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
2525
import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
2626

27-
const EMPTY_DRAG_IMAGE = new Image(1, 1)
28-
EMPTY_DRAG_IMAGE.src =
29-
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
27+
let EMPTY_DRAG_IMAGE: HTMLImageElement | null = null
28+
function getEmptyDragImage(): HTMLImageElement {
29+
if (!EMPTY_DRAG_IMAGE && typeof window !== 'undefined') {
30+
EMPTY_DRAG_IMAGE = new Image(1, 1)
31+
EMPTY_DRAG_IMAGE.src =
32+
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
33+
}
34+
return EMPTY_DRAG_IMAGE!
35+
}
3036

3137
interface WorkflowItemProps {
3238
workflow: WorkflowMetadata
@@ -231,8 +237,9 @@ export function WorkflowItem({
231237
return
232238
}
233239

234-
if (EMPTY_DRAG_IMAGE.complete) {
235-
e.dataTransfer.setDragImage(EMPTY_DRAG_IMAGE, 0, 0)
240+
const emptyImg = getEmptyDragImage()
241+
if (emptyImg?.complete) {
242+
e.dataTransfer.setDragImage(emptyImg, 0, 0)
236243
}
237244

238245
const currentSelection = useFolderStore.getState().selectedWorkflows

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export function WorkflowList({
6060
createWorkflowDragHandlers,
6161
createFolderDragHandlers,
6262
createEmptyFolderDropZone,
63+
createFolderContentDropZone,
6364
createRootDropZone,
6465
handleDragStart,
6566
handleDragEnd,
@@ -245,7 +246,7 @@ export function WorkflowList({
245246
<DropIndicatorLine show={showAfter} level={level} />
246247

247248
{isExpanded && (hasChildren || isDragging) && (
248-
<div className='relative'>
249+
<div className='relative' {...createFolderContentDropZone(folder.id)}>
249250
<div
250251
className='pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--border)]'
251252
style={{ left: `${level * TREE_SPACING.INDENT_PER_LEVEL + 12}px` }}
@@ -272,6 +273,7 @@ export function WorkflowList({
272273
isDragging,
273274
createFolderDragHandlers,
274275
createEmptyFolderDropZone,
276+
createFolderContentDropZone,
275277
handleDragStart,
276278
handleDragEnd,
277279
renderWorkflowItem,

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,19 @@ export function useDragDrop() {
120120
[]
121121
)
122122

123+
const calculateFolderDropPosition = useCallback(
124+
(e: React.DragEvent, element: HTMLElement): 'before' | 'inside' | 'after' => {
125+
const rect = element.getBoundingClientRect()
126+
const relativeY = e.clientY - rect.top
127+
const height = rect.height
128+
// Top 25% = before, middle 50% = inside, bottom 25% = after
129+
if (relativeY < height * 0.25) return 'before'
130+
if (relativeY > height * 0.75) return 'after'
131+
return 'inside'
132+
},
133+
[]
134+
)
135+
123136
type SiblingItem = { type: 'folder' | 'workflow'; id: string; sortOrder: number }
124137

125138
const getDestinationFolderId = useCallback((indicator: DropIndicator): string | null => {
@@ -193,24 +206,34 @@ export function useDragDrop() {
193206

194207
const setNormalizedDropIndicator = useCallback(
195208
(indicator: DropIndicator | null) => {
196-
if (!indicator || indicator.position !== 'after' || indicator.targetId === 'root') {
197-
setDropIndicator(indicator)
198-
return
199-
}
209+
setDropIndicator((prev) => {
210+
let next: DropIndicator | null = indicator
211+
212+
// Normalize 'after' to 'before' of next sibling
213+
if (indicator && indicator.position === 'after' && indicator.targetId !== 'root') {
214+
const siblings = getSiblingItems(indicator.folderId)
215+
const currentIdx = siblings.findIndex((s) => s.id === indicator.targetId)
216+
const nextSibling = siblings[currentIdx + 1]
217+
if (nextSibling) {
218+
next = {
219+
targetId: nextSibling.id,
220+
position: 'before',
221+
folderId: indicator.folderId,
222+
}
223+
}
224+
}
200225

201-
const siblings = getSiblingItems(indicator.folderId)
202-
const currentIdx = siblings.findIndex((s) => s.id === indicator.targetId)
203-
const nextSibling = siblings[currentIdx + 1]
204-
205-
if (nextSibling) {
206-
setDropIndicator({
207-
targetId: nextSibling.id,
208-
position: 'before',
209-
folderId: indicator.folderId,
210-
})
211-
} else {
212-
setDropIndicator(indicator)
213-
}
226+
// Skip update if indicator hasn't changed
227+
if (
228+
prev?.targetId === next?.targetId &&
229+
prev?.position === next?.position &&
230+
prev?.folderId === next?.folderId
231+
) {
232+
return prev
233+
}
234+
235+
return next
236+
})
214237
},
215238
[getSiblingItems]
216239
)
@@ -431,11 +454,19 @@ export function useDragDrop() {
431454
setHoverFolderId(folderId)
432455
}
433456
} else {
457+
// Workflow being dragged over a folder
434458
const isSameParent = draggedSourceFolderRef.current === parentFolderId
435459
if (isSameParent) {
436-
const position = calculateDropPosition(e, e.currentTarget)
460+
// Same level - use three zones: top=before, middle=inside, bottom=after
461+
const position = calculateFolderDropPosition(e, e.currentTarget)
437462
setNormalizedDropIndicator({ targetId: folderId, position, folderId: parentFolderId })
463+
if (position === 'inside') {
464+
setHoverFolderId(folderId)
465+
} else {
466+
setHoverFolderId(null)
467+
}
438468
} else {
469+
// Different container - drop into folder
439470
setNormalizedDropIndicator({
440471
targetId: folderId,
441472
position: 'inside',
@@ -450,7 +481,14 @@ export function useDragDrop() {
450481
},
451482
onDrop: handleDrop,
452483
}),
453-
[initDragOver, calculateDropPosition, setNormalizedDropIndicator, isLeavingElement, handleDrop]
484+
[
485+
initDragOver,
486+
calculateDropPosition,
487+
calculateFolderDropPosition,
488+
setNormalizedDropIndicator,
489+
isLeavingElement,
490+
handleDrop,
491+
]
454492
)
455493

456494
const createEmptyFolderDropZone = useCallback(
@@ -464,6 +502,23 @@ export function useDragDrop() {
464502
[initDragOver, setNormalizedDropIndicator, handleDrop]
465503
)
466504

505+
const createFolderContentDropZone = useCallback(
506+
(folderId: string) => ({
507+
onDragOver: (e: React.DragEvent<HTMLElement>) => {
508+
e.preventDefault()
509+
e.stopPropagation() // Prevent bubbling to root when in gaps between items
510+
lastDragYRef.current = e.clientY
511+
setIsDragging(true)
512+
// Only set folder highlight if dragging from a different folder
513+
if (draggedSourceFolderRef.current !== folderId) {
514+
setNormalizedDropIndicator({ targetId: folderId, position: 'inside', folderId: null })
515+
}
516+
},
517+
onDrop: handleDrop,
518+
}),
519+
[setNormalizedDropIndicator, handleDrop]
520+
)
521+
467522
const createRootDropZone = useCallback(
468523
() => ({
469524
onDragOver: (e: React.DragEvent<HTMLElement>) => {
@@ -506,6 +561,7 @@ export function useDragDrop() {
506561
createWorkflowDragHandlers,
507562
createFolderDragHandlers,
508563
createEmptyFolderDropZone,
564+
createFolderContentDropZone,
509565
createRootDropZone,
510566
handleDragStart,
511567
handleDragEnd,

0 commit comments

Comments
 (0)