Gallery has no drag-and-drop design import — only the 'Upload' button (click to open file picker) is available; the workspace dropzone is the only surface that supports drag-and-drop #197

Closed
opened 2026-10-03 23:50:14 +00:00 by Mark · 1 comment
Owner

Finding

src/pages/Gallery.tsx's handleUploadDesign is wired to a hidden file input:

const handleUploadDesign = useCallback(() => {
  fileInputRef.current?.click();
}, []);

grep -n 'onDrop\|onDragOver' src/pages/Gallery.tsx returns 0 hits. The Gallery has no drop zone, no onDrop handler, no drag-over visual.

A user who wants to import a design:

  • Has to click the "Upload" button
  • The native file picker opens
  • They pick the file

The same user, in the Workspace, can drag a file onto the dropzone and it just works. The Gallery's affordance is one step behind.

Where

  • Gallery: src/pages/Gallery.tsx:340-345 (handleUploadDesign)
  • File input: src/pages/Gallery.tsx (the hidden <input type="file">)
  • No drop zone: grep -n 'onDrop\|onDragOver\|onDragEnter' src/pages/Gallery.tsx returns 0 hits
  • Workspace drop zone (reference): src/components/workspace/CanvasArea.tsx (the dropzone surface)

Suggested fix shape

Add a drop zone to the Gallery's main area:

<div
  onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }}
  onDragLeave={() => setIsDragOver(false)}
  onDrop={(e) => {
    e.preventDefault();
    setIsDragOver(false);
    const files = e.dataTransfer?.files;
    if (files) handleFiles(files);
  }}
  style={{
    backgroundColor: isDragOver ? 'rgba(230,169,72,0.05)' : 'transparent',
    border: isDragOver ? '2px dashed #E6A948' : 'none',
  }}
>
  {/* existing gallery grid */}
</div>

The handleFiles helper is the same code that the existing handleFileChange runs. The drop zone wraps the existing grid; the user can drop a file anywhere on the page (not just the empty state).

Visual feedback: when isDragOver, render a translucent overlay with "Drop PES, DST, PNG, JPG, SVG, or BMP to import" text in the center of the page.

Severity

Low. The user can click the button. Power users who drag from the Finder/Explorer notice.

Discovered by

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

  • #148 (closed) — Gallery upload accept list excludes BMP (now includes it per the file input accept= attribute).
  • #186 (open) — Workspace has no clipboard paste. Drag-and-drop is the parallel "paste from elsewhere" affordance.
## Finding `src/pages/Gallery.tsx`'s `handleUploadDesign` is wired to a hidden file input: ```ts const handleUploadDesign = useCallback(() => { fileInputRef.current?.click(); }, []); ``` `grep -n 'onDrop\|onDragOver' src/pages/Gallery.tsx` returns 0 hits. The Gallery has no drop zone, no `onDrop` handler, no drag-over visual. A user who wants to import a design: - Has to click the "Upload" button - The native file picker opens - They pick the file The same user, in the Workspace, can drag a file onto the dropzone and it just works. The Gallery's affordance is one step behind. ## Where - Gallery: `src/pages/Gallery.tsx:340-345` (handleUploadDesign) - File input: `src/pages/Gallery.tsx` (the hidden `<input type="file">`) - No drop zone: `grep -n 'onDrop\|onDragOver\|onDragEnter' src/pages/Gallery.tsx` returns 0 hits - Workspace drop zone (reference): `src/components/workspace/CanvasArea.tsx` (the dropzone surface) ## Suggested fix shape Add a drop zone to the Gallery's main area: ```tsx <div onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }} onDragLeave={() => setIsDragOver(false)} onDrop={(e) => { e.preventDefault(); setIsDragOver(false); const files = e.dataTransfer?.files; if (files) handleFiles(files); }} style={{ backgroundColor: isDragOver ? 'rgba(230,169,72,0.05)' : 'transparent', border: isDragOver ? '2px dashed #E6A948' : 'none', }} > {/* existing gallery grid */} </div> ``` The `handleFiles` helper is the same code that the existing `handleFileChange` runs. The drop zone wraps the existing grid; the user can drop a file anywhere on the page (not just the empty state). Visual feedback: when `isDragOver`, render a translucent overlay with "Drop PES, DST, PNG, JPG, SVG, or BMP to import" text in the center of the page. ## Severity Low. The user can click the button. Power users who drag from the Finder/Explorer notice. ## Discovered by Gap analysis (2026-10-02) of gallery upload affordances. ## Related - #148 (closed) — Gallery upload accept list excludes BMP (now includes it per the file input `accept=` attribute). - #186 (open) — Workspace has no clipboard paste. Drag-and-drop is the parallel "paste from elsewhere" affordance.
Author
Owner

Shipped in commit fa581fd on main. Wrapped Section 3 of src/pages/Gallery.tsx in a drop target that mirrors the Workspace dropzone pattern:

  • pageDragOver state + handlePageDragOver / handlePageDragLeave / handlePageDrop handlers
  • Restricts to dataTransfer.types.includes("Files") so card→folder moves (which use text/plain via FolderNav) are unaffected
  • While dragging, an overlay shows the supported format list (PES, DST, PNG, JPG, SVG, or BMP) over the grid
  • Dropped files route through a new importFiles(files: FileList) callback shared with handleFileChange — single import pipeline, no duplicated logic
  • handleFileChange now guards on e.target.files being non-null per the React FileList | null type

Type-check passes, push landed. Closing.

Shipped in commit fa581fd on `main`. Wrapped Section 3 of `src/pages/Gallery.tsx` in a drop target that mirrors the Workspace dropzone pattern: - `pageDragOver` state + `handlePageDragOver` / `handlePageDragLeave` / `handlePageDrop` handlers - Restricts to `dataTransfer.types.includes("Files")` so card→folder moves (which use `text/plain` via FolderNav) are unaffected - While dragging, an overlay shows the supported format list (`PES, DST, PNG, JPG, SVG, or BMP`) over the grid - Dropped files route through a new `importFiles(files: FileList)` callback shared with `handleFileChange` — single import pipeline, no duplicated logic - `handleFileChange` now guards on `e.target.files` being non-null per the React `FileList | null` type Type-check passes, push landed. Closing.
Mark closed this issue 2026-10-04 01:10:39 +00:00
Sign in to join this conversation.
No description provided.