chore(react/collections/table): set up column dragging

This commit is contained in:
Elian Doran
2025-09-11 18:42:32 +03:00
parent ce0da3fb80
commit c30c9a7360
3 changed files with 131 additions and 34 deletions

View File

@@ -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 [ dropTarget, setDropTarget ] = useState<string | 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() {
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 ]);
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 }) => {
// Check if any changes affect our board
const hasRelevantChanges =
@@ -67,24 +89,70 @@ 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 (
<div className="board-view">
<div className="board-view-container">
{byColumn && columns?.map(column => (
<Column
column={column}
columnItems={byColumn.get(column)}
parentNote={parentNote}
statusAttribute={statusAttribute ?? "status"}
draggedCard={draggedCard}
setDraggedCard={setDraggedCard}
dropTarget={dropTarget}
setDropTarget={setDropTarget}
dropPosition={dropPosition}
setDropPosition={setDropPosition}
onCardDrop={refresh}
/>
<div
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}
columnIndex={index}
columnItems={byColumn.get(column)}
parentNote={parentNote}
statusAttribute={statusAttribute ?? "status"}
draggedCard={draggedCard}
setDraggedCard={setDraggedCard}
dropTarget={dropTarget}
setDropTarget={setDropTarget}
dropPosition={dropPosition}
setDropPosition={setDropPosition}
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} />
</div>
@@ -95,6 +163,7 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC
function Column({
parentNote,
column,
columnIndex,
columnItems,
statusAttribute,
draggedCard,
@@ -103,10 +172,14 @@ function Column({
setDropTarget,
dropPosition,
setDropPosition,
onCardDrop
onCardDrop,
draggedColumn,
setDraggedColumn,
isDraggingColumn
}: {
parentNote: FNote,
column: string,
columnIndex: number,
columnItems?: { note: FNote, branch: FBranch }[],
statusAttribute: string,
draggedCard: { noteId: string, branchId: string, fromColumn: string, index: number } | null,
@@ -115,9 +188,24 @@ function Column({
setDropTarget: (target: string | null) => void,
dropPosition: { column: string, index: number } | null,
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) => {
if (draggedColumn) return; // Don't handle card drops when dragging columns
e.preventDefault();
setDropTarget(column);
@@ -151,6 +239,7 @@ function Column({
}, [setDropTarget, setDropPosition]);
const handleDrop = useCallback(async (e: DragEvent) => {
if (draggedColumn) return; // Don't handle card drops when dragging columns
e.preventDefault();
setDropTarget(null);
setDropPosition(null);
@@ -189,15 +278,20 @@ function Column({
onCardDrop();
}
setDraggedCard(null);
}, [draggedCard, dropPosition, columnItems, column, statusAttribute, setDraggedCard, setDropTarget, setDropPosition, onCardDrop]);
}, [draggedCard, draggedColumn, dropPosition, columnItems, column, statusAttribute, setDraggedCard, setDropTarget, setDropPosition, onCardDrop]);
return (
<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}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<h3>
<h3
draggable="true"
onDragStart={handleColumnDragStart}
onDragEnd={handleColumnDragEnd}
>
<span>{column}</span>
<span
className="edit-icon icon bx bx-edit-alt"