Three dots, five actions, one highlight — and a delete that asks in its own row.
The prompt14,817 characters
Add the "Menu" 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 Menu, from the source below.
2. Install what it needs: npm i framer-motion 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
--danger
--danger-rgb
--font-ui
--ink
--ink-2
--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.
5. IF YOU CHANGE IT, GO ALL THE WAY. This block is
built for every state its object can really be
in — empty, one, full, refused, undone, pressed
twice, interrupted halfway — and not only the one
the demo opens on. Adapt it and the same standard
holds: work out that list before you write, and
build the whole of it. Never settle for the
minimum that makes the screenshot right. A
component somebody has to come back and finish is
the thing this was written to replace.
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.
--- Menu.tsx ---
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
import { AnimatePresence, motion, useSpring } from "framer-motion";
import { Copy, ExternalLink, Folder, MoreHorizontal, Pencil, Trash2, type LucideIcon } from "lucide-react";
/* ══ Menu ═════════════════════════════════════════════════
A file, its three dots, and the five things you can do to
it — the last of which asks first.
ONE HIGHLIGHT THAT TRAVELS. The pointer and the arrow keys
move the same thumb, one element on a spring placed by
layout arithmetic, so the menu reads as a single control
with five positions rather than five buttons that light
up. The navbar's rule, in a column.
DELETE ASKS IN ITS OWN ROW. The row does not open a dialog;
its label crossfades to the question and the two answers,
and the menu is otherwise untouched. Yes closes the menu
and the file's row becomes "Removed · Undo" with a line
draining over four seconds — the window, drawn. The demo
then puts the file back and opens the menu again, because
the open menu is the picture of this component; in an
application that timer is the line to delete. */
const W = 240;
The rest — the source and its comments — is what the plan opens.