@omnitend/dashboard-for-laravel 0.41.2 → 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/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/DXNumberStepper.vue.d.ts +33 -0
- package/dist/components/extended/DXSaveButton.vue.d.ts +38 -0
- package/dist/components/extended/DXTable.vue.d.ts +6 -2
- package/dist/composables/useForm.d.ts +7 -0
- package/dist/dashboard-for-laravel.js +9369 -9133
- 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 +2 -0
- package/dist/style.css +2 -2
- package/dist/types/index.d.ts +20 -3
- package/docs/public/api-reference.json +165 -14
- package/docs/public/docs-map.md +4 -2
- package/docs/public/llms.txt +4 -2
- package/package.json +1 -1
- package/resources/css/theme.scss +512 -89
- 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/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/DXNumberStepper.vue +243 -0
- package/resources/js/components/extended/DXSaveButton.vue +82 -0
- package/resources/js/components/extended/DXTable.vue +44 -15
- package/resources/js/composables/useForm.ts +11 -0
- package/resources/js/composables/useToast.ts +1 -1
- package/resources/js/index.ts +2 -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"),
|
|
197
240
|
);
|
|
198
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,
|
|
315
|
+
);
|
|
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")};
|
|
@@ -745,11 +1085,64 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
745
1085
|
}
|
|
746
1086
|
}
|
|
747
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
|
+
|
|
748
1141
|
// ----------------------------------------------------------------------------
|
|
749
1142
|
// Dropdowns — chevron caret (B14 / PO5)
|
|
750
1143
|
// ----------------------------------------------------------------------------
|
|
751
1144
|
// Bootstrap's `.dropdown-toggle::after` is a CSS border-triangle that sits high
|
|
752
|
-
// against
|
|
1145
|
+
// against the body font's line box and reads crude next to the rest of the theme.
|
|
753
1146
|
// Replace it with the bootstrap-icons chevron glyph, optically centred with a
|
|
754
1147
|
// little breathing room from the label. The font is already available: the
|
|
755
1148
|
// theme `@import`s `bootstrap-icons/font/bootstrap-icons` (declaring the
|
|
@@ -775,10 +1168,10 @@ $dx-dropdown-caret-shift: 0.05em; // vertical nudge for optical centring
|
|
|
775
1168
|
}
|
|
776
1169
|
|
|
777
1170
|
// ----------------------------------------------------------------------------
|
|
778
|
-
// Switches — green when ON,
|
|
1171
|
+
// Switches — green when ON, magenta (danger) when OFF, by default (#158)
|
|
779
1172
|
// ----------------------------------------------------------------------------
|
|
780
1173
|
// House style (James): an active switch — "Product is current", "Stock is
|
|
781
|
-
// tracked", "Visible" — should read success GREEN when on and
|
|
1174
|
+
// tracked", "Visible" — should read success GREEN when on and danger when off,
|
|
782
1175
|
// OUT OF THE BOX, not only when a consumer opts in. Bootstrap's default is a
|
|
783
1176
|
// primary (navy) track when on / grey when off. We flip the default here.
|
|
784
1177
|
//
|
|
@@ -789,19 +1182,22 @@ $dx-dropdown-caret-shift: 0.05em; // vertical nudge for optical centring
|
|
|
789
1182
|
// Applies to any bare `.form-switch` (DFormCheckbox `switch`); DXSwitch is the
|
|
790
1183
|
// "filled box" form where the whole control (not the toggle) carries the colour
|
|
791
1184
|
// and the pill stays a neutral affordance — it reads the same tokens below.
|
|
792
|
-
$dx-switch-on: map.get(map.get($dx-variants, "success"), "solid-bg"); // vivid lime
|
|
793
|
-
$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
|
|
794
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");
|
|
795
|
-
// A
|
|
796
|
-
|
|
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");
|
|
797
1192
|
|
|
798
1193
|
// Switch fill tokens. The ON fill is the SAME soft green as the success
|
|
799
1194
|
// badge/button (its `soft-bg`), so a switch and a success badge read as one
|
|
800
|
-
// green — not a separate, punchier lime. OFF is a LIGHT
|
|
801
|
-
//
|
|
802
|
-
//
|
|
803
|
-
// one edit moves them. Used by the DXSwitch filled box; the OFF track
|
|
804
|
-
|
|
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
|
|
805
1201
|
:root {
|
|
806
1202
|
--dx-switch-on-bg: #{$dx-switch-on-soft};
|
|
807
1203
|
--dx-switch-on-well: #{color.mix($dx-switch-on-soft, #fff, 55%)};
|
|
@@ -824,10 +1220,10 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
824
1220
|
}
|
|
825
1221
|
|
|
826
1222
|
.form-switch .form-check-input {
|
|
827
|
-
// OFF: light-
|
|
1223
|
+
// OFF: light-magenta track, deep-magenta thumb (left).
|
|
828
1224
|
background-color: var(--dx-switch-off-bg);
|
|
829
1225
|
border-color: var(--dx-switch-off-line);
|
|
830
|
-
--bs-form-switch-bg: #{$dx-switch-thumb-
|
|
1226
|
+
--bs-form-switch-bg: #{$dx-switch-thumb-off};
|
|
831
1227
|
|
|
832
1228
|
&:checked {
|
|
833
1229
|
// ON: vivid green track, white thumb (right — Bootstrap positions it).
|
|
@@ -839,7 +1235,7 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
839
1235
|
// Neutral grey focus ring (the track carries the state colour, so the brand
|
|
840
1236
|
// navy ring would clash); keep the state thumb rather than Bootstrap's navy.
|
|
841
1237
|
&:focus {
|
|
842
|
-
--bs-form-switch-bg: #{$dx-switch-thumb-
|
|
1238
|
+
--bs-form-switch-bg: #{$dx-switch-thumb-off};
|
|
843
1239
|
border-color: var(--dx-switch-off-line);
|
|
844
1240
|
box-shadow: 0 0 0 0.25rem rgba($dark, 0.15);
|
|
845
1241
|
}
|
|
@@ -873,59 +1269,86 @@ $dx-switch-on-soft: map.get(map.get($dx-variants, "success"), "soft-bg"); // #cd
|
|
|
873
1269
|
// ----------------------------------------------------------------------------
|
|
874
1270
|
// Chart palette (data-viz)
|
|
875
1271
|
// ----------------------------------------------------------------------------
|
|
876
|
-
// Dedicated categorical palette for the DX*Chart components —
|
|
877
|
-
// 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
|
|
878
1274
|
// dark "emphasis" shades (AA text/link colours, too muted for data series), and
|
|
879
|
-
//
|
|
880
|
-
//
|
|
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.
|
|
881
1289
|
//
|
|
882
|
-
//
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
//
|
|
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.
|
|
888
1300
|
//
|
|
889
|
-
// Published as --dx-chart-1..8
|
|
890
|
-
//
|
|
891
|
-
//
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
//
|
|
899
|
-
//
|
|
900
|
-
// 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.
|
|
901
1317
|
// getPalette() reads these CSS variables live — off the CHART'S OWN container,
|
|
902
1318
|
// so nested colour-mode scopes resolve correctly, and re-read on every
|
|
903
1319
|
// `data-bs-theme` change so mounted charts repaint (#161). The TS fallbacks
|
|
904
1320
|
// stay the light set (SSR/no-CSS default).
|
|
905
1321
|
$dx-chart-palette-dark: (#60a5fa, #a3e635, #a78bfa, #2dd4bf, #fb923c, #22d3ee, #fbbf24, #f472b6);
|
|
1322
|
+
$dx-chart-edge-dark: $body-bg-dark;
|
|
906
1323
|
|
|
907
|
-
|
|
1324
|
+
@mixin dx-chart-light-vars {
|
|
908
1325
|
@for $i from 1 through list.length($dx-chart-palette) {
|
|
909
1326
|
--dx-chart-#{$i}: #{list.nth($dx-chart-palette, $i)};
|
|
1327
|
+
--dx-chart-line-#{$i}: #{list.nth($dx-chart-line-palette, $i)};
|
|
910
1328
|
}
|
|
1329
|
+
--dx-chart-edge: #{$dx-chart-edge};
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
:root {
|
|
1333
|
+
@include dx-chart-light-vars;
|
|
911
1334
|
}
|
|
912
1335
|
|
|
913
1336
|
[data-bs-theme="dark"] {
|
|
914
1337
|
@for $i from 1 through list.length($dx-chart-palette-dark) {
|
|
915
1338
|
--dx-chart-#{$i}: #{list.nth($dx-chart-palette-dark, $i)};
|
|
1339
|
+
--dx-chart-line-#{$i}: #{list.nth($dx-chart-palette-dark, $i)};
|
|
916
1340
|
}
|
|
1341
|
+
--dx-chart-edge: #{$dx-chart-edge-dark};
|
|
917
1342
|
}
|
|
918
1343
|
|
|
919
1344
|
// Bootstrap allows `data-bs-theme` on ANY container, so colour-mode scopes
|
|
920
1345
|
// nest — and custom properties inherit. Without this re-declaration a LIGHT
|
|
921
1346
|
// scope inside a dark root (a light card on a dark page) would inherit the dark
|
|
922
1347
|
// palette, because only `:root` publishes the light values and the dark block
|
|
923
|
-
// above overrides it for the whole subtree (#161). Same
|
|
924
|
-
// two can't drift.
|
|
1348
|
+
// above overrides it for the whole subtree (#161). Same mixin as `:root`, so
|
|
1349
|
+
// the two can't drift.
|
|
925
1350
|
[data-bs-theme="light"] {
|
|
926
|
-
@
|
|
927
|
-
--dx-chart-#{$i}: #{list.nth($dx-chart-palette, $i)};
|
|
928
|
-
}
|
|
1351
|
+
@include dx-chart-light-vars;
|
|
929
1352
|
}
|
|
930
1353
|
|
|
931
1354
|
// The chart container used by DXBarChart/DXLineChart/DXDoughnutChart (shipped
|