feat(ui): add a shared native select and a segmented control
Two patterns the app had been rebuilding per call site. NativeSelect: eight `<select>` elements had each been hand-styled, arriving at four different answers — `h-8 rounded border px-1 text-xs`, `h-9 rounded border px-2 text-sm`, `h-9 flex-1 rounded ...`, and one correct `h-9 rounded-md border-input px-2`. Measured, that is two radii (4px against the system's 6px), two border colours (the row hairline against the 3:1 field border) and three text indents against Input's 12px. In the purchase dialog a select sat directly beside the Total input in a visibly different control language. It stays a native select on purpose: the platform picker on a phone and type-to-select on a keyboard are worth more here than a prettier menu, and entry speed is a stated product principle. The chevron is a background image from a new `--budget-select-chevron` token rather than a positioned icon, because that needs no wrapper element — so `className` lands on the select itself and every call site's existing `w-full`, `flex-1`, `h-8` and `w-40` keeps behaving as it did. The token is declared per theme since a background-image stroke cannot be `currentColor`. Segmented: four screens had built the same view switch from two loose buttons, the selected one filled and the other outlined, separated by a gap. That reads as one primary action beside one unrelated button rather than as two states of a single control. One track, no gap, `aria-pressed` per segment. Neither is wired up yet; the call sites follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
da8431a57f
commit
394c5f74df
@@ -55,6 +55,14 @@
|
||||
--surplus: #1f6640; /* carried-forward surplus */
|
||||
--overspend: #a5382a; /* negative balances only */
|
||||
|
||||
/* The chevron a native <select> draws for itself is the OS widget's, not
|
||||
ours, so `appearance: none` removes it and this paints it back. It has to
|
||||
be a data URI in a token rather than an inline SVG in the component: the
|
||||
stroke colour cannot be `currentColor` inside a background-image, so the
|
||||
glyph is re-declared per theme instead. Same path and stroke weight as
|
||||
lucide's chevron-down, which is the icon family the rest of the app uses. */
|
||||
--budget-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23546575' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
||||
|
||||
/* Elevation is light and cool, never a grey drop shadow. */
|
||||
--budget-shadow-card: 0 1px 2px rgb(22 33 43 / 0.04), 0 8px 24px -12px rgb(22 33 43 / 0.12);
|
||||
--budget-shadow-raised: 0 1px 1px rgb(22 33 43 / 0.05), 0 2px 6px -2px rgb(22 33 43 / 0.08);
|
||||
@@ -101,6 +109,9 @@
|
||||
--surplus: #57bb83;
|
||||
--overspend: #f0866a;
|
||||
|
||||
/* Same glyph, lifted to the dark theme's muted ink. */
|
||||
--budget-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a7b8' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
||||
|
||||
/* Dark elevation reads as a lighter surface plus a hairline, not a shadow:
|
||||
shadows are invisible on a dark ground. */
|
||||
--budget-shadow-card: 0 1px 0 rgb(255 255 255 / 0.04) inset, 0 12px 32px -16px rgb(0 0 0 / 0.7);
|
||||
|
||||
Reference in New Issue
Block a user