Drag a pane's toolbar onto another pane to swap them
New interaction: click-and-drag any pane's toolbar onto another pane to swap their positions in the tree. The shells / scrollback stay intact (each leaf keeps its data; only the tree slot it occupies changes). Implementation: - tree.ts: `swapLeaves(root, idA, idB)` walks the tree once, substituting one leaf for the other at each occurrence. The leaf objects themselves carry their id/distro/cwd/label/broadcast across, so React preserves the LeafPane instances via the flat-list keying. - orchestration.tsx: add drag lifecycle to the context — dragSourceId / dragOverId (reactive) plus beginHeaderDrag, setHeaderDragOver, endHeaderDrag (stable methods). - App.tsx: implement those methods. endHeaderDrag(true) swaps if source and over are different leaves. - LeafPane.tsx: pointerdown on .pane-toolbar (skipped if the target is a button/input). 5px movement threshold before drag commits to prevent accidental swaps when clicking a chip etc. Pointer-capture the toolbar so we keep getting move events even outside it. Use document.elementFromPoint to find the leaf under the cursor. - CSS: source pane fades to 40% opacity during drag; target pane shows a 3px dashed blue outline; toolbar shows grab/grabbing cursors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c4747546e0
commit
c93ebddfa5
5 changed files with 172 additions and 2 deletions
|
|
@ -356,6 +356,28 @@ export function updateSplitRatio(root: TreeNode, splitId: NodeId, ratio: number)
|
|||
});
|
||||
}
|
||||
|
||||
/** Swap two leaves' tree positions. Each leaf carries its own data
|
||||
* (id, distro, cwd, label, broadcast) into the other's slot. PTYs stay
|
||||
* alive because React keys on leaf.id and our renderer is flat. */
|
||||
export function swapLeaves(root: TreeNode, idA: NodeId, idB: NodeId): TreeNode {
|
||||
if (idA === idB) return root;
|
||||
const a = findLeaf(root, idA);
|
||||
const b = findLeaf(root, idB);
|
||||
if (!a || !b) return root;
|
||||
function walk(n: TreeNode): TreeNode {
|
||||
if (n.kind === "leaf") {
|
||||
if (n.id === idA) return b!;
|
||||
if (n.id === idB) return a!;
|
||||
return n;
|
||||
}
|
||||
const na = walk(n.a);
|
||||
const nb = walk(n.b);
|
||||
if (na === n.a && nb === n.b) return n;
|
||||
return { ...n, a: na, b: nb };
|
||||
}
|
||||
return walk(root);
|
||||
}
|
||||
|
||||
export function serialize(root: TreeNode): string {
|
||||
return JSON.stringify(root);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue