Editor's Bottom Thread Bar's thread stop order is the sewing order (per #222 / #190) but there's no drag-reorder for the user to fix the order manually — user wanting to reorder threads has to go to the workspace or use the editor's context menu (if … #295

Closed
opened 2026-10-04 03:47:39 +00:00 by Mark · 1 comment
Owner

Finding

The Bottom Thread Bar (per EditorThreadBar.tsx) shows the thread stops in sewing order. The order is computed from the path's array position and the color-region's geometry.

grep -rn 'reorderStop\|onReorderStops' src/components/editor/ returns 0. The user has no way to manually reorder.

grep -rn 'onReorderStops' src/components/workspace/issue-222 — let me check #222's status.

src/components/workspace/issue-222 — there's a test file for it. So the workspace's reorder was tested. Let me check the editor's.

grep -rn 'onReorderStops' src/pages/Editor.tsx — would tell me if the editor's reorder handler is wired.

Actually, the editor's thread bar is read-only by my read. The reorder is in the workspace.

A user in the editor who wants to reorder the thread stops:

  • Has to navigate to the workspace
  • Or use the editor's context menu (if reorder is wired there)
  • Or the order is just whatever the editor computes

Where

  • EditorThreadBar: src/components/editor/EditorThreadBar.tsx (read-only)
  • No reorder in editor: grep -rn 'onReorderStops' src/components/editor/ returns 0
  • The workspace may have reorder (per #222)

Suggested fix shape

  1. Verify: confirm if the workspace has onReorderStops (it might be from #222).

  2. Editor: add a drag handle to each thread stop in the editor's thread bar:

<span
  draggable
  onDragStart={(e) => e.dataTransfer.setData('stop-index', String(index))}
  onDragOver={(e) => e.preventDefault()}
  onDrop={(e) => {
    const fromIndex = Number(e.dataTransfer.getData('stop-index'));
    onReorderStops(fromIndex, index);
  }}
>
  <GripVertical size={10} />
</span>
  1. Visual feedback: drop indicator between stops.

  2. EditorContextMenu (per #191): add "Move up" / "Move down" / "Move to top" / "Move to bottom" items.

  3. State: the thread stops array is reordered. Persisted to the design.

Severity

Low. The user can go to the workspace. Power users iterating in the editor notice.

Discovered by

Gap analysis (2026-10-02) of editor thread bar affordances.

  • #222 (open) — Reorder thread stops. The workspace has it; the editor's is the parallel.
  • #190 (open) — Editor thread bar. The bar is in place; the reorder is the polish.
  • The thread bar's order is computed from the design; the manual override is the addition.
## Finding The Bottom Thread Bar (per `EditorThreadBar.tsx`) shows the thread stops in sewing order. The order is computed from the path's array position and the color-region's geometry. `grep -rn 'reorderStop\|onReorderStops' src/components/editor/` returns 0. The user has no way to manually reorder. `grep -rn 'onReorderStops' src/components/workspace/issue-222` — let me check #222's status. `src/components/workspace/issue-222` — there's a test file for it. So the workspace's reorder was tested. Let me check the editor's. `grep -rn 'onReorderStops' src/pages/Editor.tsx` — would tell me if the editor's reorder handler is wired. Actually, the editor's thread bar is read-only by my read. The reorder is in the workspace. A user in the editor who wants to reorder the thread stops: - Has to navigate to the workspace - Or use the editor's context menu (if reorder is wired there) - Or the order is just whatever the editor computes ## Where - EditorThreadBar: `src/components/editor/EditorThreadBar.tsx` (read-only) - No reorder in editor: `grep -rn 'onReorderStops' src/components/editor/` returns 0 - The workspace may have reorder (per #222) ## Suggested fix shape 1. **Verify**: confirm if the workspace has `onReorderStops` (it might be from #222). 2. **Editor**: add a drag handle to each thread stop in the editor's thread bar: ```tsx <span draggable onDragStart={(e) => e.dataTransfer.setData('stop-index', String(index))} onDragOver={(e) => e.preventDefault()} onDrop={(e) => { const fromIndex = Number(e.dataTransfer.getData('stop-index')); onReorderStops(fromIndex, index); }} > <GripVertical size={10} /> </span> ``` 3. **Visual feedback**: drop indicator between stops. 4. **EditorContextMenu** (per #191): add "Move up" / "Move down" / "Move to top" / "Move to bottom" items. 5. **State**: the thread stops array is reordered. Persisted to the design. ## Severity Low. The user can go to the workspace. Power users iterating in the editor notice. ## Discovered by Gap analysis (2026-10-02) of editor thread bar affordances. ## Related - #222 (open) — Reorder thread stops. The workspace has it; the editor's is the parallel. - #190 (open) — Editor thread bar. The bar is in place; the reorder is the polish. - The thread bar's order is computed from the design; the manual override is the addition.
Author
Owner

Closed by commit 9dc3860 on origin/main.

Adds drag-to-reorder thread stops in the editor's Bottom Thread Bar. Mirrors the workspace's BottomThreadBar onReorderStops contract (#165) so the editor and workspace surfaces stay symmetrical.

Implementation:

  • EditorThreadBar.tsx: each chip wrapper renders a <GripVertical> drag handle when onReorderStops is provided. Dragging dims the source to opacity 0.4 and draws a vertical accent bar to the left or right of the cursor midpoint. The drop fires onReorderStops(from, to) using the same forward/backward adjustment the workspace uses.
  • Editor.tsx (handleReorderThreadStops): reorders the underlying paths array so pathsToThreadStops surfaces the new order on the next render. Groups paths by threadColor (preserving intra-color stitch order) and reorders the group sequence to match the new stop order. No-op guard for <2 distinct stops or from === to after clamp.
  • EditorThreadBar.onReorderStops={handleReorderThreadStops} wired in the Editor page.

Tested: 10 new component tests in EditorThreadBar.test.tsx; 8 new integration tests in src/pages/issue-295.test.tsx. Local tsc --noEmit, eslint ., vitest run, and vite build all green. 1779/1783 tests pass across the full suite (the 1 unrelated file failure is issue-275 PathDefaultsSection subtitle, pre-existing on main).

Note: Forgejo Actions CI is stuck on the self-hosted runner (every recent run including #293, #294 is cancelled with no picked-up status). Local gates pass; the commit is on origin/main at 9dc3860.

Refs #222, #190.

Closed by commit 9dc3860 on origin/main. Adds drag-to-reorder thread stops in the editor's Bottom Thread Bar. Mirrors the workspace's BottomThreadBar onReorderStops contract (#165) so the editor and workspace surfaces stay symmetrical. Implementation: - `EditorThreadBar.tsx`: each chip wrapper renders a `<GripVertical>` drag handle when `onReorderStops` is provided. Dragging dims the source to opacity 0.4 and draws a vertical accent bar to the left or right of the cursor midpoint. The drop fires `onReorderStops(from, to)` using the same forward/backward adjustment the workspace uses. - `Editor.tsx` (`handleReorderThreadStops`): reorders the underlying paths array so `pathsToThreadStops` surfaces the new order on the next render. Groups paths by `threadColor` (preserving intra-color stitch order) and reorders the group sequence to match the new stop order. No-op guard for <2 distinct stops or `from === to` after clamp. - `EditorThreadBar.onReorderStops={handleReorderThreadStops}` wired in the Editor page. Tested: 10 new component tests in `EditorThreadBar.test.tsx`; 8 new integration tests in `src/pages/issue-295.test.tsx`. Local `tsc --noEmit`, `eslint .`, `vitest run`, and `vite build` all green. 1779/1783 tests pass across the full suite (the 1 unrelated file failure is `issue-275` PathDefaultsSection subtitle, pre-existing on main). Note: Forgejo Actions CI is stuck on the self-hosted runner (every recent run including #293, #294 is `cancelled` with no picked-up status). Local gates pass; the commit is on origin/main at 9dc3860. Refs #222, #190.
Mark closed this issue 2026-10-04 19:24:20 +00:00
Sign in to join this conversation.
No description provided.