@webority/theme 0.7.4 → 0.7.6
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 +108 -475
- package/scss/_marketing.scss +337 -0
- package/scss/_tokens.scss +111 -98
- package/scss/_variables.scss +92 -87
- package/scss/_wui-aliases.scss +111 -103
- package/scss/wui/_card.scss +138 -0
- package/scss/wui/_choice.scss +124 -2
- package/scss/wui/_controls.scss +236 -11
- package/scss/wui/_data.scss +26 -13
- package/scss/wui/_display.scss +160 -1
- package/scss/wui/_flow.scss +216 -7
- package/scss/wui/_media.scss +264 -14
- package/scss/wui/_navigation.scss +28 -1
- package/scss/wui/_overlays.scss +45 -1
- package/scss/wui/_typography.scss +16 -0
- package/scss/wui/_utilities.scss +253 -6
package/scss/wui/_media.scss
CHANGED
|
@@ -6,26 +6,55 @@
|
|
|
6
6
|
// here may be overridden by a later partial. Never reorder the imports.
|
|
7
7
|
|
|
8
8
|
// ── Avatar ──
|
|
9
|
-
//
|
|
10
|
-
// the
|
|
9
|
+
// The initials/icon face is the base layer; a photo overlays it edge to edge, cropped
|
|
10
|
+
// to the disc. While the photo loads — or if it breaks — the face shows through.
|
|
11
|
+
.avatar-face {
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
line-height: 1;
|
|
16
|
+
}
|
|
11
17
|
.avatar > .avatar-img {
|
|
18
|
+
position: absolute;
|
|
19
|
+
inset: 0;
|
|
12
20
|
width: 100%;
|
|
13
21
|
height: 100%;
|
|
14
22
|
border-radius: inherit;
|
|
15
23
|
object-fit: cover;
|
|
16
24
|
display: block;
|
|
25
|
+
// Photo fades + scales in so a late-arriving blob doesn't pop.
|
|
26
|
+
animation: wui-avatar-in 0.28s var(--wui-ease-out-quart, ease) both;
|
|
17
27
|
}
|
|
18
28
|
.avatar {
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
// `--avatar-size` drives the default (md, its 32px fallback) and any custom size. It is
|
|
30
|
+
// read via `var(… , 32px)` rather than declared here, so an avatar with no size INHERITS
|
|
31
|
+
// one from an AppAvatarGroup that sets it — while a preset class (explicit width below) or
|
|
32
|
+
// an avatar's own inline `--avatar-size` still wins. Never re-declare it on `.avatar`.
|
|
33
|
+
position: relative;
|
|
34
|
+
width: var(--avatar-size, 32px);
|
|
35
|
+
height: var(--avatar-size, 32px);
|
|
21
36
|
border-radius: 999px;
|
|
22
37
|
background: color-mix(in srgb, var(--color-primary) 15%, var(--color-surface));
|
|
23
38
|
color: var(--color-primary);
|
|
24
|
-
font-size:
|
|
39
|
+
font-size: calc(var(--avatar-size, 32px) * 0.375);
|
|
25
40
|
font-weight: 600;
|
|
26
41
|
display: inline-flex;
|
|
27
42
|
align-items: center;
|
|
28
43
|
justify-content: center;
|
|
44
|
+
flex: none;
|
|
45
|
+
user-select: none;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Size scale ──
|
|
49
|
+
.avatar-xs {
|
|
50
|
+
width: 20px;
|
|
51
|
+
height: 20px;
|
|
52
|
+
font-size: 8px;
|
|
53
|
+
}
|
|
54
|
+
.avatar-sm {
|
|
55
|
+
width: 24px;
|
|
56
|
+
height: 24px;
|
|
57
|
+
font-size: 10px;
|
|
29
58
|
}
|
|
30
59
|
.avatar-lg {
|
|
31
60
|
width: 48px;
|
|
@@ -37,10 +66,230 @@
|
|
|
37
66
|
height: 64px;
|
|
38
67
|
font-size: 22px;
|
|
39
68
|
}
|
|
40
|
-
.avatar-
|
|
41
|
-
width:
|
|
42
|
-
height:
|
|
69
|
+
.avatar-2xl {
|
|
70
|
+
width: 96px;
|
|
71
|
+
height: 96px;
|
|
72
|
+
font-size: 34px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Shape ── (`shape`): the disc is the default; rounded/square are card-like.
|
|
76
|
+
.avatar-rounded {
|
|
77
|
+
border-radius: 25%;
|
|
78
|
+
}
|
|
79
|
+
.avatar-square {
|
|
80
|
+
border-radius: 12%;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── Tone ── (`tone`): the initials fill. `auto` derives a stable hue from the name.
|
|
84
|
+
.avatar-neutral {
|
|
85
|
+
background: color-mix(in srgb, var(--color-text-muted) 16%, var(--color-surface));
|
|
86
|
+
color: var(--color-text-muted);
|
|
87
|
+
}
|
|
88
|
+
.avatar-success {
|
|
89
|
+
background: var(--color-success-soft);
|
|
90
|
+
color: var(--color-success-text);
|
|
91
|
+
}
|
|
92
|
+
.avatar-warning {
|
|
93
|
+
background: var(--color-warning-soft);
|
|
94
|
+
color: var(--color-warning-text);
|
|
95
|
+
}
|
|
96
|
+
.avatar-danger {
|
|
97
|
+
background: var(--color-danger-soft);
|
|
98
|
+
color: var(--color-danger-text);
|
|
99
|
+
}
|
|
100
|
+
.avatar-info {
|
|
101
|
+
background: var(--color-info-soft);
|
|
102
|
+
color: var(--color-info-text);
|
|
103
|
+
}
|
|
104
|
+
.avatar-auto {
|
|
105
|
+
background: hsl(var(--avatar-hue, 0) 60% 90%);
|
|
106
|
+
color: hsl(var(--avatar-hue, 0) 42% 32%);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── Ring ── (`ring`): a tone-coloured ring with a surface gap, separating stacked
|
|
110
|
+
// avatars or marking an active one.
|
|
111
|
+
.avatar-ring {
|
|
112
|
+
box-shadow:
|
|
113
|
+
0 0 0 2px var(--color-surface),
|
|
114
|
+
0 0 0 4px currentColor;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Corner badge ── (`badge`): a small count/marker at the top-right.
|
|
118
|
+
.avatar-badge {
|
|
119
|
+
position: absolute;
|
|
120
|
+
top: -2px;
|
|
121
|
+
right: -2px;
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
min-width: 16px;
|
|
126
|
+
height: 16px;
|
|
127
|
+
padding: 0 4px;
|
|
128
|
+
border-radius: 999px;
|
|
129
|
+
background: var(--color-danger);
|
|
130
|
+
color: #fff;
|
|
43
131
|
font-size: 10px;
|
|
132
|
+
font-weight: 700;
|
|
133
|
+
line-height: 1;
|
|
134
|
+
box-shadow: 0 0 0 2px var(--color-surface);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Clickable ── (`href` / `onClick`): the whole disc is one control.
|
|
138
|
+
.avatar-clickable {
|
|
139
|
+
padding: 0;
|
|
140
|
+
border: 0;
|
|
141
|
+
font: inherit;
|
|
142
|
+
text-decoration: none;
|
|
143
|
+
cursor: pointer;
|
|
144
|
+
-webkit-appearance: none;
|
|
145
|
+
appearance: none;
|
|
146
|
+
transition:
|
|
147
|
+
transform 0.15s var(--wui-ease-out-quart, ease),
|
|
148
|
+
box-shadow 0.15s ease;
|
|
149
|
+
}
|
|
150
|
+
.avatar-clickable:hover {
|
|
151
|
+
transform: scale(1.06);
|
|
152
|
+
}
|
|
153
|
+
.avatar-clickable:focus-visible {
|
|
154
|
+
outline: 2px solid var(--color-primary);
|
|
155
|
+
outline-offset: 2px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── Presence status ── (`status`): a dot at the lower-right, ringed in the surface
|
|
159
|
+
// colour so it reads on a photo. Online quietly pulses.
|
|
160
|
+
.avatar-status {
|
|
161
|
+
position: absolute;
|
|
162
|
+
right: 2%;
|
|
163
|
+
bottom: 2%;
|
|
164
|
+
width: 28%;
|
|
165
|
+
height: 28%;
|
|
166
|
+
min-width: 8px;
|
|
167
|
+
min-height: 8px;
|
|
168
|
+
max-width: 16px;
|
|
169
|
+
max-height: 16px;
|
|
170
|
+
border-radius: 999px;
|
|
171
|
+
box-shadow: 0 0 0 2px var(--color-surface);
|
|
172
|
+
}
|
|
173
|
+
.avatar-status-online {
|
|
174
|
+
background: var(--color-success);
|
|
175
|
+
}
|
|
176
|
+
.avatar-status-away {
|
|
177
|
+
background: var(--color-warning);
|
|
178
|
+
}
|
|
179
|
+
.avatar-status-busy {
|
|
180
|
+
background: var(--color-danger);
|
|
181
|
+
}
|
|
182
|
+
.avatar-status-offline {
|
|
183
|
+
background: color-mix(in srgb, var(--color-text-muted) 55%, var(--color-surface));
|
|
184
|
+
}
|
|
185
|
+
.avatar-status-online::after {
|
|
186
|
+
content: "";
|
|
187
|
+
position: absolute;
|
|
188
|
+
inset: 0;
|
|
189
|
+
border-radius: inherit;
|
|
190
|
+
background: var(--color-success);
|
|
191
|
+
animation: wui-avatar-ping 1.8s cubic-bezier(0, 0, 0.2, 1) infinite;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── Hover label ── (`label`): a tooltip above the avatar, revealed on hover/focus.
|
|
195
|
+
.avatar-label {
|
|
196
|
+
position: absolute;
|
|
197
|
+
bottom: calc(100% + 8px);
|
|
198
|
+
left: 50%;
|
|
199
|
+
transform: translateX(-50%) translateY(4px);
|
|
200
|
+
padding: 4px 8px;
|
|
201
|
+
border-radius: var(--radius-sm);
|
|
202
|
+
background: var(--color-text);
|
|
203
|
+
color: var(--color-surface);
|
|
204
|
+
font-size: 12px;
|
|
205
|
+
font-weight: 500;
|
|
206
|
+
line-height: 1.2;
|
|
207
|
+
white-space: nowrap;
|
|
208
|
+
opacity: 0;
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
z-index: 30;
|
|
211
|
+
transition:
|
|
212
|
+
opacity 0.16s ease,
|
|
213
|
+
transform 0.16s var(--wui-ease-out-quart, ease);
|
|
214
|
+
}
|
|
215
|
+
.avatar-label::after {
|
|
216
|
+
content: "";
|
|
217
|
+
position: absolute;
|
|
218
|
+
top: 100%;
|
|
219
|
+
left: 50%;
|
|
220
|
+
transform: translateX(-50%);
|
|
221
|
+
border: 4px solid transparent;
|
|
222
|
+
border-top-color: var(--color-text);
|
|
223
|
+
}
|
|
224
|
+
.avatar:hover > .avatar-label,
|
|
225
|
+
.avatar:focus-visible > .avatar-label,
|
|
226
|
+
.avatar:focus-within > .avatar-label {
|
|
227
|
+
opacity: 1;
|
|
228
|
+
transform: translateX(-50%) translateY(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ── Avatar group ── (AppAvatarGroup): a row of overlapping avatars, each ringed in the
|
|
232
|
+
// surface colour so it reads against its neighbour. Hover raises one to the front.
|
|
233
|
+
.avatar-group {
|
|
234
|
+
display: inline-flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
}
|
|
237
|
+
.avatar-group > .avatar {
|
|
238
|
+
margin-left: -10px;
|
|
239
|
+
box-shadow: 0 0 0 2px var(--color-surface);
|
|
240
|
+
transition: transform 0.15s var(--wui-ease-out-quart, ease);
|
|
241
|
+
}
|
|
242
|
+
.avatar-group > .avatar:first-child {
|
|
243
|
+
margin-left: 0;
|
|
244
|
+
}
|
|
245
|
+
.avatar-group > .avatar:hover {
|
|
246
|
+
z-index: 1;
|
|
247
|
+
transform: translateY(-2px);
|
|
248
|
+
}
|
|
249
|
+
.avatar-group-tight > .avatar {
|
|
250
|
+
margin-left: -14px;
|
|
251
|
+
}
|
|
252
|
+
.avatar-group-loose > .avatar {
|
|
253
|
+
margin-left: -4px;
|
|
254
|
+
}
|
|
255
|
+
// The "+N" overflow chip — a muted avatar-shaped tail.
|
|
256
|
+
.avatar-more {
|
|
257
|
+
background: color-mix(in srgb, var(--color-text-muted) 16%, var(--color-surface));
|
|
258
|
+
color: var(--color-text-muted);
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@keyframes wui-avatar-in {
|
|
263
|
+
from {
|
|
264
|
+
opacity: 0;
|
|
265
|
+
transform: scale(0.92);
|
|
266
|
+
}
|
|
267
|
+
to {
|
|
268
|
+
opacity: 1;
|
|
269
|
+
transform: scale(1);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
@keyframes wui-avatar-ping {
|
|
273
|
+
0% {
|
|
274
|
+
opacity: 0.5;
|
|
275
|
+
transform: scale(1);
|
|
276
|
+
}
|
|
277
|
+
70%,
|
|
278
|
+
100% {
|
|
279
|
+
opacity: 0;
|
|
280
|
+
transform: scale(2.2);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
@media (prefers-reduced-motion: reduce) {
|
|
284
|
+
.avatar > .avatar-img {
|
|
285
|
+
animation: none;
|
|
286
|
+
}
|
|
287
|
+
.avatar-status-online::after {
|
|
288
|
+
animation: none;
|
|
289
|
+
}
|
|
290
|
+
.avatar-label {
|
|
291
|
+
transition: opacity 0.16s ease;
|
|
292
|
+
}
|
|
44
293
|
}
|
|
45
294
|
|
|
46
295
|
// ── File attach ──
|
|
@@ -161,7 +410,7 @@
|
|
|
161
410
|
width: 28px;
|
|
162
411
|
height: 28px;
|
|
163
412
|
border: 0;
|
|
164
|
-
background:
|
|
413
|
+
background: var(--color-scrim-strong);
|
|
165
414
|
backdrop-filter: blur(10px);
|
|
166
415
|
-webkit-backdrop-filter: blur(10px);
|
|
167
416
|
color: #fff;
|
|
@@ -524,8 +773,9 @@
|
|
|
524
773
|
display: flex;
|
|
525
774
|
align-items: center;
|
|
526
775
|
justify-content: center;
|
|
527
|
-
// Subtle dim so the glassy CTA reads on any image, without hiding it
|
|
528
|
-
|
|
776
|
+
// Subtle dim so the glassy CTA reads on any image, without hiding it —
|
|
777
|
+
// half the standard scrim strength.
|
|
778
|
+
background: color-mix(in srgb, var(--color-scrim) 50%, transparent);
|
|
529
779
|
opacity: 0;
|
|
530
780
|
transition: opacity 0.15s ease;
|
|
531
781
|
}
|
|
@@ -560,7 +810,7 @@
|
|
|
560
810
|
padding: 0;
|
|
561
811
|
border: 2px solid transparent;
|
|
562
812
|
border-radius: 50%;
|
|
563
|
-
background:
|
|
813
|
+
background: var(--color-scrim-strong);
|
|
564
814
|
color: #fff;
|
|
565
815
|
cursor: pointer;
|
|
566
816
|
opacity: 0;
|
|
@@ -646,7 +896,7 @@
|
|
|
646
896
|
align-items: center;
|
|
647
897
|
justify-content: center;
|
|
648
898
|
gap: 4px;
|
|
649
|
-
background:
|
|
899
|
+
background: var(--color-scrim-strong);
|
|
650
900
|
color: #fff;
|
|
651
901
|
font-size: 11px;
|
|
652
902
|
font-weight: 600;
|
|
@@ -794,7 +1044,7 @@
|
|
|
794
1044
|
align-items: center;
|
|
795
1045
|
justify-content: center;
|
|
796
1046
|
gap: 4px;
|
|
797
|
-
background: var(--color-scrim);
|
|
1047
|
+
background: var(--color-scrim-strong);
|
|
798
1048
|
color: var(--color-on-scrim);
|
|
799
1049
|
font-size: 12px;
|
|
800
1050
|
font-weight: 600;
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
.drawer-backdrop {
|
|
55
55
|
position: fixed;
|
|
56
56
|
inset: 0;
|
|
57
|
-
background:
|
|
57
|
+
background: var(--color-scrim);
|
|
58
58
|
opacity: 0;
|
|
59
59
|
pointer-events: none;
|
|
60
60
|
transition: opacity 0.2s;
|
|
@@ -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
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// Do NOT put layout on backdropClassName — that targets a sibling, not
|
|
16
16
|
// .modal.
|
|
17
17
|
.modal-backdrop.wui-modal-dim {
|
|
18
|
-
background:
|
|
18
|
+
background: var(--color-scrim);
|
|
19
19
|
z-index: var(--wui-z-modal-backdrop);
|
|
20
20
|
}
|
|
21
21
|
.modal.wui-modal-shell {
|
|
@@ -328,3 +328,47 @@
|
|
|
328
328
|
font-size: 14px;
|
|
329
329
|
font-weight: 500;
|
|
330
330
|
}
|
|
331
|
+
|
|
332
|
+
// ── Toast (notifications) ──
|
|
333
|
+
// Bootstrap toast styling + wui extensions for title/action buttons.
|
|
334
|
+
// Used by both React AppToastContainer and Razor WUI.toast.
|
|
335
|
+
|
|
336
|
+
// Toast header with title
|
|
337
|
+
.wui-toast-header {
|
|
338
|
+
display: flex;
|
|
339
|
+
align-items: center;
|
|
340
|
+
justify-content: space-between;
|
|
341
|
+
gap: 12px;
|
|
342
|
+
padding: 10px 12px;
|
|
343
|
+
border: none;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.wui-toast-header strong {
|
|
347
|
+
font-size: 14px;
|
|
348
|
+
font-weight: 600;
|
|
349
|
+
color: inherit;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Toast action button — inherits text color from the variant tone. Scoped to the
|
|
353
|
+
// component class, not every .btn-link a consumer might place in a toast body.
|
|
354
|
+
.toast .wui-toast-action {
|
|
355
|
+
color: inherit;
|
|
356
|
+
text-decoration: none;
|
|
357
|
+
font-size: 13px;
|
|
358
|
+
font-weight: 500;
|
|
359
|
+
padding: 2px 8px;
|
|
360
|
+
white-space: nowrap;
|
|
361
|
+
flex: none;
|
|
362
|
+
opacity: 0.9;
|
|
363
|
+
transition: opacity 150ms;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.toast .wui-toast-action:hover {
|
|
367
|
+
opacity: 1;
|
|
368
|
+
text-decoration: underline;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.toast .wui-toast-action:focus-visible {
|
|
372
|
+
outline: 2px solid currentColor;
|
|
373
|
+
outline-offset: 2px;
|
|
374
|
+
}
|
|
@@ -279,6 +279,22 @@ wui-multiselect[collapse-chips] .ms-chips {
|
|
|
279
279
|
align-items: center;
|
|
280
280
|
gap: 8px;
|
|
281
281
|
}
|
|
282
|
+
.ms-input {
|
|
283
|
+
flex: 1;
|
|
284
|
+
min-width: 60px;
|
|
285
|
+
border: none;
|
|
286
|
+
background: transparent;
|
|
287
|
+
font: inherit;
|
|
288
|
+
color: inherit;
|
|
289
|
+
padding: 0;
|
|
290
|
+
margin: 0;
|
|
291
|
+
}
|
|
292
|
+
.ms-input::placeholder {
|
|
293
|
+
color: var(--color-text-subtle);
|
|
294
|
+
}
|
|
295
|
+
.ms-input:focus {
|
|
296
|
+
outline: none;
|
|
297
|
+
}
|
|
282
298
|
|
|
283
299
|
/* ── Choice card: image / custom-template variant ── */
|
|
284
300
|
.struct-card-img-card {
|