mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 03:29:02 +01:00 
			
		
		
		
	chore(react/collections/table): set up column dragging
This commit is contained in:
		
							parent
							
								
									ce0da3fb80
								
							
						
					
					
						commit
						c30c9a7360
					
				| @ -144,7 +144,10 @@ function useViewModeConfig<T extends object>(note: FNote | null | undefined, vie | |||||||
|         if (!note || !viewType) return; |         if (!note || !viewType) return; | ||||||
|         const viewStorage = new ViewModeStorage<T>(note, viewType); |         const viewStorage = new ViewModeStorage<T>(note, viewType); | ||||||
|         viewStorage.restore().then(config => { |         viewStorage.restore().then(config => { | ||||||
|             const storeFn = (config: T) => viewStorage.store(config); |             const storeFn = (config: T) => { | ||||||
|  |                 setViewConfig([ config, storeFn ]); | ||||||
|  |                 viewStorage.store(config); | ||||||
|  |             }; | ||||||
|             setViewConfig([ config, storeFn ]); |             setViewConfig([ config, storeFn ]); | ||||||
|         }); |         }); | ||||||
|     }, [ note, viewType ]); |     }, [ note, viewType ]); | ||||||
|  | |||||||
| @ -66,9 +66,10 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .board-view-container .board-column.column-dragging { | .board-view-container .board-column.column-dragging { | ||||||
|   opacity: 0.6; |   opacity: 0.5; | ||||||
|   transform: scale(0.98); |   transform: scale(0.98) rotate(2deg); | ||||||
|   transition: opacity 0.2s ease, transform 0.2s ease; |   transition: opacity 0.2s ease, transform 0.2s ease; | ||||||
|  |   box-shadow: 4px 8px 16px rgba(0, 0, 0, 0.3); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .board-view-container .board-column h3 input { | .board-view-container .board-column h3 input { | ||||||
| @ -185,20 +186,19 @@ | |||||||
|   opacity: 0.6; |   opacity: 0.6; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .column-drop-indicator { | .column-drop-placeholder { | ||||||
|   width: 4px; |   width: 250px; | ||||||
|   background-color: var(--main-text-color); |  | ||||||
|   border-radius: 2px; |  | ||||||
|   opacity: 0; |  | ||||||
|   transition: opacity 0.2s ease; |  | ||||||
|   height: 100%; |  | ||||||
|   z-index: 1000; |  | ||||||
|   box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); |  | ||||||
|   flex-shrink: 0; |   flex-shrink: 0; | ||||||
|  |   height: 200px; | ||||||
|  |   border-radius: 8px; | ||||||
|  |   background-color: rgba(0, 0, 0, 0.1); | ||||||
|  |   opacity: 0; | ||||||
|  |   transition: opacity 0.15s ease; | ||||||
|  |   margin: 0 0.5em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .column-drop-indicator.show { | .column-drop-placeholder.show { | ||||||
|   opacity: 1; |   opacity: 0.6; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .board-new-item { | .board-new-item { | ||||||
|  | |||||||
| @ -26,6 +26,8 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC | |||||||
|     const [ draggedCard, setDraggedCard ] = useState<{ noteId: string, branchId: string, fromColumn: string, index: number } | null>(null); |     const [ draggedCard, setDraggedCard ] = useState<{ noteId: string, branchId: string, fromColumn: string, index: number } | null>(null); | ||||||
|     const [ dropTarget, setDropTarget ] = useState<string | null>(null); |     const [ dropTarget, setDropTarget ] = useState<string | null>(null); | ||||||
|     const [ dropPosition, setDropPosition ] = useState<{ column: string, index: number } | null>(null); |     const [ dropPosition, setDropPosition ] = useState<{ column: string, index: number } | null>(null); | ||||||
|  |     const [ draggedColumn, setDraggedColumn ] = useState<{ column: string, index: number } | null>(null); | ||||||
|  |     const [ columnDropPosition, setColumnDropPosition ] = useState<number | null>(null); | ||||||
| 
 | 
 | ||||||
|     function refresh() { |     function refresh() { | ||||||
|         getBoardData(parentNote, statusAttribute ?? "status", viewConfig ?? {}).then(({ byColumn, newPersistedData }) => { |         getBoardData(parentNote, statusAttribute ?? "status", viewConfig ?? {}).then(({ byColumn, newPersistedData }) => { | ||||||
| @ -46,6 +48,26 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC | |||||||
| 
 | 
 | ||||||
|     useEffect(refresh, [ parentNote, noteIds ]); |     useEffect(refresh, [ parentNote, noteIds ]); | ||||||
| 
 | 
 | ||||||
|  |     const handleColumnDrop = useCallback((fromIndex: number, toIndex: number) => { | ||||||
|  |         if (!columns || fromIndex === toIndex) return; | ||||||
|  | 
 | ||||||
|  |         const newColumns = [...columns]; | ||||||
|  |         const [movedColumn] = newColumns.splice(fromIndex, 1); | ||||||
|  |         newColumns.splice(toIndex, 0, movedColumn); | ||||||
|  | 
 | ||||||
|  |         // Update view config with new column order
 | ||||||
|  |         const newViewConfig = { | ||||||
|  |             ...viewConfig, | ||||||
|  |             columns: newColumns.map(col => ({ value: col })) | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         saveConfig(newViewConfig); | ||||||
|  |         setColumns(newColumns); | ||||||
|  |         console.log("New columns are ", newColumns); | ||||||
|  |         setDraggedColumn(null); | ||||||
|  |         setColumnDropPosition(null); | ||||||
|  |     }, [columns, viewConfig, saveConfig]); | ||||||
|  | 
 | ||||||
|     useTriliumEvent("entitiesReloaded", ({ loadResults }) => { |     useTriliumEvent("entitiesReloaded", ({ loadResults }) => { | ||||||
|         // Check if any changes affect our board
 |         // Check if any changes affect our board
 | ||||||
|         const hasRelevantChanges = |         const hasRelevantChanges = | ||||||
| @ -67,12 +89,51 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC | |||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     const handleColumnDragOver = useCallback((e: DragEvent) => { | ||||||
|  |         if (!draggedColumn) return; | ||||||
|  |         e.preventDefault(); | ||||||
|  | 
 | ||||||
|  |         const container = e.currentTarget as HTMLElement; | ||||||
|  |         const columns = Array.from(container.querySelectorAll('.board-column')); | ||||||
|  |         const mouseX = e.clientX; | ||||||
|  | 
 | ||||||
|  |         let newIndex = columns.length; | ||||||
|  |         for (let i = 0; i < columns.length; i++) { | ||||||
|  |             const col = columns[i] as HTMLElement; | ||||||
|  |             const rect = col.getBoundingClientRect(); | ||||||
|  |             const colMiddle = rect.left + rect.width / 2; | ||||||
|  | 
 | ||||||
|  |             if (mouseX < colMiddle) { | ||||||
|  |                 newIndex = i; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         setColumnDropPosition(newIndex); | ||||||
|  |     }, [draggedColumn]); | ||||||
|  | 
 | ||||||
|  |     const handleContainerDrop = useCallback((e: DragEvent) => { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         if (draggedColumn && columnDropPosition !== null) { | ||||||
|  |             handleColumnDrop(draggedColumn.index, columnDropPosition); | ||||||
|  |         } | ||||||
|  |     }, [draggedColumn, columnDropPosition, handleColumnDrop]); | ||||||
|  | 
 | ||||||
|     return ( |     return ( | ||||||
|         <div className="board-view"> |         <div className="board-view"> | ||||||
|             <div className="board-view-container"> |             <div | ||||||
|                 {byColumn && columns?.map(column => ( |                 className="board-view-container" | ||||||
|  |                 onDragOver={handleColumnDragOver} | ||||||
|  |                 onDrop={handleContainerDrop} | ||||||
|  |             > | ||||||
|  |                 {byColumn && columns?.map((column, index) => ( | ||||||
|  |                     <> | ||||||
|  |                         {columnDropPosition === index && draggedColumn?.column !== column && ( | ||||||
|  |                             <div className="column-drop-placeholder show" /> | ||||||
|  |                         )} | ||||||
|                         <Column |                         <Column | ||||||
|                             column={column} |                             column={column} | ||||||
|  |                             columnIndex={index} | ||||||
|                             columnItems={byColumn.get(column)} |                             columnItems={byColumn.get(column)} | ||||||
|                             parentNote={parentNote} |                             parentNote={parentNote} | ||||||
|                             statusAttribute={statusAttribute ?? "status"} |                             statusAttribute={statusAttribute ?? "status"} | ||||||
| @ -83,8 +144,15 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC | |||||||
|                             dropPosition={dropPosition} |                             dropPosition={dropPosition} | ||||||
|                             setDropPosition={setDropPosition} |                             setDropPosition={setDropPosition} | ||||||
|                             onCardDrop={refresh} |                             onCardDrop={refresh} | ||||||
|  |                             draggedColumn={draggedColumn} | ||||||
|  |                             setDraggedColumn={setDraggedColumn} | ||||||
|  |                             isDraggingColumn={draggedColumn?.column === column} | ||||||
|                         /> |                         /> | ||||||
|  |                     </> | ||||||
|                 ))} |                 ))} | ||||||
|  |                 {columnDropPosition === columns?.length && draggedColumn && ( | ||||||
|  |                     <div className="column-drop-placeholder show" /> | ||||||
|  |                 )} | ||||||
| 
 | 
 | ||||||
|                 <AddNewColumn viewConfig={viewConfig} saveConfig={saveConfig} /> |                 <AddNewColumn viewConfig={viewConfig} saveConfig={saveConfig} /> | ||||||
|             </div> |             </div> | ||||||
| @ -95,6 +163,7 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC | |||||||
| function Column({ | function Column({ | ||||||
|     parentNote, |     parentNote, | ||||||
|     column, |     column, | ||||||
|  |     columnIndex, | ||||||
|     columnItems, |     columnItems, | ||||||
|     statusAttribute, |     statusAttribute, | ||||||
|     draggedCard, |     draggedCard, | ||||||
| @ -103,10 +172,14 @@ function Column({ | |||||||
|     setDropTarget, |     setDropTarget, | ||||||
|     dropPosition, |     dropPosition, | ||||||
|     setDropPosition, |     setDropPosition, | ||||||
|     onCardDrop |     onCardDrop, | ||||||
|  |     draggedColumn, | ||||||
|  |     setDraggedColumn, | ||||||
|  |     isDraggingColumn | ||||||
| }: { | }: { | ||||||
|     parentNote: FNote, |     parentNote: FNote, | ||||||
|     column: string, |     column: string, | ||||||
|  |     columnIndex: number, | ||||||
|     columnItems?: { note: FNote, branch: FBranch }[], |     columnItems?: { note: FNote, branch: FBranch }[], | ||||||
|     statusAttribute: string, |     statusAttribute: string, | ||||||
|     draggedCard: { noteId: string, branchId: string, fromColumn: string, index: number } | null, |     draggedCard: { noteId: string, branchId: string, fromColumn: string, index: number } | null, | ||||||
| @ -115,9 +188,24 @@ function Column({ | |||||||
|     setDropTarget: (target: string | null) => void, |     setDropTarget: (target: string | null) => void, | ||||||
|     dropPosition: { column: string, index: number } | null, |     dropPosition: { column: string, index: number } | null, | ||||||
|     setDropPosition: (position: { column: string, index: number } | null) => void, |     setDropPosition: (position: { column: string, index: number } | null) => void, | ||||||
|     onCardDrop: () => void |     onCardDrop: () => void, | ||||||
|  |     draggedColumn: { column: string, index: number } | null, | ||||||
|  |     setDraggedColumn: (column: { column: string, index: number } | null) => void, | ||||||
|  |     isDraggingColumn: boolean | ||||||
| }) { | }) { | ||||||
|  |     const handleColumnDragStart = useCallback((e: DragEvent) => { | ||||||
|  |         e.dataTransfer!.effectAllowed = 'move'; | ||||||
|  |         e.dataTransfer!.setData('text/plain', column); | ||||||
|  |         setDraggedColumn({ column, index: columnIndex }); | ||||||
|  |         e.stopPropagation(); // Prevent card drag from interfering
 | ||||||
|  |     }, [column, columnIndex, setDraggedColumn]); | ||||||
|  | 
 | ||||||
|  |     const handleColumnDragEnd = useCallback(() => { | ||||||
|  |         setDraggedColumn(null); | ||||||
|  |     }, [setDraggedColumn]); | ||||||
|  | 
 | ||||||
|     const handleDragOver = useCallback((e: DragEvent) => { |     const handleDragOver = useCallback((e: DragEvent) => { | ||||||
|  |         if (draggedColumn) return; // Don't handle card drops when dragging columns
 | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         setDropTarget(column); |         setDropTarget(column); | ||||||
| 
 | 
 | ||||||
| @ -151,6 +239,7 @@ function Column({ | |||||||
|     }, [setDropTarget, setDropPosition]); |     }, [setDropTarget, setDropPosition]); | ||||||
| 
 | 
 | ||||||
|     const handleDrop = useCallback(async (e: DragEvent) => { |     const handleDrop = useCallback(async (e: DragEvent) => { | ||||||
|  |         if (draggedColumn) return; // Don't handle card drops when dragging columns
 | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         setDropTarget(null); |         setDropTarget(null); | ||||||
|         setDropPosition(null); |         setDropPosition(null); | ||||||
| @ -189,15 +278,20 @@ function Column({ | |||||||
|             onCardDrop(); |             onCardDrop(); | ||||||
|         } |         } | ||||||
|         setDraggedCard(null); |         setDraggedCard(null); | ||||||
|     }, [draggedCard, dropPosition, columnItems, column, statusAttribute, setDraggedCard, setDropTarget, setDropPosition, onCardDrop]); |     }, [draggedCard, draggedColumn, dropPosition, columnItems, column, statusAttribute, setDraggedCard, setDropTarget, setDropPosition, onCardDrop]); | ||||||
|  | 
 | ||||||
|     return ( |     return ( | ||||||
|         <div |         <div | ||||||
|             className={`board-column ${dropTarget === column && draggedCard?.fromColumn !== column ? 'drag-over' : ''}`} |             className={`board-column ${dropTarget === column && draggedCard?.fromColumn !== column ? 'drag-over' : ''} ${isDraggingColumn ? 'column-dragging' : ''}`} | ||||||
|             onDragOver={handleDragOver} |             onDragOver={handleDragOver} | ||||||
|             onDragLeave={handleDragLeave} |             onDragLeave={handleDragLeave} | ||||||
|             onDrop={handleDrop} |             onDrop={handleDrop} | ||||||
|         > |         > | ||||||
|             <h3> |             <h3 | ||||||
|  |                 draggable="true" | ||||||
|  |                 onDragStart={handleColumnDragStart} | ||||||
|  |                 onDragEnd={handleColumnDragEnd} | ||||||
|  |             > | ||||||
|                 <span>{column}</span> |                 <span>{column}</span> | ||||||
|                 <span |                 <span | ||||||
|                     className="edit-icon icon bx bx-edit-alt" |                     className="edit-icon icon bx bx-edit-alt" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran