@fragment-build/ui 3.3.0 → 4.0.1
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/components/code-snippet/CodeSnippet.d.ts +9 -0
- package/components/code-snippet/CodeSnippet.js +14 -4
- package/components/code-snippet/CodeSnippet.js.map +1 -1
- package/components/code-snippet/code-snippet.css +18 -0
- package/components/segmented-control/SegmentedControl.d.ts +16 -0
- package/components/segmented-control/SegmentedControl.js +18 -0
- package/components/segmented-control/SegmentedControl.js.map +1 -0
- package/components/segmented-control/SegmentedControl.styles.d.ts +46 -0
- package/components/segmented-control/SegmentedControl.styles.js +20 -0
- package/components/segmented-control/SegmentedControl.styles.js.map +1 -0
- package/components/segmented-control/segmented-control.css +41 -0
- package/fragments/empty-state/EmptyState.d.ts +12 -0
- package/fragments/empty-state/EmptyState.js +12 -0
- package/fragments/empty-state/EmptyState.js.map +1 -0
- package/fragments/empty-state/EmptyState.styles.d.ts +55 -0
- package/fragments/empty-state/EmptyState.styles.js +23 -0
- package/fragments/empty-state/EmptyState.styles.js.map +1 -0
- package/fragments/empty-state/empty-state.css +39 -0
- package/fragments/form/FormCard.d.ts +14 -0
- package/fragments/form/FormCard.js +14 -0
- package/fragments/form/FormCard.js.map +1 -0
- package/fragments/form/FormCard.styles.d.ts +49 -0
- package/fragments/form/FormCard.styles.js +23 -0
- package/fragments/form/FormCard.styles.js.map +1 -0
- package/fragments/form/FormSection.d.ts +3 -1
- package/fragments/form/FormSection.js +2 -2
- package/fragments/form/FormSection.js.map +1 -1
- package/fragments/form/FormSection.styles.d.ts +6 -0
- package/fragments/form/FormSection.styles.js +2 -0
- package/fragments/form/FormSection.styles.js.map +1 -1
- package/fragments/form/form-card.css +42 -0
- package/fragments/form/form-section.css +22 -10
- package/fragments/form/form.css +1 -1
- package/fragments/page/PageHeader.d.ts +7 -2
- package/fragments/page/PageHeader.js +3 -3
- package/fragments/page/PageHeader.js.map +1 -1
- package/fragments/page/PageHeader.styles.d.ts +30 -21
- package/fragments/page/PageHeader.styles.js +10 -0
- package/fragments/page/PageHeader.styles.js.map +1 -1
- package/fragments/page/page-header.css +23 -3
- package/fragments/save-bar/SaveBar.d.ts +12 -0
- package/fragments/save-bar/SaveBar.js +15 -0
- package/fragments/save-bar/SaveBar.js.map +1 -0
- package/fragments/save-bar/SaveBar.styles.d.ts +37 -0
- package/fragments/save-bar/SaveBar.styles.js +16 -0
- package/fragments/save-bar/SaveBar.styles.js.map +1 -0
- package/fragments/save-bar/save-bar.css +28 -0
- package/fragments/shell/shell.css +8 -4
- package/fragments/sidebar/Sidebar.js +4 -1
- package/fragments/sidebar/Sidebar.js.map +1 -1
- package/fragments/sidebar/sidebar.css +48 -24
- package/fragments/stat/StatCard.d.ts +29 -0
- package/fragments/stat/StatCard.js +20 -0
- package/fragments/stat/StatCard.js.map +1 -0
- package/fragments/stat/StatCard.styles.d.ts +85 -0
- package/fragments/stat/StatCard.styles.js +26 -0
- package/fragments/stat/StatCard.styles.js.map +1 -0
- package/fragments/stat/stat-card.css +64 -0
- package/fragments/widget/Widget.d.ts +9 -2
- package/fragments/widget/Widget.js +4 -3
- package/fragments/widget/Widget.js.map +1 -1
- package/fragments/widget/Widget.styles.d.ts +51 -0
- package/fragments/widget/Widget.styles.js +12 -0
- package/fragments/widget/Widget.styles.js.map +1 -1
- package/fragments/widget/widget.css +50 -4
- package/index.css +142 -38
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/code-snippet/code-snippet.css +18 -0
- package/src/components/segmented-control/segmented-control.css +41 -0
- package/src/fragments/empty-state/empty-state.css +39 -0
- package/src/fragments/form/form-card.css +42 -0
- package/src/fragments/form/form-section.css +22 -10
- package/src/fragments/form/form.css +1 -1
- package/src/fragments/page/page-header.css +23 -3
- package/src/fragments/save-bar/save-bar.css +28 -0
- package/src/fragments/shell/shell.css +8 -4
- package/src/fragments/sidebar/sidebar.css +48 -24
- package/src/fragments/stat/stat-card.css +64 -0
- package/src/fragments/widget/widget.css +50 -4
- package/src/index.css +142 -38
|
@@ -5,28 +5,29 @@
|
|
|
5
5
|
|
|
6
6
|
.fragment-sidebar__collapsed {
|
|
7
7
|
@apply fixed top-0 left-0 border-r border-border bg-sidebar text-sidebar-foreground
|
|
8
|
-
flex flex-col h-screen gap-
|
|
8
|
+
flex flex-col h-screen gap-4 transition-all z-40;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.fragment-sidebar__collapsed-body {
|
|
12
|
-
@apply w-
|
|
12
|
+
@apply w-16 items-center flex flex-col gap-6 px-2 pt-5 overflow-y-auto flex-1;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.fragment-sidebar__collapsed-footer {
|
|
16
|
-
@apply w-
|
|
16
|
+
@apply w-16 items-center flex flex-col gap-3 px-2 pb-4;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.fragment-sidebar__expanded {
|
|
20
20
|
@apply fixed top-0 left-0 border-r border-border bg-sidebar text-sidebar-foreground
|
|
21
|
-
flex flex-col h-screen gap-
|
|
21
|
+
flex flex-col h-screen gap-4 overflow-hidden transition-all z-40;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.fragment-sidebar__expanded-body {
|
|
25
|
-
@apply w-
|
|
25
|
+
@apply w-64 flex flex-col gap-6 px-3 pt-5 overflow-y-auto flex-1;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/* The footer is chrome (account, workspace), so it is tucked behind a hairline. */
|
|
28
29
|
.fragment-sidebar__expanded-footer {
|
|
29
|
-
@apply w-
|
|
30
|
+
@apply w-64 flex flex-col gap-2 px-3 pt-3 pb-4 border-t border-border;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
.fragment-sidebar__placeholder {
|
|
@@ -34,11 +35,14 @@
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
.fragment-sidebar__layout-button-wrapper {
|
|
37
|
-
@apply fixed top-6 transition-all;
|
|
38
|
+
@apply fixed top-6 transition-all z-50;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
.fragment-sidebar__layout-button {
|
|
41
|
-
@apply h-6! w-6
|
|
42
|
+
@apply h-6! w-6! min-w-6! bg-surface! border border-border shadow-sm text-muted;
|
|
43
|
+
& svg {
|
|
44
|
+
@apply size-3.5;
|
|
45
|
+
}
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
.fragment-sidebar__bottom-nav {
|
|
@@ -68,8 +72,15 @@
|
|
|
68
72
|
|
|
69
73
|
.fragment-sidebar__collapsed-nav {
|
|
70
74
|
@apply flex flex-col gap-1;
|
|
75
|
+
|
|
76
|
+
/* The active item looks selected the same way at either rail width: the soft fill. */
|
|
77
|
+
.button--primary {
|
|
78
|
+
@apply bg-accent-soft;
|
|
79
|
+
color: var(--sidebar-accent-soft-foreground, var(--accent-soft-foreground));
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
& svg {
|
|
72
|
-
@apply size-
|
|
83
|
+
@apply size-[18px]! shrink-0 self-center;
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
|
|
@@ -106,23 +117,36 @@
|
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
.fragment-sidebar__custom-item {
|
|
109
|
-
@apply px-
|
|
120
|
+
@apply px-1;
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
.fragment-sidebar__nav {
|
|
113
|
-
@apply text-sm;
|
|
124
|
+
@apply text-sm flex flex-col gap-0.5;
|
|
125
|
+
|
|
126
|
+
/* Group label: quiet, so it organises the list without competing with it. */
|
|
127
|
+
& > .header {
|
|
128
|
+
@apply px-3 pb-1 text-xs font-medium text-muted;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.list-box {
|
|
132
|
+
@apply gap-0.5;
|
|
133
|
+
}
|
|
114
134
|
|
|
115
135
|
.list-box-item {
|
|
116
|
-
@apply px-3! pr-1! py-1! h-
|
|
136
|
+
@apply px-3! pr-1! py-1! h-9! gap-3! rounded-lg! font-normal text-sidebar-foreground/80;
|
|
137
|
+
&:hover, &[data-hovered="true"] {
|
|
138
|
+
background-color: var(--sidebar-default, var(--default)) !important;
|
|
139
|
+
@apply text-sidebar-foreground;
|
|
140
|
+
}
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
& svg {
|
|
120
|
-
@apply size-
|
|
144
|
+
@apply size-[18px] shrink-0 self-center;
|
|
121
145
|
}
|
|
122
146
|
}
|
|
123
147
|
|
|
124
148
|
.fragment-sidebar__accordion-trigger {
|
|
125
|
-
@apply w-full flex items-center gap-3 h-
|
|
149
|
+
@apply w-full flex items-center gap-3 h-9 px-3 pr-1 py-1 rounded-lg text-sm font-normal cursor-pointer
|
|
126
150
|
text-sidebar-foreground transition-colors;
|
|
127
151
|
&:hover, &[data-hovered="true"] {
|
|
128
152
|
/* `--default` is a page-level palette colour; opt out per-rail with `--sidebar-default`. */
|
|
@@ -161,7 +185,7 @@
|
|
|
161
185
|
|
|
162
186
|
.fragment-sidebar__nav-item--active {
|
|
163
187
|
/* `--accent-soft` is translucent, so it composites over the rail, not the page. */
|
|
164
|
-
@apply bg-accent-soft!;
|
|
188
|
+
@apply bg-accent-soft! font-medium!;
|
|
165
189
|
color: var(--sidebar-accent-soft-foreground, var(--accent-soft-foreground)) !important;
|
|
166
190
|
}
|
|
167
191
|
|
|
@@ -180,13 +204,13 @@
|
|
|
180
204
|
/* Layout modifier variants */
|
|
181
205
|
.fragment-sidebar--auto {
|
|
182
206
|
.fragment-sidebar__expanded {
|
|
183
|
-
@apply w-
|
|
207
|
+
@apply w-16 opacity-0 pointer-events-none xl:w-64 xl:opacity-100 xl:pointer-events-auto;
|
|
184
208
|
}
|
|
185
209
|
.fragment-sidebar__placeholder {
|
|
186
|
-
@apply w-
|
|
210
|
+
@apply w-16 opacity-0 pointer-events-none xl:w-64 xl:opacity-100 xl:pointer-events-auto;
|
|
187
211
|
}
|
|
188
212
|
.fragment-sidebar__layout-button-wrapper {
|
|
189
|
-
@apply left-
|
|
213
|
+
@apply left-16 translate-x-1/2 rotate-180 xl:left-64 xl:-translate-x-1/2 xl:rotate-0;
|
|
190
214
|
}
|
|
191
215
|
.fragment-sidebar__collapsed {
|
|
192
216
|
@apply xl:opacity-0;
|
|
@@ -195,13 +219,13 @@
|
|
|
195
219
|
|
|
196
220
|
.fragment-sidebar--collapsed {
|
|
197
221
|
.fragment-sidebar__expanded {
|
|
198
|
-
@apply w-
|
|
222
|
+
@apply w-16 opacity-0 pointer-events-none;
|
|
199
223
|
}
|
|
200
224
|
.fragment-sidebar__placeholder {
|
|
201
|
-
@apply w-
|
|
225
|
+
@apply w-16 opacity-0 pointer-events-none;
|
|
202
226
|
}
|
|
203
227
|
.fragment-sidebar__layout-button-wrapper {
|
|
204
|
-
@apply left-
|
|
228
|
+
@apply left-16 translate-x-1/2 rotate-180;
|
|
205
229
|
}
|
|
206
230
|
}
|
|
207
231
|
|
|
@@ -210,13 +234,13 @@
|
|
|
210
234
|
@apply opacity-0;
|
|
211
235
|
}
|
|
212
236
|
.fragment-sidebar__expanded {
|
|
213
|
-
@apply w-
|
|
237
|
+
@apply w-64;
|
|
214
238
|
}
|
|
215
239
|
.fragment-sidebar__placeholder {
|
|
216
|
-
@apply w-
|
|
240
|
+
@apply w-64;
|
|
217
241
|
}
|
|
218
242
|
.fragment-sidebar__layout-button-wrapper {
|
|
219
|
-
@apply left-
|
|
243
|
+
@apply left-64 -translate-x-1/2;
|
|
220
244
|
}
|
|
221
245
|
}
|
|
222
246
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.fragment-stat-card {
|
|
3
|
+
@apply p-4 gap-2 min-w-0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.fragment-stat-card__top {
|
|
7
|
+
@apply flex items-center justify-between gap-2;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.fragment-stat-card__label {
|
|
11
|
+
@apply flex items-center gap-1 text-xs font-medium text-muted min-w-0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.fragment-stat-card__help {
|
|
15
|
+
@apply inline-flex text-muted/70 hover:text-foreground cursor-help rounded-full outline-none
|
|
16
|
+
focus-visible:ring-2 focus-visible:ring-focus;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.fragment-stat-card__icon {
|
|
20
|
+
@apply flex size-8 shrink-0 items-center justify-center rounded-lg bg-default text-muted;
|
|
21
|
+
& svg {
|
|
22
|
+
@apply size-4;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.fragment-stat-card__value-row {
|
|
27
|
+
@apply flex flex-wrap items-baseline gap-x-2 gap-y-1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Proportional figures: a standalone number with tabular digits looks loosely set. */
|
|
31
|
+
.fragment-stat-card__value {
|
|
32
|
+
@apply text-2xl font-semibold tracking-tight text-foreground truncate;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.fragment-stat-card__delta {
|
|
36
|
+
@apply inline-flex items-center gap-0.5 rounded-md px-1.5 py-0.5 text-xs font-medium;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.fragment-stat-card__delta--positive {
|
|
40
|
+
@apply bg-success-soft text-success-soft-foreground;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.fragment-stat-card__delta--negative {
|
|
44
|
+
@apply bg-danger-soft text-danger-soft-foreground;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.fragment-stat-card__delta--neutral {
|
|
48
|
+
@apply bg-default text-muted;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.fragment-stat-card__hint {
|
|
52
|
+
@apply text-xs text-muted;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.fragment-stat-card__skeleton {
|
|
56
|
+
@apply h-8 w-24 rounded-lg;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.fragment-stat-card--emphasis {
|
|
60
|
+
.fragment-stat-card__value {
|
|
61
|
+
@apply text-3xl;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -1,18 +1,60 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.fragment-widget {
|
|
3
|
-
@apply
|
|
3
|
+
@apply p-5 gap-4 min-w-0;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
/* Wraps, so a long title and its controls share the row when they fit and stack when they do not. */
|
|
6
7
|
.fragment-widget__header {
|
|
7
|
-
@apply p-0;
|
|
8
|
+
@apply p-0 flex flex-row flex-wrap items-start gap-3;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.fragment-widget__header-start {
|
|
12
|
+
@apply shrink-0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.fragment-widget__heading {
|
|
16
|
+
@apply min-w-48 flex-1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.fragment-widget__title {
|
|
20
|
+
@apply text-sm font-semibold;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.fragment-widget__description {
|
|
24
|
+
@apply mt-0.5 text-xs text-muted;
|
|
8
25
|
}
|
|
9
26
|
|
|
10
27
|
.fragment-widget__header-end {
|
|
11
|
-
@apply ml-auto;
|
|
28
|
+
@apply ml-auto flex items-center gap-2 shrink-0;
|
|
12
29
|
}
|
|
13
30
|
|
|
14
31
|
.fragment-widget__content {
|
|
15
|
-
@apply p-0 overflow-visible;
|
|
32
|
+
@apply p-0 overflow-visible min-w-0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.fragment-widget__footer {
|
|
36
|
+
@apply -mx-5 -mb-5 mt-auto px-5 py-3 border-t border-separator text-xs text-muted;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.fragment-widget--padding-sm {
|
|
40
|
+
@apply p-4 gap-3;
|
|
41
|
+
|
|
42
|
+
.fragment-widget__footer {
|
|
43
|
+
@apply -mx-4 -mb-4 px-4;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Edge-to-edge content: the header keeps its inset, the body does not. */
|
|
48
|
+
.fragment-widget--flush {
|
|
49
|
+
@apply p-0 gap-0;
|
|
50
|
+
|
|
51
|
+
.fragment-widget__header {
|
|
52
|
+
@apply px-5 pt-5 pb-4;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.fragment-widget__footer {
|
|
56
|
+
@apply mx-0 mb-0;
|
|
57
|
+
}
|
|
16
58
|
}
|
|
17
59
|
|
|
18
60
|
.fragment-widget--sm {
|
|
@@ -26,4 +68,8 @@
|
|
|
26
68
|
.fragment-widget--lg {
|
|
27
69
|
@apply col-span-1 lg:col-span-2 2xl:col-span-3;
|
|
28
70
|
}
|
|
71
|
+
|
|
72
|
+
.fragment-widget--full {
|
|
73
|
+
@apply col-span-full;
|
|
74
|
+
}
|
|
29
75
|
}
|
package/src/index.css
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/*
|
|
2
|
+
* Type scale.
|
|
3
|
+
*
|
|
4
|
+
* Tailwind's own steps (12 / 14 / 16). Fragment used to pin `text-xs` to 13px and `text-sm` to
|
|
5
|
+
* 15px, which made every HeroUI control one step larger than the component library was drawn for
|
|
6
|
+
* and pushed dashboards towards a consumer-app density. Body copy is set to `text-sm` below, which
|
|
7
|
+
* is the size HeroUI's fields, list boxes and tables already use, so running text and controls now
|
|
8
|
+
* share one size.
|
|
9
|
+
*/
|
|
5
10
|
|
|
6
11
|
/*
|
|
7
12
|
* Fragment surface roles.
|
|
@@ -20,39 +25,64 @@
|
|
|
20
25
|
|
|
21
26
|
@layer base {
|
|
22
27
|
body {
|
|
23
|
-
@apply bg-background text-foreground;
|
|
28
|
+
@apply bg-background text-foreground text-sm antialiased;
|
|
24
29
|
}
|
|
25
30
|
|
|
31
|
+
/*
|
|
32
|
+
* Page title, section, card. A dashboard has many more card titles than page titles, so the
|
|
33
|
+
* steps are tight and the weight carries the hierarchy rather than the size.
|
|
34
|
+
*/
|
|
26
35
|
h1 {
|
|
27
|
-
@apply text-
|
|
36
|
+
@apply text-2xl font-semibold tracking-tight;
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
h2 {
|
|
31
|
-
@apply text-
|
|
40
|
+
@apply text-lg font-semibold tracking-tight;
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
h3 {
|
|
35
|
-
@apply text-
|
|
44
|
+
@apply text-base font-semibold;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
h4 {
|
|
48
|
+
@apply text-sm font-semibold;
|
|
36
49
|
}
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
@layer components {
|
|
53
|
+
/*
|
|
54
|
+
* Fields keep HeroUI's own height and padding. They get a hairline border instead of the
|
|
55
|
+
* default shadow, so a form reads as a set of crisp boxes on a flat surface.
|
|
56
|
+
*/
|
|
40
57
|
.input, .textarea, .select__trigger {
|
|
41
|
-
@apply border border-border
|
|
58
|
+
@apply border border-border shadow-none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.input-group, .search-field__group, .number-field__group {
|
|
62
|
+
@apply border border-border shadow-none;
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
/*
|
|
66
|
+
* Text that has to fit, in any language. Single-line controls keep one line and end in an
|
|
67
|
+
* ellipsis when a translation is longer than the room it has: HeroUI breaks a Select's value
|
|
68
|
+
* onto a second line instead ("Alle / Oberflächen"), which grows the trigger out of its row.
|
|
69
|
+
* The trigger may shrink, so the ellipsis — not an overflow — is what absorbs the difference.
|
|
70
|
+
*/
|
|
71
|
+
.select__trigger {
|
|
72
|
+
@apply min-w-0 items-center;
|
|
73
|
+
}
|
|
46
74
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
75
|
+
.select__value {
|
|
76
|
+
@apply min-w-0 truncate;
|
|
77
|
+
overflow-wrap: normal;
|
|
50
78
|
}
|
|
51
79
|
|
|
80
|
+
.chip {
|
|
81
|
+
@apply max-w-full whitespace-nowrap;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* The thumb keeps HeroUI's accent ring: transparent, only a white knob was left, invisible on a white card. */
|
|
52
85
|
.slider {
|
|
53
|
-
.slider__thumb {
|
|
54
|
-
@apply bg-transparent;
|
|
55
|
-
}
|
|
56
86
|
&[data-orientation="horizontal"] {
|
|
57
87
|
.slider__track {
|
|
58
88
|
@apply h-1;
|
|
@@ -65,33 +95,38 @@
|
|
|
65
95
|
}
|
|
66
96
|
}
|
|
67
97
|
|
|
68
|
-
.
|
|
69
|
-
@apply
|
|
98
|
+
.select__popover {
|
|
99
|
+
@apply rounded-xl;
|
|
70
100
|
}
|
|
71
101
|
|
|
72
|
-
|
|
73
|
-
|
|
102
|
+
/*
|
|
103
|
+
* HeroUI sets a modal's body in the muted colour, which suits a one-line confirmation and greys
|
|
104
|
+
* out every heading and label in a dialog that holds a form. Body copy is ink here; a dialog that
|
|
105
|
+
* only says something mutes its own message. The heading gets the weight of a page section.
|
|
106
|
+
*/
|
|
107
|
+
.modal__body {
|
|
108
|
+
@apply text-foreground;
|
|
74
109
|
}
|
|
75
110
|
|
|
76
|
-
.
|
|
77
|
-
@apply
|
|
111
|
+
.modal__heading {
|
|
112
|
+
@apply text-lg font-semibold;
|
|
78
113
|
}
|
|
79
114
|
|
|
80
115
|
.tabs {
|
|
81
116
|
&:not(.tabs--secondary) {
|
|
82
117
|
.tabs__list {
|
|
83
|
-
@apply bg-
|
|
84
|
-
|
|
85
|
-
border-radius: calc(var(--radius-
|
|
118
|
+
@apply bg-default p-1;
|
|
119
|
+
|
|
120
|
+
border-radius: calc(var(--radius-xl) + 0.25rem);
|
|
86
121
|
}
|
|
87
122
|
|
|
88
123
|
.tabs__indicator {
|
|
89
|
-
@apply
|
|
124
|
+
@apply bg-surface shadow-sm;
|
|
90
125
|
}
|
|
91
126
|
|
|
92
127
|
.tabs__tab {
|
|
93
128
|
&[data-selected="true"] {
|
|
94
|
-
@apply text-surface-
|
|
129
|
+
@apply text-surface-foreground;
|
|
95
130
|
}
|
|
96
131
|
}
|
|
97
132
|
|
|
@@ -101,7 +136,7 @@
|
|
|
101
136
|
}
|
|
102
137
|
|
|
103
138
|
.tabs__tab {
|
|
104
|
-
@apply h-
|
|
139
|
+
@apply h-8 px-4 text-sm text-nowrap;
|
|
105
140
|
}
|
|
106
141
|
|
|
107
142
|
.tabs__list {
|
|
@@ -110,25 +145,89 @@
|
|
|
110
145
|
}
|
|
111
146
|
}
|
|
112
147
|
|
|
148
|
+
/* Underline tabs size to their label, so a short list sits left instead of spreading out. */
|
|
113
149
|
&.tabs--secondary {
|
|
150
|
+
.tabs__list[data-orientation="horizontal"] {
|
|
151
|
+
@apply gap-6;
|
|
152
|
+
}
|
|
153
|
+
|
|
114
154
|
.tabs__tab {
|
|
115
|
-
@apply h-
|
|
155
|
+
@apply h-11 w-auto min-w-0 px-0.5 gap-2;
|
|
156
|
+
& svg {
|
|
157
|
+
@apply size-4;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* A static underline for tab lists that render no <Tabs.Indicator>. The animated indicator
|
|
162
|
+
* slides from the previous tab with an inline translate, and when the selection is decided
|
|
163
|
+
* during hydration (a tab read from the URL) its first frame can stick, leaving the line
|
|
164
|
+
* under the wrong tab.
|
|
165
|
+
*/
|
|
166
|
+
&[data-selected="true"]:not(:has(.tabs__indicator))::after {
|
|
167
|
+
content: '';
|
|
168
|
+
@apply absolute inset-x-0 bottom-0 h-0.5 bg-accent;
|
|
169
|
+
}
|
|
116
170
|
}
|
|
117
171
|
}
|
|
118
172
|
}
|
|
119
173
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
174
|
+
/*
|
|
175
|
+
* The primary table as one flat card: a hairline frame, a header band and row dividers, instead
|
|
176
|
+
* of HeroUI's grey frame with a white card inset in it — which on a tinted page reads as a box
|
|
177
|
+
* in a box. Rows get a visible hover, since the default (`surface` at 40%) vanishes on white.
|
|
178
|
+
*/
|
|
179
|
+
.table-root--primary {
|
|
180
|
+
@apply border border-border bg-surface p-0;
|
|
181
|
+
|
|
182
|
+
border-radius: var(--radius-3xl);
|
|
183
|
+
box-shadow: var(--fragment-card-shadow, none);
|
|
123
184
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@apply h-12 px-6;
|
|
185
|
+
.table__column {
|
|
186
|
+
@apply py-2.5 whitespace-nowrap;
|
|
127
187
|
|
|
128
|
-
|
|
129
|
-
|
|
188
|
+
&::after {
|
|
189
|
+
content: none;
|
|
130
190
|
}
|
|
131
191
|
}
|
|
192
|
+
|
|
193
|
+
.table__header {
|
|
194
|
+
@apply border-b border-separator;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.table__body tr td {
|
|
198
|
+
border-radius: 0 !important;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.table__cell {
|
|
202
|
+
@apply border-b border-separator;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.table__body tr:last-child .table__cell {
|
|
206
|
+
@apply border-b-0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.table__row {
|
|
210
|
+
@media (hover: hover) {
|
|
211
|
+
&:hover .table__cell,
|
|
212
|
+
&[data-hovered="true"] .table__cell {
|
|
213
|
+
@apply bg-surface-secondary;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.table__footer {
|
|
219
|
+
@apply border-t border-separator;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/*
|
|
224
|
+
* Cards sit apart from the page by a hairline and an optional, very soft lift. The lift is a
|
|
225
|
+
* token so a theme on a white page (where the border is all there is) can turn it off.
|
|
226
|
+
*/
|
|
227
|
+
.card {
|
|
228
|
+
@apply border border-border;
|
|
229
|
+
|
|
230
|
+
box-shadow: var(--fragment-card-shadow, none);
|
|
132
231
|
}
|
|
133
232
|
}
|
|
134
233
|
|
|
@@ -139,10 +238,15 @@
|
|
|
139
238
|
@import "./fragments/widget/widget.css";
|
|
140
239
|
@import "./components/grid/grid.css";
|
|
141
240
|
@import "./components/multi-switch/multi-switch.css";
|
|
241
|
+
@import "./components/segmented-control/segmented-control.css";
|
|
142
242
|
@import "./components/code/code.css";
|
|
143
243
|
@import "./components/code-snippet/code-snippet.css";
|
|
144
244
|
@import "./fragments/form/form.css";
|
|
145
245
|
@import "./fragments/form/form-section.css";
|
|
246
|
+
@import "./fragments/form/form-card.css";
|
|
247
|
+
@import "./fragments/save-bar/save-bar.css";
|
|
248
|
+
@import "./fragments/stat/stat-card.css";
|
|
249
|
+
@import "./fragments/empty-state/empty-state.css";
|
|
146
250
|
|
|
147
251
|
.light,
|
|
148
252
|
.default,
|