mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 18:49:00 +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;
|
||||
const viewStorage = new ViewModeStorage<T>(note, viewType);
|
||||
viewStorage.restore().then(config => {
|
||||
const storeFn = (config: T) => viewStorage.store(config);
|
||||
const storeFn = (config: T) => {
|
||||
setViewConfig([ config, storeFn ]);
|
||||
viewStorage.store(config);
|
||||
};
|
||||
setViewConfig([ config, storeFn ]);
|
||||
});
|
||||
}, [ note, viewType ]);
|
||||
|
||||
@ -66,9 +66,10 @@
|
||||
}
|
||||
|
||||
.board-view-container .board-column.column-dragging {
|
||||
opacity: 0.6;
|
||||
transform: scale(0.98);
|
||||
opacity: 0.5;
|
||||
transform: scale(0.98) rotate(2deg);
|
||||
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 {
|
||||
@ -185,20 +186,19 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.column-drop-indicator {
|
||||
width: 4px;
|
||||
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);
|
||||
.column-drop-placeholder {
|
||||
width: 250px;
|
||||
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 {
|
||||
opacity: 1;
|
||||
.column-drop-placeholder.show {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.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 [ 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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user