feat(kanban): drag column title to reorder columns #71

Merged
AhmedHanafy725 merged 3 commits from development_kanban_column_reorder into development 2026-04-23 13:29:32 +00:00
Member

Summary

Kanban columns can now be reordered by dragging the column title. The new order persists across reload and supports undo/redo.

Closes #69

Changes

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/kanban.js
    • renderKanban now stashes group._kbColumnLayout — a per-render array of {x, w, center} per column for dragend slot math.
    • colTitle is marked draggable: true.
    • colTitle.on('dragstart') cancels bubble (so the whole-kanban drag does not also fire), clears card selection, calls WhiteboardHistory.snapshotBefore, does moveToTop, and records the source column index on the group.
    • colTitle.on('dragend') converts pointer to group-local, finds the target slot (with clamping for out-of-bounds drops), splices state.columns, re-renders, commits history, and calls WhiteboardSync.onUpdate. Snap-back / same-slot / single-column drops are no-ops and do not emit sync traffic.

Preserved

  • Double-click the title still renames the column (Konva's dblclick fires when the pointer does not move beyond the drag threshold).
  • Color indicator, × delete button, + Add card, + Column.
  • Card drag-and-drop between/within columns, card selection + Delete key, transformer live-redraw, font scaling.
  • Whole-kanban drag (grab background).

Scope

  • No schema / sync changes: column order is implicit in the state.columns array order and already round-trips.
  • During drag only the colTitle Konva.Text moves with the cursor; column bg, color indicator, ×, + Add card, and cards stay put. Standard "grab the handle" affordance.

Test Results

  • cargo check --workspace: pass
  • cargo clippy --workspace -- -D warnings: pass
  • cargo fmt --check: pass

JS-only change; Rust checks confirm no regression. Manual QA required: reorder by drag, reload, undo/redo, regression-check the preserved interactions.

## Summary Kanban columns can now be reordered by dragging the column title. The new order persists across reload and supports undo/redo. ## Related Issue Closes https://forge.ourworld.tf/lhumina_code/hero_whiteboard/issues/69 ## Changes - `crates/hero_whiteboard_ui/static/web/js/whiteboard/kanban.js` - `renderKanban` now stashes `group._kbColumnLayout` — a per-render array of `{x, w, center}` per column for dragend slot math. - `colTitle` is marked `draggable: true`. - `colTitle.on('dragstart')` cancels bubble (so the whole-kanban drag does not also fire), clears card selection, calls `WhiteboardHistory.snapshotBefore`, does `moveToTop`, and records the source column index on the group. - `colTitle.on('dragend')` converts pointer to group-local, finds the target slot (with clamping for out-of-bounds drops), splices `state.columns`, re-renders, commits history, and calls `WhiteboardSync.onUpdate`. Snap-back / same-slot / single-column drops are no-ops and do not emit sync traffic. ## Preserved - Double-click the title still renames the column (Konva's dblclick fires when the pointer does not move beyond the drag threshold). - Color indicator, `×` delete button, `+ Add card`, `+ Column`. - Card drag-and-drop between/within columns, card selection + Delete key, transformer live-redraw, font scaling. - Whole-kanban drag (grab background). ## Scope - No schema / sync changes: column order is implicit in the `state.columns` array order and already round-trips. - During drag only the `colTitle` Konva.Text moves with the cursor; column bg, color indicator, `×`, `+ Add card`, and cards stay put. Standard "grab the handle" affordance. ## Test Results - `cargo check --workspace`: pass - `cargo clippy --workspace -- -D warnings`: pass - `cargo fmt --check`: pass JS-only change; Rust checks confirm no regression. Manual QA required: reorder by drag, reload, undo/redo, regression-check the preserved interactions.
feat(kanban): drag column title to reorder columns
All checks were successful
CI / build (pull_request) Successful in 2m17s
8727eb76ea
Capture per-column horizontal bounds on the group each render, mark
colTitle as draggable, and wire dragstart/dragend handlers. The
dragstart cancels bubble (preventing the whole-kanban drag from also
firing), snapshots history, moves the title to the top, and records
the source index. The dragend converts the pointer to group-local
coordinates, finds the target column via the stored layout, splices
state.columns, re-renders, and calls WhiteboardSync.onUpdate. Snap
back, single-column, and same-slot drops are no-ops and do not emit
sync traffic.

Column order is already the array order of state.columns and already
round-trips through the existing serializer, so no schema or sync
changes are required.

#69
feat(kanban): drag whole column as a unit during reorder
All checks were successful
CI / build (pull_request) Successful in 3m13s
f50e7cd694
Wrap each column's children in a per-column colGroup and make that the
draggable unit, mirroring the per-card cardGroup introduced for card
drag. Header, cards, indicator, delete button, and +Add card button
now all move with the cursor during a reorder instead of just the
title text.

Target-slot detection in dragend switched from range inclusion to
closest-center matching, so dropping in the padding gap between two
columns lands on the nearer slot instead of clamping to the far end.

cardGroup.dragstart now reparents the dragged card to the kanban group
(preserving its absolute position) so cross-column card drags render
above all columns. renderKanban on dragend destroys and rebuilds,
so no explicit cleanup is needed.
fix(kanban): allow reorder past the last column and tighten drop threshold
All checks were successful
CI / build (pull_request) Successful in 2m15s
1dc3f97e48
The prior dragend logic picked the closest of the N existing column
centers, so there was no way to signal "past the last column" and a
middle column could never become the new rightmost. It also required
dragging roughly a full column width before any swap, which read as
"sometimes it doesn't move".

Replace with a body-overlap check: whenever the dragged column's
center falls inside another column's body (extended by half the
inter-column padding so the gap never eats the drop), that column
becomes the pivot — swap with it if it is to the source's side, or
insert after it if the drag went the other way. Drops past the last
column's right edge or before the first column's left edge map to
the "past end" / "before start" slots. No-op detection stays
(targetSlot equal to srcIdx or srcIdx+1). Reorder threshold is now
roughly half a column width, which matches the visual cue.
AhmedHanafy725 merged commit dc7d1b92bd into development 2026-04-23 13:29:32 +00:00
AhmedHanafy725 deleted branch development_kanban_column_reorder 2026-04-23 13:29:36 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard!71
No description provided.