Posting a dump was a single form where the important choices were the easiest
to miss. It is now three panels: link or file, why & where, playlists.
Composition:
- No more URL/File toggle. An empty panel offers both ways in at once and the
kind follows what you actually did; a file dropped anywhere in the modal is
accepted, not just on the zone.
- Categories and visibility get their own panel instead of a disclosure that
read as optional, and the primary button stays "Next" until they've been
seen. Visibility carries a real label now.
- The draft (link, title, why, categories, visibility) is mirrored to
localStorage on every change and restored on reopen, so Escape or a stray
backdrop click costs nothing. Only an attached file can't be restored, so
that is the one case that asks before closing.
- URL dumps can carry a poster-supplied title instead of being stuck with
whatever the page scraped, editable right under the preview.
- Multipart uploads go through XHR so there is a real progress bar and a
percentage on the button, rather than 50 MB of silence.
Duplicates:
- New dumps.url_canonical column (+ index, backfilled by 0013) holding a lossy
key that ignores scheme, www., trailing slashes, tracking parameters and
YouTube share shapes. GET /api/dumps/by-url reads it, and the create form
warns "already dumped by X" while it fetches the preview. Never blocking.
Fixes:
- /api/preview now reports whether the page was actually reached: a failed
fetch still yields a hostname-only stub, so a dead link and a page without
metadata used to render identically.
- The Web Share Target never worked. The manifest posts to "/", but the index
redirect dropped the query string, so every Android share landed on the feed
with nothing pre-filled.
- File dumps no longer take the extension into their title.
- The link field no longer autofocuses on touch, where it raised a keyboard
over the modal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiAPtJZeCYYk8rKehtLUQU