Gallery's design card has no 'drag handle' to reorder within a folder — user wanting to put a design at the top of a folder has to drag it to no particular drop position, no visual indication of where it'll land #278

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

Finding

The Gallery's DesignCard has onDragStart and onDragEnd (per the snippet at line 171), but the drag is for moving to other folders. Within a folder, there's no way to reorder.

grep -n 'onReorderDesigns\|REORDER_DESIGNS' src/pages/Gallery.tsx returns 0. No reorder.

A user with 10 designs in a "Work" folder, sorted by "newest":

  • Wants to put the most-important one at the top
  • Has to manually rename to prefix it with "1_" or change the sort
  • Can't manually reorder

The fix is a drag-to-reorder within the same folder, with a visual drop indicator.

Where

  • DesignCard: src/components/gallery/DesignCard.tsx (drag start)
  • No reorder: grep -rn 'REORDER_DESIGNS' src/ returns 0
  • Sort by 'newest' / 'oldest' / 'name' is the only ordering control

Suggested fix shape

  1. State: add dragOverIndex: number | null to the Gallery's state (the design index being hovered during a drag).

  2. Drag handle: each card has a GripVertical icon (visible on hover) that's the drag source:

<span
  draggable
  onDragStart={(e) => {
    e.dataTransfer.setData('design-id', design.id);
    e.dataTransfer.effectAllowed = 'move';
  }}
  className="opacity-0 group-hover:opacity-100"
>
  <GripVertical size={14} />
</span>
  1. Drop indicator: a horizontal line between cards (a 2px gold line) when the drag is over:
{dragOverIndex === i && (
  <div className="h-0.5 bg-[#E6A948] my-1" />
)}
  1. Drop handler: onReorder(designId, targetIndex) dispatches REORDER_DESIGNS to update the design's position.

The user can drag any card to any position within the folder. The order is persisted to localStorage.

Severity

Low. The user can use the sort controls. Power users with curated folders notice.

Discovered by

Gap analysis (2026-10-02) of gallery card affordances.

  • The folder drag-and-drop reorder (per #235) is the parallel concern for folders.
  • The drag-to-folder flow is in place; the drag-to-reorder is the addition.
  • Figma/Notion have drag-to-reorder on cards; the standard pattern.
## Finding The Gallery's DesignCard has `onDragStart` and `onDragEnd` (per the snippet at line 171), but the drag is for moving to other folders. Within a folder, there's no way to reorder. `grep -n 'onReorderDesigns\|REORDER_DESIGNS' src/pages/Gallery.tsx` returns 0. No reorder. A user with 10 designs in a "Work" folder, sorted by "newest": - Wants to put the most-important one at the top - Has to manually rename to prefix it with "1_" or change the sort - Can't manually reorder The fix is a drag-to-reorder within the same folder, with a visual drop indicator. ## Where - DesignCard: `src/components/gallery/DesignCard.tsx` (drag start) - No reorder: `grep -rn 'REORDER_DESIGNS' src/` returns 0 - Sort by 'newest' / 'oldest' / 'name' is the only ordering control ## Suggested fix shape 1. **State**: add `dragOverIndex: number | null` to the Gallery's state (the design index being hovered during a drag). 2. **Drag handle**: each card has a GripVertical icon (visible on hover) that's the drag source: ```tsx <span draggable onDragStart={(e) => { e.dataTransfer.setData('design-id', design.id); e.dataTransfer.effectAllowed = 'move'; }} className="opacity-0 group-hover:opacity-100" > <GripVertical size={14} /> </span> ``` 3. **Drop indicator**: a horizontal line between cards (a 2px gold line) when the drag is over: ```tsx {dragOverIndex === i && ( <div className="h-0.5 bg-[#E6A948] my-1" /> )} ``` 4. **Drop handler**: `onReorder(designId, targetIndex)` dispatches `REORDER_DESIGNS` to update the design's position. The user can drag any card to any position within the folder. The order is persisted to localStorage. ## Severity Low. The user can use the sort controls. Power users with curated folders notice. ## Discovered by Gap analysis (2026-10-02) of gallery card affordances. ## Related - The folder drag-and-drop reorder (per #235) is the parallel concern for folders. - The drag-to-folder flow is in place; the drag-to-reorder is the addition. - Figma/Notion have drag-to-reorder on cards; the standard pattern.
Mark closed this issue 2026-10-04 14:30:24 +00:00
Author
Owner

Shipped at c05951c on origin/main.

Each design card now exposes a hover-revealed GripVertical handle in its info area that starts a custom-MIME drag (application/x-design-reorder, distinct from the existing text/plain design-to-folder and application/x-folder-id folder-reorder payloads). Dropping on another card lands the dragged card immediately above the drop target; a 2px gold top-edge line on the hovered card shows where the drop will land. Reorder works in both grid and list views.

Order is persisted to localStorage via the existing saveDesigns effect, and a new "custom" SortMode preserves the curated layout across subsequent sort changes (auto-selected after a reorder).

11 new regression tests in src/components/gallery/issue-278-design-reorder.test.tsx cover: handle renders only when wired, the handle sets the reorder MIME (not text/plain), drop on a card fires onReorderDesigns(draggedId, index), drops with the wrong MIME are no-ops, dropping on yourself is a no-op, dragover fires onReorderDragOver, dragover with text/plain does NOT, the drop indicator renders only when dragOverForReorder is true, the handle forwards dragEnd to the parent, and reorder works in both grid and list views. tsc --noEmit, npm run lint, npm run build, and the full gallery test suite (154 tests) all pass.

CI workflow run #261 is queued (status: waiting); self-hosted Forgejo runner appears offline (every recent run is cancelled or waiting). Local gates are green; can re-run CI once the runner is back.

Shipped at c05951c on origin/main. Each design card now exposes a hover-revealed GripVertical handle in its info area that starts a custom-MIME drag (`application/x-design-reorder`, distinct from the existing `text/plain` design-to-folder and `application/x-folder-id` folder-reorder payloads). Dropping on another card lands the dragged card immediately above the drop target; a 2px gold top-edge line on the hovered card shows where the drop will land. Reorder works in both grid and list views. Order is persisted to localStorage via the existing `saveDesigns` effect, and a new `"custom"` SortMode preserves the curated layout across subsequent sort changes (auto-selected after a reorder). 11 new regression tests in `src/components/gallery/issue-278-design-reorder.test.tsx` cover: handle renders only when wired, the handle sets the reorder MIME (not text/plain), drop on a card fires `onReorderDesigns(draggedId, index)`, drops with the wrong MIME are no-ops, dropping on yourself is a no-op, dragover fires `onReorderDragOver`, dragover with text/plain does NOT, the drop indicator renders only when `dragOverForReorder` is true, the handle forwards `dragEnd` to the parent, and reorder works in both grid and list views. `tsc --noEmit`, `npm run lint`, `npm run build`, and the full gallery test suite (154 tests) all pass. CI workflow run #261 is queued (`status: waiting`); self-hosted Forgejo runner appears offline (every recent run is `cancelled` or `waiting`). Local gates are green; can re-run CI once the runner is back.
Sign in to join this conversation.
No description provided.