@omnitend/dashboard-for-laravel 0.41.1 → 0.42.0
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 +2 -1
- package/dist/assets/MavenPro-Bold-35b16f06.woff2 +0 -0
- package/dist/assets/MavenPro-Medium-febc8674.woff2 +0 -0
- package/dist/assets/MavenPro-Regular-aee3df9e.woff2 +0 -0
- package/dist/assets/MavenPro-SemiBold-c555dbfa.woff2 +0 -0
- package/dist/assets/Poppins-Medium-5800fa57.woff2 +0 -0
- package/dist/assets/Poppins-SemiBold-94a36267.woff2 +0 -0
- package/dist/charts.js +148 -130
- package/dist/charts.js.map +1 -1
- package/dist/charts.umd.cjs +1 -1
- package/dist/charts.umd.cjs.map +1 -1
- package/dist/components/base/DModal.vue.d.ts +26 -2
- package/dist/components/charts/chartTheme.d.ts +14 -2
- package/dist/components/extended/DXField.vue.d.ts +16 -5
- package/dist/components/extended/DXForm.vue.d.ts +25 -9
- package/dist/components/extended/DXLoading.vue.d.ts +9 -0
- package/dist/components/extended/DXModalActions.vue.d.ts +12 -0
- package/dist/components/extended/DXNumberStepper.vue.d.ts +33 -0
- package/dist/components/extended/DXSaveButton.vue.d.ts +38 -0
- package/dist/components/extended/DXSwitch.vue.d.ts +1 -1
- package/dist/components/extended/DXTable.vue.d.ts +8 -2
- package/dist/composables/useForm.d.ts +7 -0
- package/dist/dashboard-for-laravel.js +9547 -9246
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +7 -7
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/style.css +2 -2
- package/dist/types/index.d.ts +20 -3
- package/docs/public/api-reference.json +219 -17
- package/docs/public/docs-map.md +4 -2
- package/docs/public/llms.txt +7 -2
- package/package.json +1 -1
- package/resources/css/theme.scss +524 -103
- package/resources/fonts/maven-pro/MavenPro-Bold.woff2 +0 -0
- package/resources/fonts/maven-pro/MavenPro-Medium.woff2 +0 -0
- package/resources/fonts/maven-pro/MavenPro-Regular.woff2 +0 -0
- package/resources/fonts/maven-pro/MavenPro-SemiBold.woff2 +0 -0
- package/resources/fonts/maven-pro/OFL.txt +93 -0
- package/resources/fonts/poppins/OFL.txt +93 -0
- package/resources/fonts/poppins/Poppins-Medium.woff2 +0 -0
- package/resources/fonts/poppins/Poppins-SemiBold.woff2 +0 -0
- package/resources/js/components/base/DModal.vue +13 -2
- package/resources/js/components/charts/DXBarChart.vue +2 -1
- package/resources/js/components/charts/DXDoughnutChart.vue +2 -1
- package/resources/js/components/charts/DXLineChart.vue +2 -1
- package/resources/js/components/charts/chartTheme.ts +68 -21
- package/resources/js/components/extended/DXDashboard.vue +4 -2
- package/resources/js/components/extended/DXDashboardSidebar.vue +52 -20
- package/resources/js/components/extended/DXField.vue +59 -28
- package/resources/js/components/extended/DXForm.vue +122 -21
- package/resources/js/components/extended/DXLoading.vue +47 -0
- package/resources/js/components/extended/DXModalActions.vue +13 -0
- package/resources/js/components/extended/DXNumberStepper.vue +243 -0
- package/resources/js/components/extended/DXSaveButton.vue +82 -0
- package/resources/js/components/extended/DXSwitch.vue +8 -5
- package/resources/js/components/extended/DXTable.vue +58 -22
- package/resources/js/components/extended/DXTablePagination.vue +1 -1
- package/resources/js/composables/useForm.ts +11 -0
- package/resources/js/composables/useToast.ts +1 -1
- package/resources/js/index.ts +5 -0
- package/resources/js/types/index.ts +21 -3
package/resources/css/theme.scss
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
@use "sass:color";
|
|
10
10
|
@use "sass:list";
|
|
11
11
|
@use "sass:map";
|
|
12
|
+
@use "sass:math";
|
|
12
13
|
|
|
13
14
|
// ----------------------------------------------------------------------------
|
|
14
15
|
// Colors
|
|
@@ -17,21 +18,23 @@
|
|
|
17
18
|
// Base $theme-colors carry each hue's READABLE-ON-LIGHT identity (its "emphasis"
|
|
18
19
|
// shade) — this is what `.text-*`, `.link-*`, `.border-*` and outline buttons
|
|
19
20
|
// use, so every one must clear AA on white. The one bold solid FILL (the primary
|
|
20
|
-
// button) and SOFT tints (soft buttons incl. danger, badges
|
|
21
|
+
// button) and SOFT tints (soft buttons incl. danger, badges) are applied
|
|
21
22
|
// as explicit overrides after the Bootstrap import, from the $dx-variants map. See
|
|
22
23
|
// plans/2026-07-18-semantic-colour-system.md.
|
|
23
24
|
$primary: #151e2d; // Omni Tend brand navy (16.73:1 on white)
|
|
24
25
|
$secondary: #475569; // Slate-600 (7.58:1 on white)
|
|
25
|
-
$success: #
|
|
26
|
-
$danger: #
|
|
27
|
-
$warning: #
|
|
28
|
-
$info: #
|
|
26
|
+
$success: #236b12; // Deep green emphasis (6.60:1 on white); vivid/soft tints in $dx-variants
|
|
27
|
+
$danger: #a3247f; // Deep magenta emphasis (6.74:1 on white)
|
|
28
|
+
$warning: #8a6d00; // Deep ochre emphasis (4.92:1 on white)
|
|
29
|
+
$info: #31586d; // Deep slate-teal emphasis (7.64:1 on white)
|
|
29
30
|
$light: #f8fafc; // Slate-50 (uses dark text)
|
|
30
31
|
$dark: #151e2d; // Brand navy — sidebar/high-contrast surfaces (was Slate-900 #0f172a)
|
|
31
32
|
|
|
32
|
-
// Links are the
|
|
33
|
-
//
|
|
34
|
-
$link-
|
|
33
|
+
// Links are the brand navy (16.73:1 on white). A navy link would read as bold
|
|
34
|
+
// text if it lost its underline, so links KEEP Bootstrap's default underline
|
|
35
|
+
// ($link-decoration is not overridden here; only `.btn-link`, the ghost
|
|
36
|
+
// button, drops it). The underline, not the hue, is what marks a link.
|
|
37
|
+
$link-color: #151e2d;
|
|
35
38
|
$link-shade-percentage: 15%;
|
|
36
39
|
|
|
37
40
|
// ----------------------------------------------------------------------------
|
|
@@ -47,7 +50,18 @@ $color-contrast-light: #fff; // Light text color (for dark backgrounds)
|
|
|
47
50
|
// Typography
|
|
48
51
|
// ----------------------------------------------------------------------------
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
// Two bundled typefaces (SIL OFL 1.1; woff2 + licence in resources/fonts/):
|
|
54
|
+
// MAVEN PRO for body text, and POPPINS as the DISPLAY face, published as
|
|
55
|
+
// `--dx-font-family-display`. The theme applies the display face to h1–h4 and
|
|
56
|
+
// nothing else; consumers use the token for things like product names. Both
|
|
57
|
+
// are declared with `@font-face` below, so they render on every machine, not
|
|
58
|
+
// only where the font happens to be installed (the theme used to name Poppins
|
|
59
|
+
// and ship no face for it, so most visitors got the generic sans-serif).
|
|
60
|
+
$font-family-sans-serif: "Maven Pro", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
61
|
+
"Helvetica Neue", Arial, sans-serif;
|
|
62
|
+
$dx-font-family-display: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto,
|
|
63
|
+
"Helvetica Neue", Arial, sans-serif;
|
|
64
|
+
$headings-font-family: var(--dx-font-family-display);
|
|
51
65
|
$font-size-base: 1rem; // 16px — the default tier. Legacy omnitend rendered body
|
|
52
66
|
// and table text at 16px; the earlier 0.875rem (14px) shrank every ported page's
|
|
53
67
|
// text ~12% while rem-fixed chrome stayed put, so controls read oversized and
|
|
@@ -56,14 +70,19 @@ $font-size-base: 1rem; // 16px — the default tier. Legacy omnitend rendered bo
|
|
|
56
70
|
$font-weight-base: 400;
|
|
57
71
|
$line-height-base: 1.5;
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
// A compact, restrained heading scale for dense admin screens: chosen from
|
|
74
|
+
// rendered comparisons against legacy omnitend, which set headings at weight
|
|
75
|
+
// 500. The old 2rem…1.25rem at 600 shouted over the data. h1 is at Bootstrap's
|
|
76
|
+
// RFS threshold (1.25rem), so no heading is rescaled on narrow viewports. h5
|
|
77
|
+
// and h6 sit at body size so neither outranks h4.
|
|
78
|
+
$h1-font-size: 1.25rem; // 20px
|
|
79
|
+
$h2-font-size: 1.15rem; // 18.4px
|
|
80
|
+
$h3-font-size: 1.05rem; // 16.8px
|
|
81
|
+
$h4-font-size: 1.05rem; // 16.8px
|
|
82
|
+
$h5-font-size: 1rem; // 16px
|
|
64
83
|
$h6-font-size: 1rem; // 16px
|
|
65
84
|
|
|
66
|
-
$headings-font-weight:
|
|
85
|
+
$headings-font-weight: 500;
|
|
67
86
|
|
|
68
87
|
// ----------------------------------------------------------------------------
|
|
69
88
|
// Spacing
|
|
@@ -137,7 +156,9 @@ $card-border-radius: $border-radius;
|
|
|
137
156
|
$card-border-color: $border-color;
|
|
138
157
|
$card-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
|
139
158
|
0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
|
140
|
-
|
|
159
|
+
// A quiet blue-tinted cap (legacy Omni Tend's card header) so a card's title
|
|
160
|
+
// reads as a band above its body rather than floating on the same white.
|
|
161
|
+
$card-cap-bg: #f6f8fd;
|
|
141
162
|
$card-spacer-y: 1.5rem; // 24px vertical padding
|
|
142
163
|
$card-spacer-x: 1.5rem; // 24px horizontal padding
|
|
143
164
|
|
|
@@ -145,6 +166,11 @@ $card-spacer-x: 1.5rem; // 24px horizontal padding
|
|
|
145
166
|
// Tables
|
|
146
167
|
// ----------------------------------------------------------------------------
|
|
147
168
|
|
|
169
|
+
// Body cells take the body text colour (#212529) rather than Bootstrap's
|
|
170
|
+
// `--bs-emphasis-color` (pure black), and header cells a medium weight instead
|
|
171
|
+
// of the browser's bold. Header COLOUR is `--dx-table-header-color` (below).
|
|
172
|
+
$table-color: var(--bs-body-color);
|
|
173
|
+
$table-th-font-weight: 500;
|
|
148
174
|
$table-cell-padding-y: 0.75rem;
|
|
149
175
|
$table-cell-padding-x: 1rem;
|
|
150
176
|
$table-striped-bg: #f9fafb; // Gray-50
|
|
@@ -177,25 +203,135 @@ $badge-font-weight: 500;
|
|
|
177
203
|
|
|
178
204
|
// The ONE source of truth for the semantic colour system. Each variant carries
|
|
179
205
|
// its SOLID fill + same-hue text (the primary button, solid fills), its SOFT
|
|
180
|
-
// tint pair (soft buttons, badges, alerts
|
|
181
|
-
// buttons, coloured links, .text-*), and whether
|
|
206
|
+
// tint pair (soft buttons, badges, status; alerts use its paler subtle mix),
|
|
207
|
+
// its EMPHASIS shade (outline buttons, coloured links, .text-*), and whether
|
|
208
|
+
// its button is solid or soft.
|
|
182
209
|
// The overrides after the Bootstrap import loop over this map. All pairs are
|
|
183
210
|
// WCAG AA verified. See plans/2026-07-18-semantic-colour-system.md.
|
|
184
211
|
//
|
|
185
212
|
// Only PRIMARY is a bold solid button — one loud action (the brand). Everything
|
|
186
|
-
// else, INCLUDING danger, is soft: a soft
|
|
187
|
-
// a heavy fill, and one solid button per screen keeps the hierarchy
|
|
188
|
-
//
|
|
189
|
-
//
|
|
213
|
+
// else, INCLUDING danger, is soft: a soft magenta "Delete" reads as danger
|
|
214
|
+
// without a heavy fill, and one solid button per screen keeps the hierarchy
|
|
215
|
+
// clear.
|
|
216
|
+
//
|
|
217
|
+
// The status hues are the "fruity" palette (2026-10): a vivid lime, magenta,
|
|
218
|
+
// butter yellow and sky blue for the solid fills, light tints of the same hues
|
|
219
|
+
// for the soft pair, and a deep shade of each for the emphasis. Every label is
|
|
220
|
+
// a dark same-hue ink (no white text on a status fill). Contrast: solid text on
|
|
221
|
+
// solid fill 5.50:1 (danger) to 12.67:1 (warning); soft text on soft fill
|
|
222
|
+
// 9.93:1 to 14.56:1; emphasis on white 4.92:1 (warning) to 16.73:1. Warning's
|
|
223
|
+
// soft pair IS its solid pair: the butter yellow is already light enough to be
|
|
224
|
+
// the tint.
|
|
225
|
+
//
|
|
226
|
+
// PENDING is a status of its own: waiting, and the next move is not yours
|
|
227
|
+
// ("awaiting payment", "sent to printer, not yet confirmed"). It is a violet
|
|
228
|
+
// from the chart lavender (#b9a3f0 is chart slot 5), kept clear of info's
|
|
229
|
+
// slate blue by hue and by its violet ink. Contrast: solid 7.06:1, soft
|
|
230
|
+
// 9.10:1, emphasis 6.54:1 on white, soft text on its subtle (alert) tint
|
|
231
|
+
// 11.58:1.
|
|
190
232
|
$dx-variants: (
|
|
191
233
|
"primary": (solid-bg: #151e2d, solid-text: #e9f0f8, soft-bg: #e9f0f8, soft-text: #151e2d, emphasis: #151e2d, button: "solid"),
|
|
192
234
|
"secondary": (solid-bg: #475569, solid-text: #e6ebf2, soft-bg: #e6ebf2, soft-text: #29374a, emphasis: #475569, button: "soft"),
|
|
193
|
-
"success": (solid-bg: #
|
|
194
|
-
"danger": (solid-bg: #
|
|
195
|
-
"warning": (solid-bg: #
|
|
196
|
-
"info": (solid-bg: #
|
|
235
|
+
"success": (solid-bg: #7bf25a, solid-text: #153c04, soft-bg: #c3faaa, soft-text: #153c04, emphasis: #236b12, button: "soft"),
|
|
236
|
+
"danger": (solid-bg: #e46ab9, solid-text: #3d0a2f, soft-bg: #f9dff2, soft-text: #61124c, emphasis: #a3247f, button: "soft"),
|
|
237
|
+
"warning": (solid-bg: #efd574, solid-text: #121419, soft-bg: #efd574, soft-text: #121419, emphasis: #8a6d00, button: "soft"),
|
|
238
|
+
"info": (solid-bg: #7fd7fd, solid-text: #192547, soft-bg: #d5dcf0, soft-text: #192547, emphasis: #31586d, button: "soft"),
|
|
239
|
+
"pending": (solid-bg: #b9a3f0, solid-text: #2a1260, soft-bg: #e3d3fb, soft-text: #3b1a80, emphasis: #6a43c4, button: "soft"),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Bootstrap's base map plus `pending` (its emphasis, like every other base
|
|
243
|
+
// colour), so Bootstrap generates `.btn-pending`, `.btn-outline-pending`,
|
|
244
|
+
// `.text-bg-pending`, `.text-pending`, `.link-pending`, `.border-pending`,
|
|
245
|
+
// `.alert-pending` and `.list-group-item-pending` itself. The subtle maps get
|
|
246
|
+
// their `pending` entries just before the Bootstrap import (they only exist
|
|
247
|
+
// once Bootstrap's own variables and maps have been read).
|
|
248
|
+
$theme-colors: (
|
|
249
|
+
"primary": $primary,
|
|
250
|
+
"secondary": $secondary,
|
|
251
|
+
"success": $success,
|
|
252
|
+
"info": $info,
|
|
253
|
+
"warning": $warning,
|
|
254
|
+
"danger": $danger,
|
|
255
|
+
"pending": map.get(map.get($dx-variants, "pending"), "emphasis"),
|
|
256
|
+
"light": $light,
|
|
257
|
+
"dark": $dark,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
// Bootstrap's "subtle" family (`.bg-*-subtle`, `.border-*-subtle`,
|
|
261
|
+
// `.text-*-emphasis`, list-group and table variants) is derived from the SAME
|
|
262
|
+
// soft tints, so a subtle surface is a paler cousin of the badge rather than a
|
|
263
|
+
// separate, greyer family Bootstrap would otherwise mix from the dark emphasis
|
|
264
|
+
// base. Set here, before the import, so Bootstrap's own maps pick them up.
|
|
265
|
+
//
|
|
266
|
+
// The subtle background is the soft tint mixed with white so the result is 70%
|
|
267
|
+
// white. On real pages legacy omnitend's tinted table rows measure about that
|
|
268
|
+
// (danger #fdf6fb, warning #fbf3d8); the earlier 50% mix read too strong for a
|
|
269
|
+
// row or an alert, which are large surfaces.
|
|
270
|
+
// Sass cannot create variables in a loop, hence one line per variable; the
|
|
271
|
+
// functions keep the three formulas in one place. Dark mode's `*-dark`
|
|
272
|
+
// variables are left to Bootstrap.
|
|
273
|
+
@function dx-soft($name, $key) {
|
|
274
|
+
@return map.get(map.get($dx-variants, $name), $key);
|
|
275
|
+
}
|
|
276
|
+
@function dx-subtle-bg($name) {
|
|
277
|
+
@return color.mix(#fff, dx-soft($name, "soft-bg"), 70%);
|
|
278
|
+
}
|
|
279
|
+
@function dx-subtle-border($name) {
|
|
280
|
+
@return color.scale(dx-soft($name, "soft-bg"), $lightness: -10%);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
$primary-bg-subtle: dx-subtle-bg("primary");
|
|
284
|
+
$primary-border-subtle: dx-subtle-border("primary");
|
|
285
|
+
$primary-text-emphasis: dx-soft("primary", "soft-text");
|
|
286
|
+
$secondary-bg-subtle: dx-subtle-bg("secondary");
|
|
287
|
+
$secondary-border-subtle: dx-subtle-border("secondary");
|
|
288
|
+
$secondary-text-emphasis: dx-soft("secondary", "soft-text");
|
|
289
|
+
$success-bg-subtle: dx-subtle-bg("success");
|
|
290
|
+
$success-border-subtle: dx-subtle-border("success");
|
|
291
|
+
$success-text-emphasis: dx-soft("success", "soft-text");
|
|
292
|
+
$danger-bg-subtle: dx-subtle-bg("danger");
|
|
293
|
+
$danger-border-subtle: dx-subtle-border("danger");
|
|
294
|
+
$danger-text-emphasis: dx-soft("danger", "soft-text");
|
|
295
|
+
$warning-bg-subtle: dx-subtle-bg("warning");
|
|
296
|
+
$warning-border-subtle: dx-subtle-border("warning");
|
|
297
|
+
$warning-text-emphasis: dx-soft("warning", "soft-text");
|
|
298
|
+
$info-bg-subtle: dx-subtle-bg("info");
|
|
299
|
+
$info-border-subtle: dx-subtle-border("info");
|
|
300
|
+
$info-text-emphasis: dx-soft("info", "soft-text");
|
|
301
|
+
|
|
302
|
+
// Table row variants (`.table-success` etc.) use the same 70%-white tints.
|
|
303
|
+
// Bootstrap would otherwise shift each base colour toward white, which for the
|
|
304
|
+
// dark emphasis bases gives a muddy row tint.
|
|
305
|
+
$table-variants: (
|
|
306
|
+
"primary": dx-subtle-bg("primary"),
|
|
307
|
+
"secondary": dx-subtle-bg("secondary"),
|
|
308
|
+
"success": dx-subtle-bg("success"),
|
|
309
|
+
"danger": dx-subtle-bg("danger"),
|
|
310
|
+
"warning": dx-subtle-bg("warning"),
|
|
311
|
+
"info": dx-subtle-bg("info"),
|
|
312
|
+
"pending": dx-subtle-bg("pending"),
|
|
313
|
+
"light": $light,
|
|
314
|
+
"dark": $dark,
|
|
197
315
|
);
|
|
198
316
|
|
|
317
|
+
// Form errors are crimson, NOT the danger magenta: an invalid field has to
|
|
318
|
+
// read as "wrong" at a glance, which the playful magenta badge hue does not.
|
|
319
|
+
// #c8102e is 5.88:1 on white. Danger badges and buttons stay magenta.
|
|
320
|
+
$dx-form-error: #c8102e;
|
|
321
|
+
$form-invalid-color: $dx-form-error;
|
|
322
|
+
$form-invalid-border-color: $dx-form-error;
|
|
323
|
+
$form-feedback-invalid-color: $dx-form-error;
|
|
324
|
+
$form-feedback-icon-invalid-color: $dx-form-error;
|
|
325
|
+
|
|
326
|
+
// Width of a horizontal field's label column when the caller sets no
|
|
327
|
+
// `labelCols` (DXField/DXForm). 45% sits between Bootstrap's 5/12 and 6/12
|
|
328
|
+
// steps on purpose: chosen from rendered options, it lets a label with help
|
|
329
|
+
// text wrap far less than the old 3/12 without starving the input. Applies
|
|
330
|
+
// from `sm` up; below `sm` the label stacks. Published as
|
|
331
|
+
// `--dx-form-label-width` so a consumer can retune it in CSS. An explicit
|
|
332
|
+
// `labelCols` uses the 12-column grid instead and ignores this.
|
|
333
|
+
$dx-form-label-width: 45%;
|
|
334
|
+
|
|
199
335
|
// ----------------------------------------------------------------------------
|
|
200
336
|
// Dashboard
|
|
201
337
|
// ----------------------------------------------------------------------------
|
|
@@ -204,6 +340,14 @@ $dashboard-sidebar-width: 280px;
|
|
|
204
340
|
$dashboard-sidebar-collapsed-width: 80px;
|
|
205
341
|
$dashboard-navbar-height: 64px;
|
|
206
342
|
|
|
343
|
+
// The shell's one horizontal gutter: the navbar's inner padding AND the page
|
|
344
|
+
// content's left/right edge both come from it, so the navbar's first item (the
|
|
345
|
+
// menu toggle, or whatever leads the bar) starts exactly where the page content
|
|
346
|
+
// starts. They used to be 12px and 36px, so nothing on the bar lined up with
|
|
347
|
+
// anything on the page. Published as `--dx-dashboard-gutter-x` on `:root`;
|
|
348
|
+
// a consumer can retune both edges together by overriding that.
|
|
349
|
+
$dashboard-gutter-x: 20px;
|
|
350
|
+
|
|
207
351
|
// The bar's vertical padding, and the single-row CONTENT BUDGET that follows
|
|
208
352
|
// from it. Everything on the bar's single row — the avatar toggle, whatever a
|
|
209
353
|
// consumer puts in the `actions` or `user-icon` slots — has to fit this, or the
|
|
@@ -237,6 +381,48 @@ $dashboard-navbar-content-height: calc(
|
|
|
237
381
|
// Import Bootstrap
|
|
238
382
|
// ----------------------------------------------------------------------------
|
|
239
383
|
|
|
384
|
+
// `pending` in the subtle family. Bootstrap's subtle maps, and the utility maps
|
|
385
|
+
// behind `.bg-*-subtle`, `.border-*-subtle` and `.text-*-emphasis`, list the
|
|
386
|
+
// eight stock colours by name and are defined from Bootstrap's own variables,
|
|
387
|
+
// so they can only be extended after those are read. Import the configuration
|
|
388
|
+
// layer first, merge, then import Bootstrap as a whole: every variable and map
|
|
389
|
+
// in it is `!default`, so the second read keeps these values and the layer
|
|
390
|
+
// emits no CSS. Dark mode follows Bootstrap's own derivation from the base
|
|
391
|
+
// colour (text tint 40%, background shade 80%, border shade 40%).
|
|
392
|
+
@import "bootstrap/scss/functions";
|
|
393
|
+
@import "bootstrap/scss/variables";
|
|
394
|
+
@import "bootstrap/scss/variables-dark";
|
|
395
|
+
@import "bootstrap/scss/maps";
|
|
396
|
+
|
|
397
|
+
$dx-pending-emphasis: map.get(map.get($dx-variants, "pending"), "emphasis");
|
|
398
|
+
$theme-colors-text: map.merge($theme-colors-text, ("pending": dx-soft("pending", "soft-text")));
|
|
399
|
+
$theme-colors-bg-subtle: map.merge($theme-colors-bg-subtle, ("pending": dx-subtle-bg("pending")));
|
|
400
|
+
$theme-colors-border-subtle: map.merge(
|
|
401
|
+
$theme-colors-border-subtle,
|
|
402
|
+
("pending": dx-subtle-border("pending"))
|
|
403
|
+
);
|
|
404
|
+
$theme-colors-text-dark: map.merge(
|
|
405
|
+
$theme-colors-text-dark,
|
|
406
|
+
("pending": tint-color($dx-pending-emphasis, 40%))
|
|
407
|
+
);
|
|
408
|
+
$theme-colors-bg-subtle-dark: map.merge(
|
|
409
|
+
$theme-colors-bg-subtle-dark,
|
|
410
|
+
("pending": shade-color($dx-pending-emphasis, 80%))
|
|
411
|
+
);
|
|
412
|
+
$theme-colors-border-subtle-dark: map.merge(
|
|
413
|
+
$theme-colors-border-subtle-dark,
|
|
414
|
+
("pending": shade-color($dx-pending-emphasis, 40%))
|
|
415
|
+
);
|
|
416
|
+
$utilities-text-emphasis-colors: map.merge(
|
|
417
|
+
$utilities-text-emphasis-colors,
|
|
418
|
+
("pending-emphasis": var(--bs-pending-text-emphasis))
|
|
419
|
+
);
|
|
420
|
+
$utilities-bg-subtle: map.merge($utilities-bg-subtle, ("pending-subtle": var(--bs-pending-bg-subtle)));
|
|
421
|
+
$utilities-border-subtle: map.merge(
|
|
422
|
+
$utilities-border-subtle,
|
|
423
|
+
("pending-subtle": var(--bs-pending-border-subtle))
|
|
424
|
+
);
|
|
425
|
+
|
|
240
426
|
@import "bootstrap/scss/bootstrap";
|
|
241
427
|
|
|
242
428
|
// ----------------------------------------------------------------------------
|
|
@@ -268,6 +454,53 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
268
454
|
format("woff2");
|
|
269
455
|
@import "bootstrap-icons/font/bootstrap-icons";
|
|
270
456
|
|
|
457
|
+
// ----------------------------------------------------------------------------
|
|
458
|
+
// Bundled text fonts
|
|
459
|
+
// ----------------------------------------------------------------------------
|
|
460
|
+
// Maven Pro (body) and Poppins (display), woff2 only, one face per weight the
|
|
461
|
+
// theme uses: Maven Pro 400/500/600/700 (body, `.fw-medium`/`.fw-semibold`,
|
|
462
|
+
// `<strong>`/`.fw-bold`), Poppins 500 (h1–h4) and 600 (`.fw-semibold` on a
|
|
463
|
+
// display heading, e.g. DXDashboardNavbar's page title). A weight not listed
|
|
464
|
+
// here is synthesised by the browser, so add a face rather than relying on it.
|
|
465
|
+
//
|
|
466
|
+
// These are extracted out of `dist/style.css` the same way as the icon font
|
|
467
|
+
// (#77): Vite inlines every CSS-referenced woff2 in library mode, and
|
|
468
|
+
// `scripts/extract-icon-font.mjs` writes each back out as
|
|
469
|
+
// `dist/assets/<file>-<hash>.woff2`. A face downloads only when text actually
|
|
470
|
+
// renders in it. `swap` shows the fallback stack while the file loads rather
|
|
471
|
+
// than invisible text.
|
|
472
|
+
$dx-bundled-fonts: (
|
|
473
|
+
("Maven Pro", 400, "maven-pro/MavenPro-Regular"),
|
|
474
|
+
("Maven Pro", 500, "maven-pro/MavenPro-Medium"),
|
|
475
|
+
("Maven Pro", 600, "maven-pro/MavenPro-SemiBold"),
|
|
476
|
+
("Maven Pro", 700, "maven-pro/MavenPro-Bold"),
|
|
477
|
+
("Poppins", 500, "poppins/Poppins-Medium"),
|
|
478
|
+
("Poppins", 600, "poppins/Poppins-SemiBold"),
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
@each $family, $weight, $file in $dx-bundled-fonts {
|
|
482
|
+
@font-face {
|
|
483
|
+
font-family: $family;
|
|
484
|
+
font-style: normal;
|
|
485
|
+
font-weight: $weight;
|
|
486
|
+
font-display: swap;
|
|
487
|
+
src: url("../fonts/#{$file}.woff2") format("woff2");
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
:root {
|
|
492
|
+
--dx-font-family-display: #{$dx-font-family-display};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Bootstrap gives `$headings-font-family` to h1–h6; the display face is for
|
|
496
|
+
// h1–h4 only, so the two smallest headings stay in the body face.
|
|
497
|
+
h5,
|
|
498
|
+
.h5,
|
|
499
|
+
h6,
|
|
500
|
+
.h6 {
|
|
501
|
+
font-family: var(--bs-body-font-family);
|
|
502
|
+
}
|
|
503
|
+
|
|
271
504
|
// ----------------------------------------------------------------------------
|
|
272
505
|
// Forms
|
|
273
506
|
// ----------------------------------------------------------------------------
|
|
@@ -286,6 +519,18 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
286
519
|
--dx-input-height: calc(
|
|
287
520
|
#{$input-line-height * 1em} + #{$input-padding-y * 2} + (2 * #{$input-border-width})
|
|
288
521
|
);
|
|
522
|
+
--dx-form-label-width: #{$dx-form-label-width};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// The default horizontal label column. DXField renders it with BFormGroup's
|
|
526
|
+
// `labelColsSm` (so it is a `col-sm` that stacks below `sm`, as any `labelCols`
|
|
527
|
+
// breakpoint does) plus this modifier, which fixes its width; the input column
|
|
528
|
+
// is a plain `.col` and takes the rest. `.row >` lifts it over `.col-sm`.
|
|
529
|
+
@include media-breakpoint-up(sm) {
|
|
530
|
+
.row > .dx-field-label-col--default-width {
|
|
531
|
+
flex: 0 0 auto;
|
|
532
|
+
width: var(--dx-form-label-width);
|
|
533
|
+
}
|
|
289
534
|
}
|
|
290
535
|
|
|
291
536
|
// Bootstrap sizes grouped buttons with padding properties, but leaves their
|
|
@@ -317,6 +562,51 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
317
562
|
}
|
|
318
563
|
}
|
|
319
564
|
|
|
565
|
+
// A display-only value in a form row: a badge, a line of text, a short stack
|
|
566
|
+
// of lines. It has no input box, so on its own it sits at the top of the row
|
|
567
|
+
// while the label column (`.col-form-label`) is padded down to an input's text
|
|
568
|
+
// line. This gives it the same offset and line-height Bootstrap gives
|
|
569
|
+
// `.col-form-label` and `.form-control-plaintext`, so its FIRST line shares
|
|
570
|
+
// the label's centre. DXField wraps a `plaintext` field's `value` slot in it;
|
|
571
|
+
// consumers put it on their own display-only content. A `.form-control-
|
|
572
|
+
// plaintext` inside already carries the offset, so it drops its own.
|
|
573
|
+
.dx-form-plaintext {
|
|
574
|
+
padding-top: calc(#{$input-padding-y} + #{$input-border-width});
|
|
575
|
+
padding-bottom: calc(#{$input-padding-y} + #{$input-border-width});
|
|
576
|
+
line-height: $input-line-height;
|
|
577
|
+
|
|
578
|
+
> .form-control-plaintext {
|
|
579
|
+
padding-top: 0;
|
|
580
|
+
padding-bottom: 0;
|
|
581
|
+
border-top-width: 0;
|
|
582
|
+
border-bottom-width: 0;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// A badge is an inline-block in a smaller font, so neither `baseline` nor
|
|
586
|
+
// `middle` centres it on the line (both land ~2px off, the way depending on
|
|
587
|
+
// the font's x-height). Pin it to the line's top and push it down by half
|
|
588
|
+
// the spare height: the line is `$input-line-height` parent-ems, the badge
|
|
589
|
+
// is 1em (Bootstrap's `line-height: 1`) plus its padding, in badge-ems.
|
|
590
|
+
.badge {
|
|
591
|
+
vertical-align: top;
|
|
592
|
+
margin-top: calc(
|
|
593
|
+
(#{math.div($input-line-height, math.div($badge-font-size, 1em)) * 1em} - 1em - #{$badge-padding-y * 2}) / 2
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Switch-list option rows (DXField `switch-list`) are one line each: a label,
|
|
599
|
+
// a switch and an optional trailing control (a notes input in the
|
|
600
|
+
// `switch-list-item` slot). Centre all three in the row, instead of the
|
|
601
|
+
// top-aligned horizontal rhythm above, so the padded label column, the 24px
|
|
602
|
+
// switch and a taller input share one centre whether or not the input is
|
|
603
|
+
// showing. Comes after `.dx-form--horizontal .row` at the same specificity so
|
|
604
|
+
// it wins. The `.row` is bootstrap-vue-next's, inside the BFormGroup wrapper,
|
|
605
|
+
// so a utility class on the DFormGroup lands on the wrapper and does nothing.
|
|
606
|
+
.dx-switch-list-row .row {
|
|
607
|
+
align-items: center;
|
|
608
|
+
}
|
|
609
|
+
|
|
320
610
|
// Bootstrap's `.input-group` defaults to `flex-wrap: wrap`, letting a
|
|
321
611
|
// narrow container (e.g. a compact table cell, a small screen) stack the
|
|
322
612
|
// prepend/append affix onto its own line below the input. That breaks the
|
|
@@ -328,13 +618,44 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
328
618
|
flex-wrap: nowrap;
|
|
329
619
|
}
|
|
330
620
|
|
|
621
|
+
// DXNumberStepper: `[ − ][ 12 ][ + ]`. The buttons are DButton icon-only
|
|
622
|
+
// squares, sized by the input group. The number is centred between them, and
|
|
623
|
+
// the browser's spin arrows are hidden (they duplicate the buttons and push the
|
|
624
|
+
// number off centre). Global rather than scoped: the input is a bvn root, where
|
|
625
|
+
// a scoped rule is not reliably reached (see CLAUDE.md, scope-id trap).
|
|
626
|
+
// The input is a fixed few characters wide (the group is inline, so it does
|
|
627
|
+
// not stretch across a table cell); retune with `--dx-number-stepper-input-width`.
|
|
628
|
+
.dx-number-stepper {
|
|
629
|
+
display: inline-flex;
|
|
630
|
+
width: auto;
|
|
631
|
+
vertical-align: middle;
|
|
632
|
+
|
|
633
|
+
> .dx-number-stepper__input {
|
|
634
|
+
flex: 0 1 auto;
|
|
635
|
+
width: var(--dx-number-stepper-input-width, 6ch);
|
|
636
|
+
min-width: 4ch;
|
|
637
|
+
padding-left: 0.25rem;
|
|
638
|
+
padding-right: 0.25rem;
|
|
639
|
+
text-align: center;
|
|
640
|
+
-moz-appearance: textfield;
|
|
641
|
+
appearance: textfield;
|
|
642
|
+
|
|
643
|
+
&::-webkit-inner-spin-button,
|
|
644
|
+
&::-webkit-outer-spin-button {
|
|
645
|
+
-webkit-appearance: none;
|
|
646
|
+
margin: 0;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
331
651
|
// ----------------------------------------------------------------------------
|
|
332
652
|
// Nav tabs
|
|
333
653
|
// ----------------------------------------------------------------------------
|
|
334
654
|
// Chrome recedes, content leads — the same ethos as the muted table headers
|
|
335
655
|
// (#157). Bootstrap gives an INACTIVE tab `--bs-nav-link-color:
|
|
336
|
-
// var(--bs-link-color)`, i.e. the
|
|
337
|
-
//
|
|
656
|
+
// var(--bs-link-color)`, i.e. the link colour (brand navy, near-black), so
|
|
657
|
+
// every tab reads as selected and a row of tabs competes with the fields
|
|
658
|
+
// below. Mute the
|
|
338
659
|
// inactive tabs and let the ACTIVE one (Bootstrap's
|
|
339
660
|
// `--bs-nav-tabs-link-active-color`, the near-black emphasis colour) carry the
|
|
340
661
|
// selection on its own.
|
|
@@ -358,6 +679,22 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
358
679
|
// Dashboard Custom Styles
|
|
359
680
|
// ----------------------------------------------------------------------------
|
|
360
681
|
|
|
682
|
+
:root {
|
|
683
|
+
--dx-dashboard-gutter-x: #{$dashboard-gutter-x};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Both are the `DContainer fluid` directly inside the navbar header and the
|
|
687
|
+
// <main> panel (which keeps only its vertical padding, `py-4`). In the main
|
|
688
|
+
// panel's centred branch the DRow's negative margins and the DCol's padding
|
|
689
|
+
// cancel, so the content edge is this padding in both branches. Two classes
|
|
690
|
+
// so it outranks Bootstrap's own `.container-fluid` padding regardless of
|
|
691
|
+
// stylesheet order.
|
|
692
|
+
.dashboard-navbar > .container-fluid,
|
|
693
|
+
.dashboard-main > .container-fluid {
|
|
694
|
+
padding-left: var(--dx-dashboard-gutter-x);
|
|
695
|
+
padding-right: var(--dx-dashboard-gutter-x);
|
|
696
|
+
}
|
|
697
|
+
|
|
361
698
|
.dashboard-sidebar {
|
|
362
699
|
background-color: $dark;
|
|
363
700
|
width: $dashboard-sidebar-width;
|
|
@@ -519,12 +856,12 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
519
856
|
// the base `.toast` rule (above, and Bootstrap's own) already reads.
|
|
520
857
|
//
|
|
521
858
|
// Sourced from each variant's `soft-bg` in $dx-variants (#143) — the same
|
|
522
|
-
// vivid-derived soft family badges
|
|
859
|
+
// vivid-derived soft family badges use — so the toast hue tracks the
|
|
523
860
|
// palette and editing a `soft-bg` moves toasts too. Previously these mixed the
|
|
524
861
|
// dark *emphasis* base colours (greyer success/warning) and danger's saturated
|
|
525
862
|
// red (a pink, not the soft system's plum). Mixed 50% with white so a large
|
|
526
863
|
// toast surface stays fainter than a small badge while keeping the hue.
|
|
527
|
-
@each $name in ("success", "danger", "warning", "info") {
|
|
864
|
+
@each $name in ("success", "danger", "warning", "info", "pending") {
|
|
528
865
|
$variant: map.get($dx-variants, $name);
|
|
529
866
|
&.toast-#{$name} {
|
|
530
867
|
--bs-toast-bg: #{color.mix(map.get($variant, "soft-bg"), $white, 50%)};
|
|
@@ -542,9 +879,10 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
542
879
|
// active). secondary/success/danger/warning/info are SOFT (light tint bg +
|
|
543
880
|
// dark text, fully overridden incl. hover/active).
|
|
544
881
|
// - Outline buttons: the emphasis shade for border/label, the soft tint on hover.
|
|
882
|
+
// - Disabled buttons of every variant: the neutral grey set after this loop.
|
|
545
883
|
// - Badges: `.badge.text-bg-*` re-tinted soft — needs `!important` because
|
|
546
884
|
// Bootstrap's `.text-bg-*` helper sets its colours `!important` by design.
|
|
547
|
-
// - Alerts: the
|
|
885
|
+
// - Alerts: the SUBTLE tint (70% white) with the subtle border.
|
|
548
886
|
// - Links/text: `.link-*` and `.text-*` take the emphasis shade so they read
|
|
549
887
|
// on white (the base colours already carry emphasis for most variants; this
|
|
550
888
|
// pins the two — success/warning — whose base differs).
|
|
@@ -563,7 +901,6 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
563
901
|
--bs-btn-color: #{$solid-text};
|
|
564
902
|
--bs-btn-hover-color: #{$solid-text};
|
|
565
903
|
--bs-btn-active-color: #{$solid-text};
|
|
566
|
-
--bs-btn-disabled-color: #{$solid-text};
|
|
567
904
|
}
|
|
568
905
|
} @else {
|
|
569
906
|
// Soft button: light tint bg + dark same-hue label; darken the tint slightly
|
|
@@ -578,9 +915,6 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
578
915
|
--bs-btn-active-color: #{$soft-text};
|
|
579
916
|
--bs-btn-active-bg: #{color.scale($soft-bg, $lightness: -10%)};
|
|
580
917
|
--bs-btn-active-border-color: #{color.scale($soft-bg, $lightness: -10%)};
|
|
581
|
-
--bs-btn-disabled-color: #{$soft-text};
|
|
582
|
-
--bs-btn-disabled-bg: #{$soft-bg};
|
|
583
|
-
--bs-btn-disabled-border-color: #{$soft-bg};
|
|
584
918
|
}
|
|
585
919
|
}
|
|
586
920
|
|
|
@@ -621,20 +955,25 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
621
955
|
color: #{$soft-text} !important;
|
|
622
956
|
}
|
|
623
957
|
|
|
624
|
-
// Alert —
|
|
958
|
+
// Alert — the SUBTLE tint (the 70%-white mix), the subtle border and the
|
|
959
|
+
// soft text. Not the soft tint: warning's soft-bg is its full butter-yellow
|
|
960
|
+
// solid, so a soft warning alert was as loud as a solid fill, and an alert is
|
|
961
|
+
// a large surface. The border (the soft tint 10% darker, the same shade as
|
|
962
|
+
// `$X-border-subtle`) is what keeps the paler box visible against a white
|
|
963
|
+
// card. Badges, soft buttons and toasts keep their own tints.
|
|
625
964
|
.alert-#{$name} {
|
|
626
|
-
--bs-alert-bg: #{
|
|
965
|
+
--bs-alert-bg: #{dx-subtle-bg($name)};
|
|
627
966
|
--bs-alert-color: #{$soft-text};
|
|
628
|
-
--bs-alert-border-color: #{
|
|
967
|
+
--bs-alert-border-color: #{dx-subtle-border($name)};
|
|
629
968
|
--bs-alert-link-color: #{$emphasis};
|
|
630
969
|
}
|
|
631
970
|
|
|
632
971
|
// Progress bars — large FILLS use the vivid `solid-bg`, not the dark
|
|
633
|
-
// emphasis Bootstrap wires into `.bg-*` (#154). A big solid block of
|
|
634
|
-
// emphasis
|
|
635
|
-
// vivid fill is the same family as the switch
|
|
636
|
-
// bar read as one system.
|
|
637
|
-
//
|
|
972
|
+
// emphasis Bootstrap wires into `.bg-*` (#154). A big solid block of a
|
|
973
|
+
// deep emphasis shade reads muddy and clashes with the soft badge tint; the
|
|
974
|
+
// vivid fill is the same family as the switch colours, so badge + switch +
|
|
975
|
+
// bar read as one system. Every status variant's solid differs from its
|
|
976
|
+
// emphasis, so all four change hex here. The variant-less default bar
|
|
638
977
|
// stays `$progress-bar-bg` (brand navy). `!important` beats the `.bg-*`
|
|
639
978
|
// utility, which sets its colour `!important` by design.
|
|
640
979
|
//
|
|
@@ -655,9 +994,10 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
655
994
|
|
|
656
995
|
// Publish each variant's soft/emphasis shades as CSS variables so components
|
|
657
996
|
// (e.g. DXSwitch's on-box) and consumers can reference the exact soft-first
|
|
658
|
-
// tints on any element
|
|
659
|
-
//
|
|
660
|
-
//
|
|
997
|
+
// tints on any element. Bootstrap's own `--bs-*-bg-subtle` are now derived
|
|
998
|
+
// from these same tints (a 70%-white mix, set before the import), so they are
|
|
999
|
+
// a paler step of this family rather than a different one; use these when you
|
|
1000
|
+
// need the badge/alert tint itself. These are the values the $dx-variants loop paints.
|
|
661
1001
|
:root {
|
|
662
1002
|
@each $name, $v in $dx-variants {
|
|
663
1003
|
--dx-#{$name}-soft-bg: #{map.get($v, "soft-bg")};
|
|
@@ -694,6 +1034,11 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
694
1034
|
vertical-align: middle;
|
|
695
1035
|
}
|
|
696
1036
|
|
|
1037
|
+
// Column help uses the table's header colour rather than the form-label ink.
|
|
1038
|
+
.table > thead th .dx-field-label__text {
|
|
1039
|
+
color: inherit;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
697
1042
|
.table > thead {
|
|
698
1043
|
vertical-align: middle;
|
|
699
1044
|
}
|
|
@@ -740,17 +1085,70 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
740
1085
|
}
|
|
741
1086
|
}
|
|
742
1087
|
|
|
1088
|
+
// Disabled buttons: one neutral treatment whatever the variant. Bootstrap's is
|
|
1089
|
+
// opacity alone (0.65), so a disabled butter-yellow warning or lime success
|
|
1090
|
+
// button kept its colour and still looked pressable. Light grey fill, grey
|
|
1091
|
+
// label, full opacity; outline and link buttons keep no fill (grey border /
|
|
1092
|
+
// grey text). The label is #6c757d on #e9ecef, 3.95:1: disabled controls are
|
|
1093
|
+
// exempt from WCAG 1.4.3, but it stays readable. Bootstrap already sets
|
|
1094
|
+
// `pointer-events: none` on a disabled `.btn`, so there is no hover state and a
|
|
1095
|
+
// `cursor` would never show. Published as `--dx-btn-disabled-*` so a consumer
|
|
1096
|
+
// can retune all three together.
|
|
1097
|
+
$dx-btn-disabled-bg: #e9ecef; // $gray-200
|
|
1098
|
+
$dx-btn-disabled-color: #6c757d; // $gray-600
|
|
1099
|
+
$dx-btn-disabled-outline-border: #ced4da; // $gray-400
|
|
1100
|
+
|
|
1101
|
+
:root {
|
|
1102
|
+
--dx-btn-disabled-bg: #{$dx-btn-disabled-bg};
|
|
1103
|
+
--dx-btn-disabled-color: #{$dx-btn-disabled-color};
|
|
1104
|
+
--dx-btn-disabled-outline-border: #{$dx-btn-disabled-outline-border};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Drives Bootstrap's own `--bs-btn-disabled-*` variables, which its
|
|
1108
|
+
// `.btn:disabled` rule paints. Two classes (or `fieldset:disabled .btn`) so it
|
|
1109
|
+
// outranks the per-variant `.btn-*` rules that set the same variables.
|
|
1110
|
+
.btn:is(:disabled, .disabled),
|
|
1111
|
+
fieldset:disabled .btn {
|
|
1112
|
+
--bs-btn-disabled-opacity: 1;
|
|
1113
|
+
--bs-btn-disabled-bg: var(--dx-btn-disabled-bg);
|
|
1114
|
+
--bs-btn-disabled-color: var(--dx-btn-disabled-color);
|
|
1115
|
+
--bs-btn-disabled-border-color: var(--dx-btn-disabled-bg);
|
|
1116
|
+
|
|
1117
|
+
&:is([class*="btn-outline-"]) {
|
|
1118
|
+
--bs-btn-disabled-bg: transparent;
|
|
1119
|
+
--bs-btn-disabled-border-color: var(--dx-btn-disabled-outline-border);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
&.btn-link {
|
|
1123
|
+
--bs-btn-disabled-bg: transparent;
|
|
1124
|
+
--bs-btn-disabled-border-color: transparent;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// The one exception: DXSaveButton's saved state ("✓ Saved") is a REAL
|
|
1129
|
+
// disabled button, but it is a confirmation, not an unavailable action, so it
|
|
1130
|
+
// keeps its variant's own colours (by default the navy primary fill, #151e2d /
|
|
1131
|
+
// #e9f0f8) at full opacity rather than the neutral grey above, so saving
|
|
1132
|
+
// changes the label and the disabled state but not the colour. Three classes
|
|
1133
|
+
// plus the state, so it outranks the neutral rule (and `fieldset:disabled .btn`).
|
|
1134
|
+
.btn.dx-save-button--saved:is(:disabled, .disabled) {
|
|
1135
|
+
--bs-btn-disabled-opacity: 1;
|
|
1136
|
+
--bs-btn-disabled-bg: var(--bs-btn-bg);
|
|
1137
|
+
--bs-btn-disabled-color: var(--bs-btn-color);
|
|
1138
|
+
--bs-btn-disabled-border-color: var(--bs-btn-border-color);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
743
1141
|
// ----------------------------------------------------------------------------
|
|
744
1142
|
// Dropdowns — chevron caret (B14 / PO5)
|
|
745
1143
|
// ----------------------------------------------------------------------------
|
|
746
1144
|
// Bootstrap's `.dropdown-toggle::after` is a CSS border-triangle that sits high
|
|
747
|
-
// against
|
|
1145
|
+
// against the body font's line box and reads crude next to the rest of the theme.
|
|
748
1146
|
// Replace it with the bootstrap-icons chevron glyph, optically centred with a
|
|
749
1147
|
// little breathing room from the label. The font is already available: the
|
|
750
1148
|
// theme `@import`s `bootstrap-icons/font/bootstrap-icons` (declaring the
|
|
751
1149
|
// `@font-face`), and #77's post-build extraction ships that woff2 with the
|
|
752
1150
|
// stylesheet — so this needs no new dependency and no data-URI. Values signed
|
|
753
|
-
// off after one padding iteration in the
|
|
1151
|
+
// off after one padding iteration in the interim UI; the glyph metrics
|
|
754
1152
|
// are tunable via the variables below.
|
|
755
1153
|
$dx-dropdown-caret-size: 0.75em; // glyph size relative to the label
|
|
756
1154
|
$dx-dropdown-caret-gap: 0.4em; // space between label and chevron
|
|
@@ -770,10 +1168,10 @@ $dx-dropdown-caret-shift: 0.05em; // vertical nudge for optical centring
|
|
|
770
1168
|
}
|
|
771
1169
|
|
|
772
1170
|
// ----------------------------------------------------------------------------
|
|
773
|
-
// Switches — green when ON,
|
|
1171
|
+
// Switches — green when ON, magenta (danger) when OFF, by default (#158)
|
|
774
1172
|
// ----------------------------------------------------------------------------
|
|
775
1173
|
// House style (James): an active switch — "Product is current", "Stock is
|
|
776
|
-
// tracked", "Visible" — should read success GREEN when on and
|
|
1174
|
+
// tracked", "Visible" — should read success GREEN when on and danger when off,
|
|
777
1175
|
// OUT OF THE BOX, not only when a consumer opts in. Bootstrap's default is a
|
|
778
1176
|
// primary (navy) track when on / grey when off. We flip the default here.
|
|
779
1177
|
//
|
|
@@ -784,19 +1182,22 @@ $dx-dropdown-caret-shift: 0.05em; // vertical nudge for optical centring
|
|
|
784
1182
|
// Applies to any bare `.form-switch` (DFormCheckbox `switch`); DXSwitch is the
|
|
785
1183
|
// "filled box" form where the whole control (not the toggle) carries the colour
|
|
786
1184
|
// and the pill stays a neutral affordance — it reads the same tokens below.
|
|
787
|
-
$dx-switch-on: map.get(map.get($dx-variants, "success"), "solid-bg"); // vivid lime
|
|
788
|
-
$dx-switch-off: map.get(map.get($dx-variants, "danger"), "solid-bg"); // vivid
|
|
1185
|
+
$dx-switch-on: map.get(map.get($dx-variants, "success"), "solid-bg"); // vivid lime #7bf25a
|
|
1186
|
+
$dx-switch-off: map.get(map.get($dx-variants, "danger"), "solid-bg"); // vivid magenta #e46ab9
|
|
789
1187
|
$dx-switch-thumb-white: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
|
|
790
|
-
// A
|
|
791
|
-
|
|
1188
|
+
// A coloured thumb reads better than white on the light OFF track. Its fill is
|
|
1189
|
+
// the danger EMPHASIS (#a3247f) — an SVG data URI can't take a Sass variable
|
|
1190
|
+
// without string surgery, so keep this literal in step with $dx-variants.
|
|
1191
|
+
$dx-switch-thumb-off: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23a3247f'/%3e%3c/svg%3e");
|
|
792
1192
|
|
|
793
1193
|
// Switch fill tokens. The ON fill is the SAME soft green as the success
|
|
794
1194
|
// badge/button (its `soft-bg`), so a switch and a success badge read as one
|
|
795
|
-
// green — not a separate, punchier lime. OFF is a LIGHT
|
|
796
|
-
//
|
|
797
|
-
//
|
|
798
|
-
// one edit moves them. Used by the DXSwitch filled box; the OFF track
|
|
799
|
-
|
|
1195
|
+
// green — not a separate, punchier lime. OFF is a LIGHT magenta: a 20% tint of
|
|
1196
|
+
// the danger solid (mixed here rather than the danger `soft-bg`, so the
|
|
1197
|
+
// track's well/line/ink steps all come from one hue). Derived from the base
|
|
1198
|
+
// tokens so one edit moves them. Used by the DXSwitch filled box; the OFF track
|
|
1199
|
+
// reuses them.
|
|
1200
|
+
$dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #c3faaa
|
|
800
1201
|
:root {
|
|
801
1202
|
--dx-switch-on-bg: #{$dx-switch-on-soft};
|
|
802
1203
|
--dx-switch-on-well: #{color.mix($dx-switch-on-soft, #fff, 55%)};
|
|
@@ -806,30 +1207,23 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
806
1207
|
--dx-switch-off-well: #{color.mix($dx-switch-off, #fff, 10%)};
|
|
807
1208
|
--dx-switch-off-line: #{color.mix($dx-switch-off, #fff, 45%)};
|
|
808
1209
|
--dx-switch-off-ink: #{color.mix($dx-switch-off, #000, 30%)};
|
|
809
|
-
--dx-switch-pill: var(--bs-gray-400, #ced4da);
|
|
1210
|
+
--dx-switch-pill: var(--bs-gray-400, #ced4da);
|
|
1211
|
+
--dx-switch-off-pill: #{color.mix(map.get(map.get($dx-variants, "danger"), "soft-text"), $gray-400, 50%)};
|
|
810
1212
|
--dx-switch-on-pill: #{color.mix(map.get(map.get($dx-variants, "success"), "soft-text"), $gray-400, 50%)};
|
|
811
1213
|
}
|
|
812
1214
|
|
|
813
|
-
//
|
|
814
|
-
//
|
|
815
|
-
//
|
|
816
|
-
// reads visibly HIGH beside the text (same optical-metrics issue as the B14
|
|
817
|
-
// dropdown caret). `0.325em` lands the box centre on Poppins' visual centre —
|
|
818
|
-
// judged against a rendered filmstrip (0.25/0.30/0.325/0.35em) with Poppins
|
|
819
|
-
// loaded, not from the maths. A top MARGIN (not flex-centring) is deliberate:
|
|
820
|
-
// it aligns to the first line, so a multi-line label keeps the box on line one
|
|
821
|
-
// rather than floating to the block's vertical centre. DXSwitch is unaffected —
|
|
822
|
-
// it flex-centres and zeroes this margin on its inner input at higher
|
|
823
|
-
// specificity (`.dx-switch :deep(.form-check-input) { margin: 0 }`).
|
|
1215
|
+
// Centre checkboxes/radios on the first label line using their actual size.
|
|
1216
|
+
// The old em offset assumed a 1em box; these controls are now 1.25rem tall.
|
|
1217
|
+
// A margin keeps wrapped labels aligned to line one rather than the whole block.
|
|
824
1218
|
.form-check-input {
|
|
825
|
-
margin-top:
|
|
1219
|
+
margin-top: calc((1lh - #{$form-check-input-width}) / 2);
|
|
826
1220
|
}
|
|
827
1221
|
|
|
828
1222
|
.form-switch .form-check-input {
|
|
829
|
-
// OFF: light-
|
|
1223
|
+
// OFF: light-magenta track, deep-magenta thumb (left).
|
|
830
1224
|
background-color: var(--dx-switch-off-bg);
|
|
831
1225
|
border-color: var(--dx-switch-off-line);
|
|
832
|
-
--bs-form-switch-bg: #{$dx-switch-thumb-
|
|
1226
|
+
--bs-form-switch-bg: #{$dx-switch-thumb-off};
|
|
833
1227
|
|
|
834
1228
|
&:checked {
|
|
835
1229
|
// ON: vivid green track, white thumb (right — Bootstrap positions it).
|
|
@@ -841,7 +1235,7 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
841
1235
|
// Neutral grey focus ring (the track carries the state colour, so the brand
|
|
842
1236
|
// navy ring would clash); keep the state thumb rather than Bootstrap's navy.
|
|
843
1237
|
&:focus {
|
|
844
|
-
--bs-form-switch-bg: #{$dx-switch-thumb-
|
|
1238
|
+
--bs-form-switch-bg: #{$dx-switch-thumb-off};
|
|
845
1239
|
border-color: var(--dx-switch-off-line);
|
|
846
1240
|
box-shadow: 0 0 0 0.25rem rgba($dark, 0.15);
|
|
847
1241
|
}
|
|
@@ -875,59 +1269,86 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
875
1269
|
// ----------------------------------------------------------------------------
|
|
876
1270
|
// Chart palette (data-viz)
|
|
877
1271
|
// ----------------------------------------------------------------------------
|
|
878
|
-
// Dedicated categorical palette for the DX*Chart components —
|
|
879
|
-
// the semantic
|
|
1272
|
+
// Dedicated categorical palette for the DX*Chart components — its own lists,
|
|
1273
|
+
// NOT the semantic `--bs-*` variables (#141): the base $theme-colors carry
|
|
880
1274
|
// dark "emphasis" shades (AA text/link colours, too muted for data series), and
|
|
881
|
-
//
|
|
882
|
-
//
|
|
1275
|
+
// a series colour must not move when a status colour is retuned. The fills do
|
|
1276
|
+
// share the fruity family's hues (slots 1/2/3/6 are the info/success/danger/
|
|
1277
|
+
// warning solids) so charts and badges read as one system; the order, not the
|
|
1278
|
+
// status meaning, is what the slots encode.
|
|
1279
|
+
//
|
|
1280
|
+
// Eight light, vivid FILLS in a FIXED order, plus a darker LINE shade per slot
|
|
1281
|
+
// and one EDGE colour. The fills are light (1.35–2.97:1 on white), so they
|
|
1282
|
+
// cannot carry WCAG 1.4.11 non-text contrast on their own; that job goes to:
|
|
1283
|
+
// - the EDGE: bars and doughnut segments get a 1px near-black outline
|
|
1284
|
+
// (#121419, the warning label ink; 18.42:1 on white), which separates each
|
|
1285
|
+
// mark from the white page and from its neighbours whatever the fill;
|
|
1286
|
+
// - the LINE shades: each fill darkened toward black (same hue) until it
|
|
1287
|
+
// clears 3.5:1 on white. Line strokes and point outlines use them; the
|
|
1288
|
+
// fill only shows as point centres and a 35% area wash.
|
|
883
1289
|
//
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
//
|
|
888
|
-
//
|
|
889
|
-
//
|
|
1290
|
+
// The order is load-bearing: slot 1 is pinned and slots 2..8 were chosen by
|
|
1291
|
+
// exhaustive permutation to maximise the minimum adjacent-pair separation
|
|
1292
|
+
// under colour-vision deficiency (OKLab ΔE ×100, Viénot protan/deutan). The
|
|
1293
|
+
// shipped order is the best available for both lists: fills min adjacent CVD
|
|
1294
|
+
// ΔE 19.56, lines 13.73 (weakest neighbours: the magenta and olive line
|
|
1295
|
+
// shades, slots 3/4). Min adjacent normal-vision ΔE: fills 21.41, lines 16.63.
|
|
1296
|
+
// Reordering, swapping a hue, or editing a line shade needs the validation
|
|
1297
|
+
// re-run, not an eyeball: `node scripts/validate-chart-palette.mjs` reads these
|
|
1298
|
+
// lists from this file, prints the scores, and checks every line shade is its
|
|
1299
|
+
// fill darkened to 3.5:1.
|
|
890
1300
|
//
|
|
891
|
-
// Published as --dx-chart-1..8
|
|
892
|
-
//
|
|
893
|
-
//
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
//
|
|
901
|
-
//
|
|
902
|
-
// 5.67–10.23:1
|
|
1301
|
+
// Published as --dx-chart-1..8 (fills), --dx-chart-line-1..8 and
|
|
1302
|
+
// --dx-chart-edge so consumers can retheme charts by overriding the
|
|
1303
|
+
// variables; chartTheme.ts reads them at runtime (with these hexes as
|
|
1304
|
+
// fallbacks for SSR / missing-CSS cases — keep the lists in sync; the sync is
|
|
1305
|
+
// enforced by tests/components/charts.test.ts, which parses this file).
|
|
1306
|
+
$dx-chart-palette: (#7fd7fd, #7bf25a, #e46ab9, #d6e86a, #b9a3f0, #efd574, #9fb4ff, #f7a072);
|
|
1307
|
+
$dx-chart-line-palette: (#5590aa, #4d9839, #d161a9, #848f41, #907fbb, #99884a, #7686be, #ba7956);
|
|
1308
|
+
$dx-chart-edge: #121419;
|
|
1309
|
+
|
|
1310
|
+
// Dark-surface remap (#145). The dark set predates the light fills above and
|
|
1311
|
+
// is unchanged: mid-lightness hues that already clear 3:1 on Bootstrap's dark
|
|
1312
|
+
// body (#212529) — 5.67–10.23:1 — so in dark mode the fills ARE the line
|
|
1313
|
+
// shades, and the edge is the dark body colour itself (an invisible 1px
|
|
1314
|
+
// separator between segments, as before the light edge existed). Validated
|
|
1315
|
+
// with the same method: min adjacent CVD ΔE 15.09, min adjacent normal ΔE
|
|
1316
|
+
// 25.33. Swapping a step needs that validation re-run.
|
|
903
1317
|
// getPalette() reads these CSS variables live — off the CHART'S OWN container,
|
|
904
1318
|
// so nested colour-mode scopes resolve correctly, and re-read on every
|
|
905
1319
|
// `data-bs-theme` change so mounted charts repaint (#161). The TS fallbacks
|
|
906
1320
|
// stay the light set (SSR/no-CSS default).
|
|
907
1321
|
$dx-chart-palette-dark: (#60a5fa, #a3e635, #a78bfa, #2dd4bf, #fb923c, #22d3ee, #fbbf24, #f472b6);
|
|
1322
|
+
$dx-chart-edge-dark: $body-bg-dark;
|
|
908
1323
|
|
|
909
|
-
|
|
1324
|
+
@mixin dx-chart-light-vars {
|
|
910
1325
|
@for $i from 1 through list.length($dx-chart-palette) {
|
|
911
1326
|
--dx-chart-#{$i}: #{list.nth($dx-chart-palette, $i)};
|
|
1327
|
+
--dx-chart-line-#{$i}: #{list.nth($dx-chart-line-palette, $i)};
|
|
912
1328
|
}
|
|
1329
|
+
--dx-chart-edge: #{$dx-chart-edge};
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
:root {
|
|
1333
|
+
@include dx-chart-light-vars;
|
|
913
1334
|
}
|
|
914
1335
|
|
|
915
1336
|
[data-bs-theme="dark"] {
|
|
916
1337
|
@for $i from 1 through list.length($dx-chart-palette-dark) {
|
|
917
1338
|
--dx-chart-#{$i}: #{list.nth($dx-chart-palette-dark, $i)};
|
|
1339
|
+
--dx-chart-line-#{$i}: #{list.nth($dx-chart-palette-dark, $i)};
|
|
918
1340
|
}
|
|
1341
|
+
--dx-chart-edge: #{$dx-chart-edge-dark};
|
|
919
1342
|
}
|
|
920
1343
|
|
|
921
1344
|
// Bootstrap allows `data-bs-theme` on ANY container, so colour-mode scopes
|
|
922
1345
|
// nest — and custom properties inherit. Without this re-declaration a LIGHT
|
|
923
1346
|
// scope inside a dark root (a light card on a dark page) would inherit the dark
|
|
924
1347
|
// palette, because only `:root` publishes the light values and the dark block
|
|
925
|
-
// above overrides it for the whole subtree (#161). Same
|
|
926
|
-
// two can't drift.
|
|
1348
|
+
// above overrides it for the whole subtree (#161). Same mixin as `:root`, so
|
|
1349
|
+
// the two can't drift.
|
|
927
1350
|
[data-bs-theme="light"] {
|
|
928
|
-
@
|
|
929
|
-
--dx-chart-#{$i}: #{list.nth($dx-chart-palette, $i)};
|
|
930
|
-
}
|
|
1351
|
+
@include dx-chart-light-vars;
|
|
931
1352
|
}
|
|
932
1353
|
|
|
933
1354
|
// The chart container used by DXBarChart/DXLineChart/DXDoughnutChart (shipped
|