aee8b6179a
Last parity gap from the VanillaJS → Svelte migration (issue #500), frontend-only — the backend endpoints already exist. - Drag-out download: onItemDragStart now also sets the DataTransfer `DownloadURL` type, so dragging a row/selection onto the OS desktop downloads it — a single file directly (GET /api/files/{id}), a folder as a zip (GET /api/folders/{id}/download?format=zip), and a multi-selection as one server-zipped archive via the GET twin GET /api/batch/download (DownloadURL can only point at a GET URL). The zip name is shared with the in-app batch download via a new batchZipName() helper. - Folder drag-drop upload: onDrop now walks dropped directory trees with webkitGetAsEntry/createReader into {file, relativePath} rows and recreates the tree server-side, instead of dropping only a folder's top-level files. The recursive-upload core is extracted into uploadTree() and shared with the folder picker (onUploadFolder), so both paths behave identically. Plain multi-file drops keep the existing flat fast-path. Stacked on #502 (shares onItemDragStart). Frontend gate green (svelte-check 0/0, eslint, stylelint, prettier) + 47 Vitest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>