@webority/theme 0.7.3 → 0.7.5
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/README.md +108 -6
- package/dist/webority-theme.css +1 -1
- package/package.json +1 -1
- package/scss/_components.scss +158 -547
- package/scss/_marketing.scss +337 -0
- package/scss/_tokens.scss +119 -108
- package/scss/_variables.scss +126 -132
- package/scss/_wui-aliases.scss +103 -102
- package/scss/wui/_choice.scss +4 -4
- package/scss/wui/_controls.scss +167 -251
- package/scss/wui/_data.scss +39 -0
- package/scss/wui/_display.scss +88 -0
- package/scss/wui/_navigation.scss +27 -0
- package/scss/wui/_overlays.scss +2 -2
- package/scss/wui/_scrollbar.scss +13 -11
- package/scss/wui/_shell.scss +3 -3
- package/scss/wui/_utilities.scss +139 -1
package/scss/wui/_data.scss
CHANGED
|
@@ -202,6 +202,45 @@
|
|
|
202
202
|
text-align: right;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// Row expansion (renderExpanded) — a narrow leading toggle column, a chevron that rotates when
|
|
206
|
+
// open, and a full-width detail row beneath the expanded row.
|
|
207
|
+
.table-ledger .wui-expand-cell,
|
|
208
|
+
.table-ledger thead th.wui-expand-cell {
|
|
209
|
+
width: 40px;
|
|
210
|
+
padding: 0 4px 0 12px;
|
|
211
|
+
text-align: center;
|
|
212
|
+
}
|
|
213
|
+
.wui-expand-toggle {
|
|
214
|
+
display: inline-flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: center;
|
|
217
|
+
width: 28px;
|
|
218
|
+
height: 28px;
|
|
219
|
+
padding: 0;
|
|
220
|
+
border: none;
|
|
221
|
+
border-radius: var(--radius-sm, 6px);
|
|
222
|
+
background: transparent;
|
|
223
|
+
color: var(--color-text-subtle);
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
transition:
|
|
226
|
+
background-color 0.12s,
|
|
227
|
+
color 0.12s;
|
|
228
|
+
}
|
|
229
|
+
.wui-expand-toggle:hover {
|
|
230
|
+
background: var(--color-bg-muted);
|
|
231
|
+
color: var(--color-text);
|
|
232
|
+
}
|
|
233
|
+
.wui-expand-toggle .bi {
|
|
234
|
+
transition: transform 0.18s var(--wui-ease-out-quart, ease);
|
|
235
|
+
}
|
|
236
|
+
.wui-expand-toggle.is-open .bi {
|
|
237
|
+
transform: rotate(180deg);
|
|
238
|
+
}
|
|
239
|
+
.table-ledger tr.wui-row-expanded > td {
|
|
240
|
+
padding: 0 20px 16px;
|
|
241
|
+
background: var(--color-bg-muted);
|
|
242
|
+
}
|
|
243
|
+
|
|
205
244
|
// Ledger chrome — the shared table look. Applies to every .table-ledger: a
|
|
206
245
|
// floating 42px header band, airy rows on a hairline rule, and an inset from
|
|
207
246
|
// the card edge. Column geometry is NOT set here.
|
package/scss/wui/_display.scss
CHANGED
|
@@ -28,6 +28,33 @@
|
|
|
28
28
|
background: var(--color-primary-soft);
|
|
29
29
|
color: var(--color-primary);
|
|
30
30
|
}
|
|
31
|
+
// Tone modifiers — same semantic vocabulary as .badge/.status-label (success / warning /
|
|
32
|
+
// danger / info / primary / neutral). primary is the default look above, restated here so
|
|
33
|
+
// an explicit icon-tone="primary" matches an omitted one.
|
|
34
|
+
.kpi-icon-primary {
|
|
35
|
+
background: var(--color-primary-soft);
|
|
36
|
+
color: var(--color-primary);
|
|
37
|
+
}
|
|
38
|
+
.kpi-icon-success {
|
|
39
|
+
background: var(--color-success-soft);
|
|
40
|
+
color: var(--color-success-text);
|
|
41
|
+
}
|
|
42
|
+
.kpi-icon-warning {
|
|
43
|
+
background: var(--color-warning-soft);
|
|
44
|
+
color: var(--color-warning-text);
|
|
45
|
+
}
|
|
46
|
+
.kpi-icon-danger {
|
|
47
|
+
background: var(--color-danger-soft);
|
|
48
|
+
color: var(--color-danger-text);
|
|
49
|
+
}
|
|
50
|
+
.kpi-icon-info {
|
|
51
|
+
background: var(--color-info-soft);
|
|
52
|
+
color: var(--color-info-text);
|
|
53
|
+
}
|
|
54
|
+
.kpi-icon-neutral {
|
|
55
|
+
background: var(--color-bg-muted);
|
|
56
|
+
color: var(--color-text-muted);
|
|
57
|
+
}
|
|
31
58
|
.kpi-label {
|
|
32
59
|
font-size: 13px;
|
|
33
60
|
font-weight: 500;
|
|
@@ -61,6 +88,20 @@
|
|
|
61
88
|
.kpi-delta.down {
|
|
62
89
|
color: var(--color-danger-text);
|
|
63
90
|
}
|
|
91
|
+
// Trend chart. currentColor so it inherits kpi-value's colour by default, or a wrapping
|
|
92
|
+
// tone context (e.g. .kpi-delta.up) if placed there — no colour hardcoded here.
|
|
93
|
+
.kpi-sparkline {
|
|
94
|
+
display: block;
|
|
95
|
+
width: 48px;
|
|
96
|
+
height: 16px;
|
|
97
|
+
margin-top: 8px;
|
|
98
|
+
color: var(--color-primary);
|
|
99
|
+
}
|
|
100
|
+
.kpi-sparkline polyline {
|
|
101
|
+
stroke-width: 1.5;
|
|
102
|
+
stroke-linecap: round;
|
|
103
|
+
stroke-linejoin: round;
|
|
104
|
+
}
|
|
64
105
|
|
|
65
106
|
// Icon-left layout: the icon spans the label/value/delta stack instead of sitting above it.
|
|
66
107
|
.kpi.kpi-inline {
|
|
@@ -89,6 +130,48 @@
|
|
|
89
130
|
border-color: transparent;
|
|
90
131
|
background: var(--color-primary-soft);
|
|
91
132
|
}
|
|
133
|
+
// Needs-action state — orthogonal to variant, so it composes with plain/filled/accent
|
|
134
|
+
// rather than replacing the surface.
|
|
135
|
+
.kpi.kpi-attention {
|
|
136
|
+
border-color: var(--color-warning);
|
|
137
|
+
background: var(--color-warning-soft);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Hero size — the single headline stat above a dashboard. Enlarges the value and its
|
|
141
|
+
// chrome; orthogonal to variant/inline/attention, so it composes with all of them.
|
|
142
|
+
.kpi.kpi-lg {
|
|
143
|
+
padding: 20px;
|
|
144
|
+
}
|
|
145
|
+
.kpi.kpi-lg .kpi-label {
|
|
146
|
+
font-size: 14px;
|
|
147
|
+
}
|
|
148
|
+
.kpi.kpi-lg .kpi-value {
|
|
149
|
+
font-size: 40px;
|
|
150
|
+
}
|
|
151
|
+
.kpi.kpi-lg .kpi-icon {
|
|
152
|
+
width: 44px;
|
|
153
|
+
height: 44px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// The whole tile as a link (href). Colour/underline reset so the anchor reads as the
|
|
157
|
+
// card, not as text; the hover lift matches .res-card's tint-and-lift treatment.
|
|
158
|
+
a.kpi {
|
|
159
|
+
text-decoration: none;
|
|
160
|
+
color: inherit;
|
|
161
|
+
transition:
|
|
162
|
+
border-color 0.15s ease,
|
|
163
|
+
box-shadow 0.15s ease,
|
|
164
|
+
transform 0.15s ease;
|
|
165
|
+
}
|
|
166
|
+
a.kpi:hover {
|
|
167
|
+
border-color: var(--color-primary);
|
|
168
|
+
box-shadow: var(--shadow-md);
|
|
169
|
+
transform: translateY(-2px);
|
|
170
|
+
}
|
|
171
|
+
a.kpi:focus-visible {
|
|
172
|
+
outline: 2px solid var(--color-primary);
|
|
173
|
+
outline-offset: 2px;
|
|
174
|
+
}
|
|
92
175
|
|
|
93
176
|
// A row of tiles. Wraps rather than scrolls — a KPI strip that scrolls hides numbers.
|
|
94
177
|
.kpi-row {
|
|
@@ -163,6 +246,11 @@
|
|
|
163
246
|
text-overflow: ellipsis;
|
|
164
247
|
white-space: nowrap;
|
|
165
248
|
}
|
|
249
|
+
// A blank fact reads as a muted "no value", not a broken row.
|
|
250
|
+
.info-value.is-empty {
|
|
251
|
+
font-weight: 400;
|
|
252
|
+
color: var(--color-text-subtle);
|
|
253
|
+
}
|
|
166
254
|
a.info-row,
|
|
167
255
|
a.info-row:hover {
|
|
168
256
|
text-decoration: none;
|
|
@@ -549,3 +549,30 @@
|
|
|
549
549
|
cursor: not-allowed;
|
|
550
550
|
opacity: 0.6;
|
|
551
551
|
}
|
|
552
|
+
|
|
553
|
+
// Breadcrumbs — Bootstrap's .breadcrumb with brand tokens (AppBreadcrumbs / <app-breadcrumbs>).
|
|
554
|
+
// The divider is a CSS ::before glyph, so React (react-bootstrap Breadcrumb) and Razor share it.
|
|
555
|
+
.breadcrumb {
|
|
556
|
+
--bs-breadcrumb-divider: "›";
|
|
557
|
+
--bs-breadcrumb-divider-color: var(--color-text-subtle);
|
|
558
|
+
margin-bottom: 0;
|
|
559
|
+
font-size: 13px;
|
|
560
|
+
}
|
|
561
|
+
.breadcrumb-item a {
|
|
562
|
+
display: inline-flex;
|
|
563
|
+
align-items: center;
|
|
564
|
+
gap: 4px;
|
|
565
|
+
color: var(--color-text-muted);
|
|
566
|
+
text-decoration: none;
|
|
567
|
+
}
|
|
568
|
+
.breadcrumb-item a:hover {
|
|
569
|
+
color: var(--color-primary);
|
|
570
|
+
text-decoration: underline;
|
|
571
|
+
}
|
|
572
|
+
.breadcrumb-item.active {
|
|
573
|
+
display: inline-flex;
|
|
574
|
+
align-items: center;
|
|
575
|
+
gap: 4px;
|
|
576
|
+
color: var(--color-text);
|
|
577
|
+
font-weight: 500;
|
|
578
|
+
}
|
package/scss/wui/_overlays.scss
CHANGED
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
// .modal.
|
|
17
17
|
.modal-backdrop.wui-modal-dim {
|
|
18
18
|
background: rgba(15, 23, 42, 0.45);
|
|
19
|
-
z-index:
|
|
19
|
+
z-index: var(--wui-z-modal-backdrop);
|
|
20
20
|
}
|
|
21
21
|
.modal.wui-modal-shell {
|
|
22
22
|
--bs-modal-bg: transparent;
|
|
23
23
|
align-items: center;
|
|
24
24
|
justify-content: center;
|
|
25
|
-
z-index:
|
|
25
|
+
z-index: var(--wui-z-modal);
|
|
26
26
|
padding: 20px;
|
|
27
27
|
}
|
|
28
28
|
// `display: flex` ONLY while the dialog is actually open.
|
package/scss/wui/_scrollbar.scss
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
// AppScrollbar
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// track on Firefox; the `::-webkit-scrollbar` rules cover Chromium and Safari. The track stays
|
|
5
|
-
// transparent so the thumb reads as a slim overlay rather than filling a grey gutter.
|
|
1
|
+
// AppScrollbar / opt-in internal scrollers — same tokens as the document rail
|
|
2
|
+
// (--wui-scrollbar*). Document chrome lives on html/body only; use this class
|
|
3
|
+
// for panels, drawers, and modal bodies that need a matching thin thumb.
|
|
6
4
|
.wui-scroll {
|
|
7
5
|
overflow: auto;
|
|
8
6
|
scrollbar-width: thin;
|
|
9
|
-
scrollbar-color: var(--wui-
|
|
7
|
+
scrollbar-color: var(--wui-scrollbar) transparent;
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
.wui-scroll::-webkit-scrollbar {
|
|
@@ -19,14 +17,18 @@
|
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
.wui-scroll::-webkit-scrollbar-thumb {
|
|
22
|
-
background-color: var(--wui-
|
|
23
|
-
border-radius:
|
|
24
|
-
// A 2px transparent border clipped to padding-box insets the thumb, so it sits as a slim pill
|
|
25
|
-
// in the middle of the track instead of filling the whole gutter width.
|
|
20
|
+
background-color: var(--wui-scrollbar);
|
|
21
|
+
border-radius: 9999px;
|
|
26
22
|
border: 2px solid transparent;
|
|
27
23
|
background-clip: padding-box;
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
.wui-scroll::-webkit-scrollbar-thumb:hover {
|
|
31
|
-
background-color: var(--wui-
|
|
27
|
+
background-color: var(--wui-scrollbar-hover);
|
|
28
|
+
background-clip: padding-box;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.wui-scroll::-webkit-scrollbar-thumb:active {
|
|
32
|
+
background-color: var(--wui-scrollbar-active);
|
|
33
|
+
background-clip: padding-box;
|
|
32
34
|
}
|
package/scss/wui/_shell.scss
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
inset: 0;
|
|
14
14
|
// Above the app but below a modal's backdrop, so an error dialog raised during
|
|
15
15
|
// boot is never trapped behind it.
|
|
16
|
-
z-index:
|
|
16
|
+
z-index: var(--wui-z-shell);
|
|
17
17
|
display: grid;
|
|
18
18
|
place-items: center;
|
|
19
19
|
padding: 24px;
|
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
top: 0;
|
|
620
620
|
bottom: 0;
|
|
621
621
|
left: 0;
|
|
622
|
-
z-index:
|
|
622
|
+
z-index: var(--wui-z-shell-drawer);
|
|
623
623
|
width: var(--app-sidebar-w);
|
|
624
624
|
padding: 20px 16px;
|
|
625
625
|
transform: translateX(-100%);
|
|
@@ -665,7 +665,7 @@
|
|
|
665
665
|
.app-shell.app-shell.mobile-open .app-scrim {
|
|
666
666
|
position: fixed;
|
|
667
667
|
inset: 0;
|
|
668
|
-
z-index:
|
|
668
|
+
z-index: var(--wui-z-shell-scrim);
|
|
669
669
|
display: block;
|
|
670
670
|
border: 0;
|
|
671
671
|
padding: 0;
|
package/scss/wui/_utilities.scss
CHANGED
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
.infotip-pop.is-portal {
|
|
117
117
|
bottom: auto;
|
|
118
118
|
transform: none;
|
|
119
|
-
z-index:
|
|
119
|
+
z-index: var(--wui-z-menu);
|
|
120
120
|
}
|
|
121
121
|
.infotip-pop.is-portal::after {
|
|
122
122
|
display: none;
|
|
@@ -235,6 +235,144 @@
|
|
|
235
235
|
border: 2px solid var(--color-bg);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
// Reset wrapper for a custom AppDropdown trigger (React `trigger` / Razor <app-dropdown-toggle>).
|
|
239
|
+
// Strips the icon-button chrome so the caller's own node styles itself; keeps the button
|
|
240
|
+
// focusable with a visible focus ring for keyboard a11y.
|
|
241
|
+
.wui-dropdown-trigger {
|
|
242
|
+
display: inline-flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
padding: 0;
|
|
245
|
+
border: none;
|
|
246
|
+
background: transparent;
|
|
247
|
+
color: inherit;
|
|
248
|
+
font: inherit;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
}
|
|
251
|
+
.wui-dropdown-trigger:focus-visible {
|
|
252
|
+
outline: 2px solid var(--color-primary);
|
|
253
|
+
outline-offset: 2px;
|
|
254
|
+
border-radius: var(--radius-sm);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// AppPopover wrapper (React panel styling comes from Bootstrap's .popover; this is only the
|
|
258
|
+
// Razor anchor span carrying the data-bs-* wiring). inline-block so it hugs its trigger and
|
|
259
|
+
// gives Bootstrap a stable anchor box.
|
|
260
|
+
.app-popover {
|
|
261
|
+
display: inline-block;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Page/system-level announcement bar (AppBanner / <app-banner>). Full-width and persistent —
|
|
265
|
+
// distinct from an inline .alert or a transient toast. Tones reuse the shared soft/text ramp.
|
|
266
|
+
.wui-banner {
|
|
267
|
+
display: flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 12px;
|
|
270
|
+
width: 100%;
|
|
271
|
+
padding: 12px 20px;
|
|
272
|
+
font-size: 14px;
|
|
273
|
+
line-height: 1.4;
|
|
274
|
+
}
|
|
275
|
+
.wui-banner-icon {
|
|
276
|
+
flex: none;
|
|
277
|
+
display: inline-flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
}
|
|
280
|
+
.wui-banner-body {
|
|
281
|
+
flex: 1 1 auto;
|
|
282
|
+
min-width: 0;
|
|
283
|
+
}
|
|
284
|
+
.wui-banner-dismiss {
|
|
285
|
+
flex: none;
|
|
286
|
+
display: inline-flex;
|
|
287
|
+
align-items: center;
|
|
288
|
+
justify-content: center;
|
|
289
|
+
padding: 4px;
|
|
290
|
+
border: none;
|
|
291
|
+
background: transparent;
|
|
292
|
+
color: inherit;
|
|
293
|
+
cursor: pointer;
|
|
294
|
+
opacity: 0.7;
|
|
295
|
+
border-radius: var(--radius-sm);
|
|
296
|
+
}
|
|
297
|
+
.wui-banner-dismiss:hover {
|
|
298
|
+
opacity: 1;
|
|
299
|
+
}
|
|
300
|
+
.wui-banner-dismiss:focus-visible {
|
|
301
|
+
outline: 2px solid currentColor;
|
|
302
|
+
outline-offset: 2px;
|
|
303
|
+
}
|
|
304
|
+
.wui-banner-info {
|
|
305
|
+
background: var(--color-info-soft);
|
|
306
|
+
color: var(--color-info-text);
|
|
307
|
+
}
|
|
308
|
+
.wui-banner-success {
|
|
309
|
+
background: var(--color-success-soft);
|
|
310
|
+
color: var(--color-success-text);
|
|
311
|
+
}
|
|
312
|
+
.wui-banner-warning {
|
|
313
|
+
background: var(--color-warning-soft);
|
|
314
|
+
color: var(--color-warning-text);
|
|
315
|
+
}
|
|
316
|
+
.wui-banner-danger {
|
|
317
|
+
background: var(--color-danger-soft);
|
|
318
|
+
color: var(--color-danger-text);
|
|
319
|
+
}
|
|
320
|
+
.wui-banner-neutral {
|
|
321
|
+
background: var(--color-bg-subtle);
|
|
322
|
+
color: var(--color-text);
|
|
323
|
+
border-bottom: 1px solid var(--color-border);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Determinate progress-bar fill tones (AppProgress / AppMeter / <app-progress>) — the fill sits
|
|
327
|
+
// in Bootstrap's .progress track; only the bar colour is brand-toned.
|
|
328
|
+
//
|
|
329
|
+
// success + danger use the DEEPENED -strong fills, not the mid tones: when showLabel is set the
|
|
330
|
+
// bar carries Bootstrap's WHITE label text, and white on the mid --wui-success (#17C653) /
|
|
331
|
+
// --wui-danger (#F8285A) fails AA (2.78:1 / 3.86:1). The -strong fills clear it (both ~5.8:1),
|
|
332
|
+
// the same trick btn-danger uses. info/warning/neutral stay on their mid tones (info/neutral
|
|
333
|
+
// pass with white; warning is not shown with a white label).
|
|
334
|
+
.wui-progress-info {
|
|
335
|
+
background-color: var(--color-info);
|
|
336
|
+
}
|
|
337
|
+
.wui-progress-success {
|
|
338
|
+
background-color: var(--wui-success-strong);
|
|
339
|
+
}
|
|
340
|
+
.wui-progress-warning {
|
|
341
|
+
background-color: var(--color-warning);
|
|
342
|
+
}
|
|
343
|
+
.wui-progress-danger {
|
|
344
|
+
background-color: var(--wui-danger-strong);
|
|
345
|
+
}
|
|
346
|
+
.wui-progress-neutral {
|
|
347
|
+
background-color: var(--color-text-subtle);
|
|
348
|
+
}
|
|
349
|
+
// Thin bar for inline / table use.
|
|
350
|
+
.progress.progress-sm {
|
|
351
|
+
height: 4px;
|
|
352
|
+
}
|
|
353
|
+
// Indeterminate "working…" sweep — a partial segment that travels the track (the bar carries
|
|
354
|
+
// no width style in this mode, so the width + motion come from here).
|
|
355
|
+
.wui-progress-indeterminate {
|
|
356
|
+
width: 40%;
|
|
357
|
+
animation: wui-progress-indeterminate 1.1s ease-in-out infinite;
|
|
358
|
+
}
|
|
359
|
+
@keyframes wui-progress-indeterminate {
|
|
360
|
+
0% {
|
|
361
|
+
margin-left: -40%;
|
|
362
|
+
}
|
|
363
|
+
100% {
|
|
364
|
+
margin-left: 100%;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
@media (prefers-reduced-motion: reduce) {
|
|
368
|
+
// No sweep for reduced-motion users — settle to a static full bar.
|
|
369
|
+
.wui-progress-indeterminate {
|
|
370
|
+
margin-left: 0;
|
|
371
|
+
width: 100%;
|
|
372
|
+
animation: none;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
238
376
|
// ── Spinner / shimmer ──
|
|
239
377
|
.wui-spinner {
|
|
240
378
|
width: 18px;
|