A drop zone that swells for the file, then lists it with a ring that fills.
The prompt26,840 characters
Add the "Upload" component from notboring to my project.
It is licensed for use in my projects — notboring.dev/license. Please:
1. Create the component at a sensible path for this
project, named Upload, from the source below.
2. Install what it needs: npm i lucide-react
3. Add the CSS to the project's stylesheet.
4. THE PART THAT NEEDS YOUR JUDGMENT. The CSS reads
these custom properties and does not define them:
--card
--font-ui
--ink
--ink-3
--ink-4
--ink-rgb
They are notboring's design tokens. Map each one to
whatever this project already uses for the same
job — its own ink, ground, surface and UI font —
rather than defining them as new globals. If the
project has no equivalent, define it locally on
the component's own root so nothing leaks out.
Anything ending -rgb wants three bare numbers,
because the CSS builds rgba() from it.
Keep the comments. They say why the numbers are what
they are, and they are most of what makes this worth
copying rather than rewriting.
--- Upload.tsx ---
import { useCallback, useEffect, useRef, useState } from "react";
import { X } from "lucide-react";
/* ══ Upload ═══════════════════════════════════════════════
A drop zone, and the list it turns into.
THE ZONE SWELLS FOR THE FILE, THEN LISTS IT. The obvious
build is a drop target and, somewhere under it, a table of
uploads that appears once the first file lands — two
things, one of them invisible until it mattered. Here there
is one well. Empty, it is the whole card and says so; hand
it a file and it SHRINKS to a strip at the top, and the
rows take the room it gave up. Its height is one tween, so
the strip arriving and the rows arriving are the same event
seen from both ends.
THE RING BECOMES THE CHECK. A ring that fills and is then
replaced by a tick is a swap, however short the crossfade.
This one fills, and at full its stroke thickens until the
ring is a disc, and the tick is drawn out of that disc in
the card's own color. Two readings of one number, and no
frame in which a row shows two opinions about whether it is
done.
The rest — the source and its comments — is what you are buying.