@spree/dashboard-ui 6.0.2 → 6.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +20 -19
- package/src/index.ts +5 -0
- package/src/lib/field-trigger.ts +10 -0
- package/src/lib/same-rich-text.ts +12 -3
- package/src/lib/utils.ts +14 -1
- package/src/spree/address-block.tsx +3 -3
- package/src/spree/address-book-row.tsx +88 -0
- package/src/spree/bulk-price-table.tsx +3 -3
- package/src/spree/claim-resolve-dialog.tsx +1 -1
- package/src/spree/collapsible-card.tsx +2 -2
- package/src/spree/color-picker.tsx +1 -1
- package/src/spree/currency-label.tsx +71 -0
- package/src/spree/data-grid/cells.tsx +2 -2
- package/src/spree/data-grid/data-grid.tsx +2 -2
- package/src/spree/delivery-form-dialog.tsx +1 -1
- package/src/spree/drag-handle.tsx +1 -1
- package/src/spree/editable-note-card.tsx +2 -2
- package/src/spree/form-actions.tsx +32 -10
- package/src/spree/fulfill-items-form.tsx +20 -22
- package/src/spree/fulfillment-edit-dialog.tsx +1 -1
- package/src/spree/fulfillment-item-list.tsx +87 -28
- package/src/spree/fulfillment-panel.tsx +2 -2
- package/src/spree/icons.ts +8 -0
- package/src/spree/json-preview-drawer.tsx +32 -7
- package/src/spree/json-value-view.tsx +14 -4
- package/src/spree/label-upload-dialog.tsx +1 -1
- package/src/spree/language-menu-items.tsx +1 -1
- package/src/spree/metadata/metadata-card.tsx +2 -2
- package/src/spree/order-cancel-dialog.tsx +3 -3
- package/src/spree/post-sale-create-dialogs.tsx +36 -33
- package/src/spree/post-sale-fields.tsx +30 -1
- package/src/spree/product-identity.tsx +74 -0
- package/src/spree/product-membership-list.tsx +79 -41
- package/src/spree/products/status-card.tsx +1 -1
- package/src/spree/quantity-tier-editor.tsx +1 -1
- package/src/spree/return-dialogs.tsx +2 -2
- package/src/spree/search-input.tsx +3 -1
- package/src/spree/secret-input.tsx +1 -1
- package/src/spree/section.tsx +55 -0
- package/src/spree/stat-item.tsx +27 -0
- package/src/spree/tax-identifiers-card.tsx +117 -76
- package/src/spree/theme-toggle.tsx +1 -1
- package/src/spree/wizard.tsx +2 -2
- package/src/styles.css +226 -120
- package/src/ui/alert.tsx +20 -17
- package/src/ui/attachment.tsx +1 -1
- package/src/ui/avatar.tsx +2 -2
- package/src/ui/badge.tsx +1 -1
- package/src/ui/breadcrumb.tsx +1 -1
- package/src/ui/button.tsx +14 -11
- package/src/ui/calendar.tsx +2 -2
- package/src/ui/card.tsx +14 -37
- package/src/ui/chart.tsx +1 -1
- package/src/ui/checkbox.tsx +2 -2
- package/src/ui/code-editor.tsx +6 -2
- package/src/ui/collapsible.tsx +21 -2
- package/src/ui/combobox.tsx +12 -16
- package/src/ui/command.tsx +8 -6
- package/src/ui/context-menu.tsx +1 -1
- package/src/ui/data-table.tsx +58 -15
- package/src/ui/date-picker.tsx +3 -3
- package/src/ui/date-range-panel.tsx +102 -0
- package/src/ui/date-range-picker.tsx +33 -72
- package/src/ui/dialog.tsx +3 -3
- package/src/ui/dropdown-menu.tsx +6 -6
- package/src/ui/empty.tsx +3 -3
- package/src/ui/field.tsx +33 -12
- package/src/ui/input-group.tsx +17 -6
- package/src/ui/input.tsx +148 -4
- package/src/ui/item.tsx +7 -4
- package/src/ui/label.tsx +1 -1
- package/src/ui/media-preview.tsx +40 -5
- package/src/ui/pagination.tsx +16 -4
- package/src/ui/progress.tsx +2 -2
- package/src/ui/radio-group.tsx +2 -2
- package/src/ui/rich-text-editor.tsx +3 -3
- package/src/ui/select.tsx +7 -16
- package/src/ui/sheet.tsx +13 -5
- package/src/ui/sidebar.tsx +5 -5
- package/src/ui/switch.tsx +8 -2
- package/src/ui/tabs.tsx +45 -9
- package/src/ui/textarea.tsx +1 -1
- package/src/ui/toast.tsx +2 -2
- package/src/ui/tooltip.tsx +1 -1
package/src/styles.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
@import "tw-animate-css";
|
|
3
3
|
@import "./shadcn.css";
|
|
4
|
-
@import "@fontsource-variable/
|
|
4
|
+
@import "@fontsource-variable/inter/opsz.css";
|
|
5
5
|
@import "@fontsource-variable/geist-mono";
|
|
6
6
|
|
|
7
7
|
/* Tailwind v4 only scans the consuming project's own source by default.
|
|
@@ -31,38 +31,24 @@
|
|
|
31
31
|
|
|
32
32
|
/* Brand palette.
|
|
33
33
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
34
|
+
* Both themes use Tailwind's `neutral` ramp: a true zero-chroma grey, so the
|
|
35
|
+
* blue accent stays the only thing in the palette that reads as colour, and
|
|
36
|
+
* as interaction.
|
|
36
37
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* looking blue-cold, and leaves the blue accent still the only thing in the
|
|
41
|
-
* palette that reads as interaction.
|
|
42
|
-
*
|
|
43
|
-
* Dark mode is a true zero-chroma grey (Geist's own neutral, and shadcn's
|
|
44
|
-
* default). The warm tint that flatters a white sheet works against a
|
|
45
|
-
* near-black one: at these lightnesses the same chroma stops reading as
|
|
46
|
-
* warmth and starts reading as a brown cast over the whole screen. Keep dark
|
|
47
|
-
* neutrals at chroma 0 — the hue channel there is noise, not decoration.
|
|
48
|
-
*
|
|
49
|
-
* In both themes the lightness decisions below are load-bearing for contrast,
|
|
50
|
-
* and none of them move. Light mode's values are stone's chroma and hue
|
|
51
|
-
* interpolated onto those lightnesses rather than snapped to the nearest ramp
|
|
52
|
-
* step; dark mode's are the same lightnesses with the chroma dropped.
|
|
38
|
+
* The lightness decisions below are load-bearing for contrast, and none of
|
|
39
|
+
* them move. Where a ramp step could not meet a contrast requirement, the
|
|
40
|
+
* value sits between two steps at chroma 0 rather than snapping to one.
|
|
53
41
|
*
|
|
54
42
|
* Primary CTAs stay near-black rather than adopting the site's blue button:
|
|
55
43
|
* in a dense admin UI the blue has to stay meaningful as a selection and
|
|
56
44
|
* focus signal, which it stops being once every page renders a saturated
|
|
57
45
|
* blue button. */
|
|
58
46
|
:root {
|
|
59
|
-
/* Light-mode neutrals are Tailwind's **
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
whichever surface is the odd one out. Dark mode deliberately uses a
|
|
65
|
-
different family — see the note on `.dark`.
|
|
47
|
+
/* Light-mode neutrals are Tailwind's **neutral** scale. Every neutral here
|
|
48
|
+
is either an exact step (labelled with it) or, where a step could not
|
|
49
|
+
meet a contrast requirement, a chroma-0 value between two steps. Never
|
|
50
|
+
mix a tinted ramp (stone, zinc, slate) in: two families read as a colour
|
|
51
|
+
cast on whichever surface is the odd one out.
|
|
66
52
|
|
|
67
53
|
Tokens that must equal another token point at it with var() rather than
|
|
68
54
|
repeating its value, so the two cannot drift. */
|
|
@@ -74,28 +60,28 @@
|
|
|
74
60
|
--link: oklch(0.5106 0.1868 257.7);
|
|
75
61
|
--link-hover: oklch(0.44 0.16 257.7);
|
|
76
62
|
|
|
77
|
-
--background: oklch(98.5% 0
|
|
78
|
-
--foreground: oklch(14.
|
|
63
|
+
--background: oklch(98.5% 0 0); /* neutral-50 — chrome one step below white */
|
|
64
|
+
--foreground: oklch(14.5% 0 0); /* neutral-950 */
|
|
79
65
|
--card: oklch(1 0 0); /* #ffffff — cards and inputs read as raised */
|
|
80
66
|
--card-foreground: var(--foreground);
|
|
81
67
|
--popover: var(--card);
|
|
82
68
|
--popover-foreground: var(--foreground);
|
|
83
|
-
--primary: var(--foreground); /*
|
|
69
|
+
--primary: var(--foreground); /* neutral-950 — near-black primary CTAs */
|
|
84
70
|
--primary-foreground: var(--card);
|
|
85
71
|
/* Filled surfaces (table headers, badges, secondary buttons) read as a
|
|
86
72
|
whisper against the white card rather than a distinct band. */
|
|
87
|
-
--secondary: oklch(97% 0
|
|
73
|
+
--secondary: oklch(97% 0 0); /* neutral-100 */
|
|
88
74
|
--secondary-foreground: var(--foreground);
|
|
89
75
|
--muted: var(--background);
|
|
90
|
-
/* Between
|
|
91
|
-
surface this text lands on
|
|
92
|
-
accent 4.
|
|
93
|
-
|
|
94
|
-
--muted-foreground: oklch(0.
|
|
95
|
-
/* Hover/highlight for menu items and table rows, and the same
|
|
76
|
+
/* Between neutral-500 and -600. Clears 4.5:1 against every
|
|
77
|
+
surface this text lands on, the selected one included: white card 5.65:1,
|
|
78
|
+
sidebar 5.18:1, --accent-strong 4.83:1 (a lighter step measured 4.42:1
|
|
79
|
+
there and failed). */
|
|
80
|
+
--muted-foreground: oklch(0.515 0 0);
|
|
81
|
+
/* Hover/highlight for menu items and table rows, and the same neutral-100 as
|
|
96
82
|
--secondary: a hover and a filled surface are the same weight of "one step
|
|
97
83
|
off the card", so they are one value rather than two that drift apart.
|
|
98
|
-
|
|
84
|
+
neutral-200 was tried and reads as a pressed state on a white surface.
|
|
99
85
|
|
|
100
86
|
It is also the lightest step that keeps --muted-foreground legible on it:
|
|
101
87
|
the previous bespoke grey measured 4.47:1, just under the 4.5 this file
|
|
@@ -109,38 +95,39 @@
|
|
|
109
95
|
--accent cannot do this job. It is the hover/fill surface, so it has to
|
|
110
96
|
stay light enough for --muted-foreground to clear 4.5:1 on it — which
|
|
111
97
|
leaves it at 1.04:1 against the page, invisible as a selection. Two
|
|
112
|
-
different jobs, two tokens.
|
|
113
|
-
|
|
98
|
+
different jobs, two tokens. Muted text and links land on it too (counts
|
|
99
|
+
and hints in a selected row), so --muted-foreground and --link are set
|
|
100
|
+
to clear 4.5:1 here; keep that in mind before darkening it.
|
|
114
101
|
|
|
115
|
-
|
|
116
|
-
--accent-hover
|
|
117
|
-
selection needs to, and
|
|
102
|
+
Between two steps rather than snapped to one (like
|
|
103
|
+
--accent-hover): neutral-200 read heavier than a
|
|
104
|
+
selection needs to, and neutral-100 is --accent itself, which would collapse
|
|
118
105
|
the two tokens into one and leave a hovered item darker than a selected
|
|
119
106
|
one. This sits between them. */
|
|
120
|
-
--accent-strong: oklch(94.7% 0
|
|
107
|
+
--accent-strong: oklch(94.7% 0 0);
|
|
121
108
|
/* Hover, between --accent and --accent-strong so a nav item has somewhere to
|
|
122
109
|
go on hover *and* somewhere further to go when it is the active one.
|
|
123
|
-
|
|
124
|
-
--
|
|
110
|
+
Between two steps rather than snapped — deliberate, like
|
|
111
|
+
--accent-strong.
|
|
125
112
|
|
|
126
113
|
--accent is too light to be a hover here: on the sidebar's ground (the
|
|
127
114
|
page colour, not a card) it measures 1.04:1, which is invisible. */
|
|
128
|
-
--accent-hover: oklch(95.9% 0
|
|
115
|
+
--accent-hover: oklch(95.9% 0 0);
|
|
129
116
|
/* The active item hovered. It darkens rather than lightening: a selected
|
|
130
117
|
row that goes paler under the pointer reads as being deselected. Stays one
|
|
131
118
|
step under --accent-strong, or the two land on the same value and a
|
|
132
119
|
selected item stops responding to the pointer. */
|
|
133
|
-
--accent-strong-hover: oklch(92.
|
|
120
|
+
--accent-strong-hover: oklch(92.2% 0 0); /* neutral-200 */
|
|
134
121
|
--destructive: oklch(0.58 0.22 27); /* red-600 */
|
|
135
122
|
--destructive-foreground: var(--card);
|
|
136
123
|
/* The full-strength rule colour. Nothing styles with it directly — the two
|
|
137
124
|
tokens below are both a share of it, so neither compounds the other's
|
|
138
125
|
reduction.
|
|
139
126
|
|
|
140
|
-
|
|
127
|
+
neutral-200. This is the floor for a hairline: anything lighter stops
|
|
141
128
|
holding a container's edge on a white sheet, and the row rules of a long
|
|
142
129
|
table start to disappear before the frame around them does. */
|
|
143
|
-
--border-base: oklch(92.
|
|
130
|
+
--border-base: oklch(92.2% 0 0); /* neutral-200 */
|
|
144
131
|
/* A structural edge — the content sheet, a dialog, a dropdown, a popover, a
|
|
145
132
|
table's frame. These are surfaces that float above the page or divide it,
|
|
146
133
|
and their edge is what says where one ends and the next begins, so it
|
|
@@ -154,6 +141,10 @@
|
|
|
154
141
|
suggest where the region ends. Used by `CardContent`'s frame; a dialog or
|
|
155
142
|
the sheet itself must keep --border, or the shell loses its outline. */
|
|
156
143
|
--border-card: color-mix(in srgb, var(--border-base) 70%, transparent);
|
|
144
|
+
/* A card's surface: its faint border, and a wide, soft lift under it, so it
|
|
145
|
+
reads as resting on the page rather than only ruled onto it. */
|
|
146
|
+
--card-edge: var(--border-card);
|
|
147
|
+
--card-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.03), 0 4px 16px 0 rgb(0 0 0 / 0.03);
|
|
157
148
|
/* Dividers *inside* a container — card header/footer splits, dialog and
|
|
158
149
|
sheet separators, table row rules.
|
|
159
150
|
|
|
@@ -167,9 +158,7 @@
|
|
|
167
158
|
--border-subtle: color-mix(in srgb, var(--border-base) 50%, transparent);
|
|
168
159
|
/* A mark that has to hold its own against the surface with nothing else
|
|
169
160
|
drawing it — the bar of a scrollbar, the focus ring the skip link draws.
|
|
170
|
-
|
|
171
|
-
3.11:1 on the page ground, the lightest step that clears the minimum on
|
|
172
|
-
both.
|
|
161
|
+
The standard border at 80%, so it follows --border in both themes.
|
|
173
162
|
|
|
174
163
|
No form control uses this. Fields, selects and comboboxes take `--border`
|
|
175
164
|
with `--shadow-control`; checkboxes and radios, too small to carry that
|
|
@@ -179,7 +168,34 @@
|
|
|
179
168
|
`--muted`, so any resting tint either collides with that meaning or (as
|
|
180
169
|
happened) lands darker than it and inverts the signal outright. On this
|
|
181
170
|
palette the enabled state has to stay on the card colour. */
|
|
182
|
-
--border-control:
|
|
171
|
+
--border-control: color-mix(in srgb, var(--border) 80%, transparent);
|
|
172
|
+
/* A field's resting lift (`shadow-control`), and its edge: a neutral-300
|
|
173
|
+
hairline and a soft two-step shadow below it, which together read as a
|
|
174
|
+
box set into the page, its lower edge a touch darker than the rest. The
|
|
175
|
+
dark theme overrides the edge (see there). */
|
|
176
|
+
--field-shadow: 0 1px 2px -1px rgb(0 0 0 / 0.01), 0 3px 4px -1.5px rgb(0 0 0 / 0.03);
|
|
177
|
+
/* Solid rather than a black veil, so the edge keeps one weight over the
|
|
178
|
+
neutral-100 hover instead of darkening. */
|
|
179
|
+
--field-border: oklch(87% 0 0); /* neutral-300 */
|
|
180
|
+
/* A field under the pointer: the outline button's hover, so every control
|
|
181
|
+
answers the pointer the same way. A disabled field is never tinted on
|
|
182
|
+
hover, so the two never meet. */
|
|
183
|
+
--field-hover: var(--accent);
|
|
184
|
+
/* A switch's track when off: a grey dark enough for the white knob to
|
|
185
|
+
stand clear of it. */
|
|
186
|
+
--switch-off: oklch(87% 0 0); /* neutral-300 */
|
|
187
|
+
/* A number field's step buttons, at rest, under the pointer and pressed.
|
|
188
|
+
Rest is one step past the field's own hover fill so the buttons hold
|
|
189
|
+
their shape when the field is hovered. */
|
|
190
|
+
--stepper: oklch(92.2% 0 0); /* neutral-200 */
|
|
191
|
+
--stepper-hover: oklch(87% 0 0); /* neutral-300 */
|
|
192
|
+
--stepper-active: oklch(70.8% 0 0); /* neutral-400 */
|
|
193
|
+
/* A focused field: the blue edge (set on the field's border), a faint halo,
|
|
194
|
+
a soft glow spreading below and a faint one inside, over the field's
|
|
195
|
+
resting shadow. */
|
|
196
|
+
--field-focus-shadow:
|
|
197
|
+
0 0 0 3px rgb(53 115 246 / 0.06), 0 4px 20px 2px rgb(53 115 246 / 0.06),
|
|
198
|
+
inset 0 0 8px 1px rgb(53 115 246 / 0.05), var(--field-shadow);
|
|
183
199
|
/* A card that *holds* other records — an order's fulfillments, its returns,
|
|
184
200
|
its claims — rather than holding content directly.
|
|
185
201
|
|
|
@@ -204,7 +220,7 @@
|
|
|
204
220
|
/* The recessed well a raised thing sits in — a tab strip's track, a
|
|
205
221
|
segmented control. Paired with --nested-raised: the track always sits one
|
|
206
222
|
step under it, which is why the two themes name different tokens rather
|
|
207
|
-
than sharing one. Light steps down from white to
|
|
223
|
+
than sharing one. Light steps down from white to neutral-100. */
|
|
208
224
|
--track-recessed: var(--accent);
|
|
209
225
|
--input: color-mix(in srgb, var(--border-base) 80%, transparent);
|
|
210
226
|
--ring: var(--brand-blue);
|
|
@@ -220,13 +236,18 @@
|
|
|
220
236
|
makes the sheet's rounded edge and shadow read at all: when the two were
|
|
221
237
|
the same colour the inset was invisible. Everything else still points at
|
|
222
238
|
the page token it matches, so the rest cannot drift. */
|
|
223
|
-
--sidebar: oklch(97% 0
|
|
224
|
-
--sidebar-foreground: oklch(26.
|
|
239
|
+
--sidebar: oklch(97% 0 0); /* neutral-100 */
|
|
240
|
+
--sidebar-foreground: oklch(26.9% 0 0); /* neutral-800 */
|
|
225
241
|
--sidebar-primary: var(--primary);
|
|
226
242
|
--sidebar-primary-foreground: var(--primary-foreground);
|
|
227
|
-
--sidebar-accent: oklch(92.
|
|
243
|
+
--sidebar-accent: oklch(92.2% 0 0);
|
|
228
244
|
--sidebar-accent-foreground: var(--accent-foreground);;
|
|
229
245
|
--sidebar-accent-hover: var(--accent-strong);
|
|
246
|
+
/* The current page in the sidebar: one step stronger than --accent-strong,
|
|
247
|
+
which selected rows and tabs share, so where you are reads at a glance.
|
|
248
|
+
Its own pair so those keep theirs (muted text is tuned to --accent-strong). */
|
|
249
|
+
--sidebar-active: oklch(92.2% 0 0); /* neutral-200 */
|
|
250
|
+
--sidebar-active-hover: oklch(90% 0 0);
|
|
230
251
|
/* Matches the rule the top bar draws, so every edge framing the shell —
|
|
231
252
|
the sidebar's, the top bar's, the settings header's — is one weight. */
|
|
232
253
|
--sidebar-border: color-mix(in srgb, var(--border) 75%, transparent);
|
|
@@ -269,32 +290,37 @@
|
|
|
269
290
|
--status-blue-bg: var(--color-sky-100);
|
|
270
291
|
--status-blue-border: var(--color-sky-200);
|
|
271
292
|
--status-blue-fg: var(--color-sky-700);
|
|
293
|
+
|
|
294
|
+
/* A quieter fill for a status surface larger than a badge — an alert, a
|
|
295
|
+
notice. A paragraph of tinted text over the badge's fill reads as a shout;
|
|
296
|
+
one step lighter holds the same hue at a volume a block of copy can
|
|
297
|
+
carry. Text stays on the badge's step. */
|
|
298
|
+
--status-green-surface: var(--color-green-50);
|
|
299
|
+
--status-amber-surface: var(--color-amber-50);
|
|
300
|
+
--status-red-surface: var(--color-red-50);
|
|
301
|
+
--status-blue-surface: var(--color-sky-50);
|
|
272
302
|
}
|
|
273
303
|
|
|
274
304
|
.dark {
|
|
275
|
-
/*
|
|
305
|
+
/* A near-black base, with surfaces stepping up in lightness.
|
|
276
306
|
*
|
|
277
|
-
* Every neutral below is zero-chroma
|
|
278
|
-
*
|
|
279
|
-
* themes split. The lightness ladder is unchanged from the warm version;
|
|
280
|
-
* only the tint was removed.
|
|
307
|
+
* Every neutral below is zero-chroma, like light mode's. See the palette
|
|
308
|
+
* note at the top of this file.
|
|
281
309
|
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
* made the one boundary that was visible — the sidebar's — look like the
|
|
288
|
-
* sheet had been lit. Reference dark dashboards space adjacent surfaces
|
|
289
|
-
* 5-6 points apart for the same reason.
|
|
310
|
+
* A near-black ground (#0a0a0a) with surfaces stepping about 2-3 points of
|
|
311
|
+
* OKLCH lightness, as in the near-black dashboards this follows. A grey
|
|
312
|
+
* ground lifted to 22 read as washed out next to them. Cards share the
|
|
313
|
+
* sheet's colour and are told apart by their faint border; the sheet sits
|
|
314
|
+
* one step above the sidebar.
|
|
290
315
|
*
|
|
291
|
-
* The ladder, ground upward: sidebar
|
|
292
|
-
* / secondary + nested-raised
|
|
293
|
-
* accent-strong
|
|
294
|
-
* surface a merchant actually reads
|
|
295
|
-
|
|
316
|
+
* The ladder, ground upward: sidebar + muted + background 14.5 / card 16.5
|
|
317
|
+
* / secondary + nested-raised 20 / accent 22.5 / accent-hover 25 /
|
|
318
|
+
* accent-strong 29. --card is the anchor, since the inset sheet is the
|
|
319
|
+
* surface a merchant actually reads. Muted text and links have to clear
|
|
320
|
+
* 4.5:1 on --accent-strong, the lightest surface they sit on. */
|
|
321
|
+
--background: oklch(14.5% 0 0);
|
|
296
322
|
--foreground: oklch(95% 0 0);
|
|
297
|
-
--card: oklch(
|
|
323
|
+
--card: oklch(16.5% 0 0);
|
|
298
324
|
--card-foreground: var(--foreground);
|
|
299
325
|
--popover: var(--card);
|
|
300
326
|
--popover-foreground: var(--foreground);
|
|
@@ -307,36 +333,54 @@
|
|
|
307
333
|
at or under the card's lightness erases them — while too big a step reads
|
|
308
334
|
as a bright band across a full-width table header. Dark mode raises where
|
|
309
335
|
light mode lowers, since a surface reads as raised by getting lighter. */
|
|
310
|
-
--secondary: oklch(
|
|
336
|
+
--secondary: oklch(20% 0 0);
|
|
311
337
|
--secondary-foreground: var(--foreground);
|
|
312
|
-
--muted: oklch(
|
|
313
|
-
/*
|
|
314
|
-
(
|
|
315
|
-
|
|
316
|
-
--
|
|
338
|
+
--muted: oklch(14.5% 0 0);
|
|
339
|
+
/* Light enough to clear 4.5:1 on every dark ground, the selected
|
|
340
|
+
--accent-strong included (about 5.7:1). Lower than white-ish greys so
|
|
341
|
+
secondary text stays secondary on the near-black ground. */
|
|
342
|
+
--muted-foreground: oklch(72% 0 0);
|
|
343
|
+
--accent: oklch(22.5% 0 0);
|
|
317
344
|
--accent-foreground: var(--foreground);
|
|
318
|
-
--accent-strong: oklch(
|
|
319
|
-
--accent-hover: oklch(
|
|
320
|
-
--accent-strong-hover: oklch(
|
|
345
|
+
--accent-strong: oklch(29% 0 0);
|
|
346
|
+
--accent-hover: oklch(25% 0 0);
|
|
347
|
+
--accent-strong-hover: oklch(34% 0 0);
|
|
321
348
|
--destructive: oklch(0.704 0.191 22.216);
|
|
322
349
|
/* A white veil over whatever surface it crosses, so one value works on the
|
|
323
350
|
page ground and the raised sheet alike. Both shares below are half of it,
|
|
324
351
|
as in light mode, so a container's edge and the rules inside it are one
|
|
325
352
|
hairline weight. */
|
|
326
|
-
--border-base: oklch(1 0 0 /
|
|
353
|
+
--border-base: oklch(1 0 0 / 10%);
|
|
327
354
|
--border: var(--border-base);
|
|
328
|
-
|
|
355
|
+
/* Full strength here, where light mode takes 70%: cards and the sheet they
|
|
356
|
+
sit on share --card, so in the dark the edge is the only thing that tells
|
|
357
|
+
one card from the next. The base veil is kept faint (about 1.25:1 on the
|
|
358
|
+
card) so that edge outlines a card without drawing a box around it. */
|
|
359
|
+
--border-card: var(--border-base);
|
|
360
|
+
/* A black shadow does nothing on a near-black ground; the border is what
|
|
361
|
+
tells one card from the next here. */
|
|
362
|
+
--card-edge: var(--border-card);
|
|
363
|
+
--card-shadow: none;
|
|
329
364
|
--border-subtle: color-mix(in srgb, var(--border-base) 50%, transparent);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
365
|
+
--border-control: color-mix(in srgb, var(--border) 80%, transparent);
|
|
366
|
+
/* On a dark card a field's edge does the work a shadow does in light mode:
|
|
367
|
+
a black lift barely shows here, and a firmer one read as a smudge. So the
|
|
368
|
+
field border is a step stronger than a card's (16% white against 10%). */
|
|
369
|
+
--field-border: oklch(1 0 0 / 16%);
|
|
370
|
+
--field-hover: var(--accent);
|
|
371
|
+
--switch-off: oklch(1 0 0 / 24%);
|
|
372
|
+
--stepper: oklch(26.9% 0 0); /* neutral-800 */
|
|
373
|
+
--stepper-hover: oklch(37.1% 0 0); /* neutral-700 */
|
|
374
|
+
--stepper-active: oklch(43.9% 0 0); /* neutral-600 */
|
|
375
|
+
/* Light mode's glows vanish on a near-black ground, so the halo and the
|
|
376
|
+
glow below are firmer here. */
|
|
377
|
+
--field-focus-shadow: 0 0 0 3px rgb(53 115 246 / 0.2), 0 4px 20px 2px rgb(53 115 246 / 0.12);
|
|
334
378
|
/* Same arrangement as light — container at the page colour, records raised
|
|
335
|
-
above it
|
|
379
|
+
above it, a 5.5-point step. Records take `--nested-raised` rather
|
|
336
380
|
than `--card`: the card token is a step above the page, which is where the
|
|
337
381
|
container would sit if it had a fill of its own. */
|
|
338
382
|
--card-container: var(--background);
|
|
339
|
-
--nested-raised: oklch(
|
|
383
|
+
--nested-raised: oklch(20% 0 0);
|
|
340
384
|
/* Not --accent here: dark mode's accent is lighter than every raised
|
|
341
385
|
surface, so a shared token would put the selected tab below its own
|
|
342
386
|
track. --muted is the step under --nested-raised. */
|
|
@@ -347,8 +391,8 @@
|
|
|
347
391
|
in dark mode drew a grey halo and lost the one signal that says "this is
|
|
348
392
|
where typing goes". */
|
|
349
393
|
--ring: oklch(0.68 0.19 258);
|
|
350
|
-
--link: oklch(0.
|
|
351
|
-
--link-hover: oklch(0.
|
|
394
|
+
--link: oklch(0.76 0.14 258);
|
|
395
|
+
--link-hover: oklch(0.83 0.12 258);
|
|
352
396
|
--chart-1: oklch(0.809 0.105 251.813);
|
|
353
397
|
--chart-2: oklch(0.623 0.214 259.815);
|
|
354
398
|
--chart-3: oklch(0.546 0.245 262.881);
|
|
@@ -360,21 +404,17 @@
|
|
|
360
404
|
|
|
361
405
|
Measured against --card, not --background: the shell renders the sidebar's
|
|
362
406
|
`inset` variant, so the sheet beside it is the card surface and that
|
|
363
|
-
pairing is what a merchant actually sees.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
was the four surfaces above it sitting within half a point of each other,
|
|
367
|
-
so the sidebar edge was the only visible boundary on the screen and it
|
|
368
|
-
carried the whole contrast budget alone. Widening those steps (see the
|
|
369
|
-
ramp note on --background) fixes it; this stays low so the ground still
|
|
370
|
-
recedes. */
|
|
371
|
-
--sidebar: oklch(14% 0 0);
|
|
407
|
+
pairing is what a merchant actually sees. Two points under it: on a
|
|
408
|
+
near-black ground a wider step makes the sheet read as grey. */
|
|
409
|
+
--sidebar: oklch(14.5% 0 0);
|
|
372
410
|
--sidebar-foreground: var(--foreground);
|
|
373
411
|
--sidebar-primary: var(--primary);
|
|
374
412
|
--sidebar-primary-foreground: var(--primary-foreground);
|
|
375
413
|
--sidebar-accent: var(--accent);
|
|
376
414
|
--sidebar-accent-foreground: var(--accent-foreground);
|
|
377
415
|
--sidebar-accent-hover: var(--accent-hover);
|
|
416
|
+
--sidebar-active: oklch(25% 0 0);
|
|
417
|
+
--sidebar-active-hover: oklch(28% 0 0);
|
|
378
418
|
/* Matches the rule the top bar draws, so every edge framing the shell —
|
|
379
419
|
the sidebar's, the top bar's, the settings header's — is one weight. */
|
|
380
420
|
--sidebar-border: color-mix(in srgb, var(--border) 75%, transparent);
|
|
@@ -406,21 +446,55 @@
|
|
|
406
446
|
--status-blue-bg: var(--color-sky-900);
|
|
407
447
|
--status-blue-border: var(--color-sky-900);
|
|
408
448
|
--status-blue-fg: var(--color-sky-300);
|
|
449
|
+
|
|
450
|
+
/* The 900 step mixed into the card rather than laid over it at an opacity,
|
|
451
|
+
so the surface is one solid colour on any ground. At full strength a 900
|
|
452
|
+
block outweighs everything around it, and step-300 text gains contrast on
|
|
453
|
+
the darker fill. */
|
|
454
|
+
--status-green-surface: color-mix(in oklab, var(--color-green-900) 40%, var(--card));
|
|
455
|
+
--status-amber-surface: color-mix(in oklab, var(--color-amber-900) 40%, var(--card));
|
|
456
|
+
--status-red-surface: color-mix(in oklab, var(--color-red-900) 40%, var(--card));
|
|
457
|
+
--status-blue-surface: color-mix(in oklab, var(--color-sky-900) 40%, var(--card));
|
|
409
458
|
}
|
|
410
459
|
|
|
411
460
|
@theme inline {
|
|
412
|
-
--font-sans: "
|
|
461
|
+
--font-sans: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
|
|
462
|
+
--font-sans--font-feature-settings: "cv11", "ss01";
|
|
413
463
|
--font-mono: "Geist Mono Variable", ui-monospace, monospace;
|
|
414
|
-
|
|
415
|
-
|
|
464
|
+
/* Geist Mono's ligatures merge a space and a following `--` into one glyph,
|
|
465
|
+
hiding the space in command-line flags. */
|
|
466
|
+
--font-mono--font-feature-settings: "liga" 0, "calt" 0;
|
|
467
|
+
|
|
468
|
+
/* Inter at 13px reads thin under grayscale antialiasing, so every step
|
|
469
|
+
sits 50 heavier than the CSS keyword it replaces. */
|
|
470
|
+
--font-weight-normal: 450;
|
|
471
|
+
--font-weight-medium: 550;
|
|
472
|
+
--font-weight-semibold: 650;
|
|
473
|
+
/* Bold keeps a visible step above semibold, now that semibold is 650. */
|
|
474
|
+
--font-weight-bold: 750;
|
|
475
|
+
|
|
476
|
+
/* Typography scale — matches Spree admin (smaller than Tailwind defaults).
|
|
477
|
+
Each size carries its own line height on a 4px grid; left to Tailwind's,
|
|
478
|
+
they kept ratios tuned for its larger sizes and text of one size landed
|
|
479
|
+
on five different line heights. */
|
|
416
480
|
--text-xs: 0.75rem;
|
|
481
|
+
--text-xs--line-height: 1rem;
|
|
482
|
+
/* 13px is the one text size; `text-base` is what components use, and
|
|
483
|
+
`text-sm` is kept equal so older or plugin markup lands on it too. */
|
|
417
484
|
--text-sm: 0.8125rem;
|
|
418
|
-
--text-
|
|
485
|
+
--text-sm--line-height: 1.25rem;
|
|
486
|
+
--text-base: 0.8125rem;
|
|
487
|
+
--text-base--line-height: 1.25rem;
|
|
419
488
|
--text-lg: 1rem;
|
|
489
|
+
--text-lg--line-height: 1.5rem;
|
|
420
490
|
--text-xl: 1.25rem;
|
|
491
|
+
--text-xl--line-height: 1.75rem;
|
|
421
492
|
--text-2xl: 1.5rem;
|
|
493
|
+
--text-2xl--line-height: 2rem;
|
|
422
494
|
--text-3xl: 1.75rem;
|
|
495
|
+
--text-3xl--line-height: 2.25rem;
|
|
423
496
|
--text-4xl: 2rem;
|
|
497
|
+
--text-4xl--line-height: 2.5rem;
|
|
424
498
|
|
|
425
499
|
/* The resting lift on a control that sits ON a surface — a field, a button,
|
|
426
500
|
a card. Measured off a reference: the ground under a field's bottom edge
|
|
@@ -430,7 +504,10 @@
|
|
|
430
504
|
/* A form field's resting lift. Heavier than --shadow-xs and weighted to the
|
|
431
505
|
bottom edge only, so the field reads as a slightly raised well without a
|
|
432
506
|
tinted fill — the fill stays on the card colour (see --border-control). */
|
|
433
|
-
--shadow-control:
|
|
507
|
+
--shadow-control: var(--field-shadow);
|
|
508
|
+
/* Not `--shadow-card`: `--color-card` makes `shadow-card` a shadow colour. */
|
|
509
|
+
--shadow-card-lift: var(--card-shadow);
|
|
510
|
+
--shadow-field-focus: var(--field-focus-shadow);
|
|
434
511
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
435
512
|
--shadow-nav: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.04) 0px 0px 0px 1px, rgba(0, 0, 0, 0.04) 0px 1px 2px -1px, rgba(0, 0, 0, 0.02) 0px 2px 4px 0px;
|
|
436
513
|
|
|
@@ -444,14 +521,15 @@
|
|
|
444
521
|
/* Radius scale, remapped one step rounder than Tailwind's defaults.
|
|
445
522
|
Corner radius is most of what reads as "soft", and remapping the scale
|
|
446
523
|
reaches every `rounded-lg`/`rounded-xl` already written in the components
|
|
447
|
-
— including the `calc(var(--radius-
|
|
524
|
+
— including the `calc(var(--radius-card) - 1px)` a card header derives its
|
|
448
525
|
own corner from, which would drift out of alignment if the components
|
|
449
526
|
were each edited by hand instead. */
|
|
450
527
|
--radius-sm: 0.4rem;
|
|
451
528
|
--radius-md: 0.5rem;
|
|
452
529
|
--radius-lg: 0.625rem;
|
|
453
530
|
--radius-xl: 0.75rem;
|
|
454
|
-
--radius-2xl:
|
|
531
|
+
--radius-2xl: 1.25rem; /* 20px: the shell sheet, dialogs, sheets and toasts */
|
|
532
|
+
--radius-card: 1rem; /* 16px: cards; what a card's inside edge derives from */
|
|
455
533
|
|
|
456
534
|
/* Sidebar + header tokens */
|
|
457
535
|
--spacing-sidebar-width: 240px;
|
|
@@ -497,8 +575,17 @@
|
|
|
497
575
|
--color-input: var(--input);
|
|
498
576
|
--color-border: var(--border);
|
|
499
577
|
--color-border-card: var(--border-card);
|
|
578
|
+
--color-card-edge: var(--card-edge);
|
|
500
579
|
--color-border-subtle: var(--border-subtle);
|
|
501
580
|
--color-border-control: var(--border-control);
|
|
581
|
+
--color-field-border: var(--field-border);
|
|
582
|
+
--color-field-hover: var(--field-hover);
|
|
583
|
+
--color-switch-off: var(--switch-off);
|
|
584
|
+
--color-stepper: var(--stepper);
|
|
585
|
+
--color-stepper-hover: var(--stepper-hover);
|
|
586
|
+
--color-stepper-active: var(--stepper-active);
|
|
587
|
+
--color-sidebar-active: var(--sidebar-active);
|
|
588
|
+
--color-sidebar-active-hover: var(--sidebar-active-hover);
|
|
502
589
|
--color-card-container: var(--card-container);
|
|
503
590
|
--color-nested-raised: var(--nested-raised);
|
|
504
591
|
--color-track-recessed: var(--track-recessed);
|
|
@@ -531,18 +618,22 @@
|
|
|
531
618
|
--color-success: var(--status-green-fg);
|
|
532
619
|
--color-success-bg: var(--status-green-bg);
|
|
533
620
|
--color-success-border: var(--status-green-border);
|
|
621
|
+
--color-success-surface: var(--status-green-surface);
|
|
534
622
|
|
|
535
623
|
--color-warning: var(--status-amber-fg);
|
|
536
624
|
--color-warning-bg: var(--status-amber-bg);
|
|
537
625
|
--color-warning-border: var(--status-amber-border);
|
|
626
|
+
--color-warning-surface: var(--status-amber-surface);
|
|
538
627
|
|
|
539
628
|
--color-danger: var(--status-red-fg);
|
|
540
629
|
--color-danger-bg: var(--status-red-bg);
|
|
541
630
|
--color-danger-border: var(--status-red-border);
|
|
631
|
+
--color-danger-surface: var(--status-red-surface);
|
|
542
632
|
|
|
543
633
|
--color-info: var(--status-blue-fg);
|
|
544
634
|
--color-info-bg: var(--status-blue-bg);
|
|
545
635
|
--color-info-border: var(--status-blue-border);
|
|
636
|
+
--color-info-surface: var(--status-blue-surface);
|
|
546
637
|
|
|
547
638
|
/* Re-point Tailwind's blue ramp at the brand accent. Interactive blue is
|
|
548
639
|
used throughout the component layer for focus borders, checked states and
|
|
@@ -698,12 +789,12 @@
|
|
|
698
789
|
|
|
699
790
|
@layer base {
|
|
700
791
|
:root {
|
|
701
|
-
--scrollbar-thumb: oklch(
|
|
702
|
-
--scrollbar-thumb-hover: oklch(70.
|
|
792
|
+
--scrollbar-thumb: oklch(87% 0 0); /* neutral-300 */
|
|
793
|
+
--scrollbar-thumb-hover: oklch(70.8% 0 0); /* neutral-400 */
|
|
703
794
|
}
|
|
704
795
|
.dark {
|
|
705
|
-
--scrollbar-thumb: oklch(37.
|
|
706
|
-
--scrollbar-thumb-hover: oklch(
|
|
796
|
+
--scrollbar-thumb: oklch(37.1% 0 0); /* neutral-700 */
|
|
797
|
+
--scrollbar-thumb-hover: oklch(43.9% 0 0); /* neutral-600 */
|
|
707
798
|
}
|
|
708
799
|
|
|
709
800
|
/* Themed scrollbar inside floating surfaces only — page scrollbar stays
|
|
@@ -764,7 +855,7 @@
|
|
|
764
855
|
*
|
|
765
856
|
* `pointer: coarse` rather than a width breakpoint: this is about the input
|
|
766
857
|
* method, and a small window on a laptop should keep the compact type. */
|
|
767
|
-
/* Nav rows and menu labels read small on a phone at the desktop
|
|
858
|
+
/* Nav rows and menu labels read small on a phone at the desktop 13px.
|
|
768
859
|
* 16px is the size the platform uses for a primary list row. Sizing is left
|
|
769
860
|
* to the components themselves — buttons carry their own touch targets. */
|
|
770
861
|
@media (pointer: coarse) {
|
|
@@ -842,8 +933,7 @@
|
|
|
842
933
|
}
|
|
843
934
|
|
|
844
935
|
html {
|
|
845
|
-
@apply font-sans antialiased;
|
|
846
|
-
text-rendering: optimizeLegibility;
|
|
936
|
+
@apply font-sans font-normal antialiased;
|
|
847
937
|
/* No `overflow-y: scroll` here. It used to reserve the scrollbar gutter so
|
|
848
938
|
* the page would not jump sideways between a short route and a tall one,
|
|
849
939
|
* back when the document was what scrolled. The inset shell ended that:
|
|
@@ -859,9 +949,11 @@
|
|
|
859
949
|
max-width: 100vw;
|
|
860
950
|
}
|
|
861
951
|
|
|
952
|
+
/* 13px, the one text size: components use `text-base` too, so text that
|
|
953
|
+
sets no size of its own lands on the same size as everything around it.
|
|
954
|
+
`text-xs` (12px) is the only smaller step, for captions and badges. */
|
|
862
955
|
body {
|
|
863
956
|
@apply bg-background text-foreground text-base;
|
|
864
|
-
line-height: 1.5;
|
|
865
957
|
}
|
|
866
958
|
|
|
867
959
|
/* Headings — semibold (600) like Rails admin */
|
|
@@ -871,7 +963,7 @@
|
|
|
871
963
|
h4,
|
|
872
964
|
h5,
|
|
873
965
|
h6 {
|
|
874
|
-
@apply font-semibold
|
|
966
|
+
@apply font-semibold;
|
|
875
967
|
}
|
|
876
968
|
|
|
877
969
|
h1 {
|
|
@@ -895,6 +987,20 @@
|
|
|
895
987
|
}
|
|
896
988
|
|
|
897
989
|
@layer components {
|
|
990
|
+
/* A table that opens its card (the `Card > CardContent p-0 > Table` pattern)
|
|
991
|
+
rounds its header's top corners to the inside of the card's 1px border.
|
|
992
|
+
The header cells carry their own fill, so without this their square
|
|
993
|
+
corners stick out past the card's curve. Tables that manage their own
|
|
994
|
+
corners (`roundedTop`) set the same radius, so the two never disagree. */
|
|
995
|
+
[data-slot='card'] > [data-slot='card-content']:first-child > :first-child thead > tr:first-child {
|
|
996
|
+
& > th:first-child {
|
|
997
|
+
border-top-left-radius: calc(var(--radius-card) - 1px);
|
|
998
|
+
}
|
|
999
|
+
& > th:last-child {
|
|
1000
|
+
border-top-right-radius: calc(var(--radius-card) - 1px);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
898
1004
|
/* Checkerboard for the color picker's "no color selected" swatch.
|
|
899
1005
|
Two-tone diagonal pattern using `--border` + `--background` so it's
|
|
900
1006
|
visible in both light and dark themes. */
|