@omnitend/dashboard-for-laravel 0.18.1 → 0.19.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/dist/components/extended/DXField.vue.d.ts +50 -35
- package/dist/dashboard-for-laravel.js +5627 -5579
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +5 -5
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/style.css +2 -2
- package/package.json +1 -1
- package/resources/css/theme.scss +40 -1
- package/resources/js/components/extended/DXDashboard.vue +3 -0
- package/resources/js/components/extended/DXDashboardNavbar.vue +1 -1
- package/resources/js/components/extended/DXField.vue +72 -14
- package/resources/js/components/extended/DXFieldLabel.vue +7 -0
- package/resources/js/components/extended/DXForm.vue +4 -1
package/package.json
CHANGED
package/resources/css/theme.scss
CHANGED
|
@@ -79,13 +79,18 @@ $btn-padding-x-lg: 1.5rem; // 24px
|
|
|
79
79
|
// Forms
|
|
80
80
|
// ----------------------------------------------------------------------------
|
|
81
81
|
|
|
82
|
-
$input-padding-y: 0.625rem
|
|
82
|
+
$input-padding-y: 0.375rem; // compact fields (Bootstrap's default; 0.625rem read oversized)
|
|
83
83
|
$input-padding-x: 1rem;
|
|
84
84
|
$input-border-radius: $border-radius;
|
|
85
85
|
$input-border-color: #d1d5db; // Gray-300
|
|
86
86
|
$input-focus-border-color: $primary;
|
|
87
87
|
$input-focus-box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
88
88
|
|
|
89
|
+
// Check/radio inputs default their border to `$border-color` (Gray-200), not
|
|
90
|
+
// `$input-border-color` — so a bare checkbox looks faint beside the (darker,
|
|
91
|
+
// Gray-300) text inputs. Share the input border colour across all controls.
|
|
92
|
+
$form-check-input-border: 1px solid $input-border-color;
|
|
93
|
+
|
|
89
94
|
// ----------------------------------------------------------------------------
|
|
90
95
|
// Cards
|
|
91
96
|
// ----------------------------------------------------------------------------
|
|
@@ -188,6 +193,36 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
188
193
|
);
|
|
189
194
|
}
|
|
190
195
|
|
|
196
|
+
// Bigger check/radio boxes — Bootstrap's 1em default reads small next to the
|
|
197
|
+
// theme's inputs and is a fiddly touch target.
|
|
198
|
+
.form-check-input {
|
|
199
|
+
width: 1.25rem;
|
|
200
|
+
height: 1.25rem;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Horizontal ("label-left") forms: a compact settings-form rhythm, with the
|
|
204
|
+
// label + control top-aligned so a checkbox/switch sits on the label's first
|
|
205
|
+
// line rather than floating above it (the label column carries a top offset to
|
|
206
|
+
// line up with text inputs; the checkbox is given the same offset). Vertical
|
|
207
|
+
// forms are unaffected.
|
|
208
|
+
.dx-form--horizontal {
|
|
209
|
+
.row {
|
|
210
|
+
align-items: flex-start;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.col-form-label {
|
|
214
|
+
padding-top: 0.4rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.form-check {
|
|
218
|
+
margin-top: 0.4rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.mb-3 {
|
|
222
|
+
margin-bottom: 0.5rem;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
191
226
|
// Bootstrap's `.input-group` defaults to `flex-wrap: wrap`, letting a
|
|
192
227
|
// narrow container (e.g. a compact table cell, a small screen) stack the
|
|
193
228
|
// prepend/append affix onto its own line below the input. That breaks the
|
|
@@ -243,6 +278,10 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
243
278
|
|
|
244
279
|
.dashboard-navbar {
|
|
245
280
|
height: $dashboard-navbar-height;
|
|
281
|
+
// A light grey top bar over the white content panel (higher contrast than a
|
|
282
|
+
// grey-everywhere layout). The navbar markup drops its `bg-white` class so
|
|
283
|
+
// this wins without `!important`.
|
|
284
|
+
background-color: #f8f9fa;
|
|
246
285
|
}
|
|
247
286
|
|
|
248
287
|
// ----------------------------------------------------------------------------
|
|
@@ -247,5 +247,8 @@ const toggleSidebar = () => {
|
|
|
247
247
|
.dashboard-main {
|
|
248
248
|
flex: 1;
|
|
249
249
|
max-width: 100%;
|
|
250
|
+
/* A white content panel under the light grey top bar / layout, so forms and
|
|
251
|
+
content sit on white (higher contrast than a grey-everywhere dashboard). */
|
|
252
|
+
background-color: #fff;
|
|
250
253
|
}
|
|
251
254
|
</style>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
`DXDashboard`, which forwards these slots with a `navbar-` prefix.
|
|
6
6
|
-->
|
|
7
7
|
<template>
|
|
8
|
-
<header class="dashboard-navbar
|
|
8
|
+
<header class="dashboard-navbar border-bottom">
|
|
9
9
|
<DContainer fluid>
|
|
10
10
|
<!-- Flex bar that wraps: below `md` the search drops to its own
|
|
11
11
|
full-width row beneath the toggle/title/user-menu row. -->
|
|
@@ -35,11 +35,20 @@
|
|
|
35
35
|
:class="field.class || 'mb-3'"
|
|
36
36
|
v-bind="horizontalAttrs"
|
|
37
37
|
>
|
|
38
|
-
<!-- The
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
<!-- The row label (left column) names the control; the checkbox's own
|
|
39
|
+
label is kept for screen readers but hidden visually so it doesn't
|
|
40
|
+
duplicate the row label. In horizontal layout the hint sits beneath
|
|
41
|
+
the label here rather than below the control. -->
|
|
41
42
|
<template v-if="!hideLabel" #label>
|
|
42
43
|
<DXFieldLabel :label="resolvedLabel" :info="resolvedInfo" />
|
|
44
|
+
<small
|
|
45
|
+
v-if="isHorizontal && (resolvedHint || $slots.hint)"
|
|
46
|
+
class="form-text text-muted d-block dx-field-hint"
|
|
47
|
+
>
|
|
48
|
+
<slot name="hint" :field="field" :model="model">{{
|
|
49
|
+
resolvedHint
|
|
50
|
+
}}</slot>
|
|
51
|
+
</small>
|
|
43
52
|
</template>
|
|
44
53
|
<slot
|
|
45
54
|
v-if="$slots.value"
|
|
@@ -55,14 +64,14 @@
|
|
|
55
64
|
:disabled="isDisabled || isReadonly"
|
|
56
65
|
v-bind="field.inputProps"
|
|
57
66
|
>
|
|
58
|
-
<DXFieldLabel :label="resolvedLabel" />
|
|
67
|
+
<DXFieldLabel :label="resolvedLabel" class="visually-hidden" />
|
|
59
68
|
</DFormCheckbox>
|
|
60
69
|
|
|
61
70
|
<DFormInvalidFeedback v-if="form.hasError(errorKey)" force-show>
|
|
62
71
|
{{ form.getError(errorKey) }}
|
|
63
72
|
</DFormInvalidFeedback>
|
|
64
73
|
<slot name="info" :field="field" :model="model" />
|
|
65
|
-
<DFormText v-if="resolvedHint || $slots.hint" class="text-muted">
|
|
74
|
+
<DFormText v-if="!hintInLabel && (resolvedHint || $slots.hint)" class="text-muted">
|
|
66
75
|
<slot name="hint" :field="field" :model="model">{{ resolvedHint }}</slot>
|
|
67
76
|
</DFormText>
|
|
68
77
|
<DFormText v-if="field.help">{{ field.help }}</DFormText>
|
|
@@ -122,11 +131,22 @@
|
|
|
122
131
|
:class="[field.class || 'mb-3', 'dx-switch', { 'dx-switch--on': switchIsOn }]"
|
|
123
132
|
v-bind="horizontalAttrs"
|
|
124
133
|
>
|
|
125
|
-
<!-- The
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
<!-- The row label (left column) names the control. The switch's own
|
|
135
|
+
inner text is shown only when the field opts into contextual on/off
|
|
136
|
+
text (e.g. "Product is current"); otherwise it falls back to the row
|
|
137
|
+
label and is hidden visually (kept for screen readers). In horizontal
|
|
138
|
+
layout the hint sits beneath the label here rather than below the
|
|
139
|
+
control. -->
|
|
128
140
|
<template v-if="!hideLabel" #label>
|
|
129
141
|
<DXFieldLabel :label="resolvedLabel" :info="resolvedInfo" />
|
|
142
|
+
<small
|
|
143
|
+
v-if="isHorizontal && (resolvedHint || $slots.hint)"
|
|
144
|
+
class="form-text text-muted d-block dx-field-hint"
|
|
145
|
+
>
|
|
146
|
+
<slot name="hint" :field="field" :model="model">{{
|
|
147
|
+
resolvedHint
|
|
148
|
+
}}</slot>
|
|
149
|
+
</small>
|
|
130
150
|
</template>
|
|
131
151
|
<slot
|
|
132
152
|
v-if="$slots.value"
|
|
@@ -143,14 +163,17 @@
|
|
|
143
163
|
:disabled="isDisabled || isReadonly"
|
|
144
164
|
v-bind="field.inputProps"
|
|
145
165
|
>
|
|
146
|
-
<DXFieldLabel
|
|
166
|
+
<DXFieldLabel
|
|
167
|
+
:label="switchText"
|
|
168
|
+
:class="switchHasContextualText ? undefined : 'visually-hidden'"
|
|
169
|
+
/>
|
|
147
170
|
</DFormCheckbox>
|
|
148
171
|
|
|
149
172
|
<DFormInvalidFeedback v-if="form.hasError(errorKey)" force-show>
|
|
150
173
|
{{ form.getError(errorKey) }}
|
|
151
174
|
</DFormInvalidFeedback>
|
|
152
175
|
<slot name="info" :field="field" :model="model" />
|
|
153
|
-
<DFormText v-if="resolvedHint || $slots.hint" class="text-muted">
|
|
176
|
+
<DFormText v-if="!hintInLabel && (resolvedHint || $slots.hint)" class="text-muted">
|
|
154
177
|
<slot name="hint" :field="field" :model="model">{{ resolvedHint }}</slot>
|
|
155
178
|
</DFormText>
|
|
156
179
|
<DFormText v-if="field.help">{{ field.help }}</DFormText>
|
|
@@ -246,9 +269,19 @@
|
|
|
246
269
|
<DFormGroup v-else :class="field.class || 'mb-3'" v-bind="horizontalAttrs">
|
|
247
270
|
<!-- Label with optional info popover. Omitted entirely (not just
|
|
248
271
|
emptied) when hideLabel is set, so BFormGroup doesn't reserve a
|
|
249
|
-
label column/row for it (see DXRepeater's table layout).
|
|
272
|
+
label column/row for it (see DXRepeater's table layout). In
|
|
273
|
+
horizontal layout the hint sits beneath the label here rather than
|
|
274
|
+
below the control. -->
|
|
250
275
|
<template v-if="!hideLabel" #label>
|
|
251
276
|
<DXFieldLabel :label="resolvedLabel" :info="resolvedInfo" />
|
|
277
|
+
<small
|
|
278
|
+
v-if="isHorizontal && (resolvedHint || $slots.hint)"
|
|
279
|
+
class="form-text text-muted d-block dx-field-hint"
|
|
280
|
+
>
|
|
281
|
+
<slot name="hint" :field="field" :model="model">{{
|
|
282
|
+
resolvedHint
|
|
283
|
+
}}</slot>
|
|
284
|
+
</small>
|
|
252
285
|
</template>
|
|
253
286
|
|
|
254
287
|
<!-- Custom value slot overrides the built-in control -->
|
|
@@ -435,8 +468,9 @@
|
|
|
435
468
|
-->
|
|
436
469
|
<slot name="info" :field="field" :model="model" />
|
|
437
470
|
|
|
438
|
-
<!-- Hint (dynamic, slot-overridable)
|
|
439
|
-
|
|
471
|
+
<!-- Hint (dynamic, slot-overridable). In horizontal layout it renders in
|
|
472
|
+
the label column instead (see the #label slot above). -->
|
|
473
|
+
<DFormText v-if="!hintInLabel && (resolvedHint || $slots.hint)" class="text-muted">
|
|
440
474
|
<!--
|
|
441
475
|
@slot Overrides the field's hint text shown below the control.
|
|
442
476
|
@binding {FieldDefinition} field The field definition being rendered.
|
|
@@ -564,10 +598,34 @@ function labelColsAttrs(cols: LabelCols | undefined): Record<string, any> {
|
|
|
564
598
|
// with sibling row labels (#78).
|
|
565
599
|
const horizontalAttrs = computed<Record<string, any>>(() =>
|
|
566
600
|
isHorizontal.value && !props.hideLabel
|
|
567
|
-
?
|
|
601
|
+
? {
|
|
602
|
+
...labelColsAttrs(props.labelCols ?? 3),
|
|
603
|
+
// Right-align the label column so the label (and the hint that
|
|
604
|
+
// sits beneath it in horizontal layout) line up against the
|
|
605
|
+
// control column, like a classic label-left settings form.
|
|
606
|
+
labelClass: "text-sm-end dx-field-label-col",
|
|
607
|
+
}
|
|
568
608
|
: {},
|
|
569
609
|
);
|
|
570
610
|
|
|
611
|
+
// In horizontal layout the hint moves up into the label column (beneath the
|
|
612
|
+
// label), rather than below the control — so a row reads "label + hint | control".
|
|
613
|
+
// Vertical layout (and a hidden label, which reserves no label column) keeps the
|
|
614
|
+
// hint below the control.
|
|
615
|
+
const hintInLabel = computed(() => isHorizontal.value && !props.hideLabel);
|
|
616
|
+
|
|
617
|
+
// A `switch` renders visible text inside the control only when the field opts
|
|
618
|
+
// into contextual on/off text (textWhenTrue/textWhenFalse) — e.g. "Product is
|
|
619
|
+
// current". Without it, `switchText` falls back to the row label, which would
|
|
620
|
+
// duplicate the outer label, so the inner label is kept for screen readers but
|
|
621
|
+
// hidden visually (the row label names the control). A plain `checkbox` never
|
|
622
|
+
// shows visible inner text for the same reason.
|
|
623
|
+
const switchHasContextualText = computed(
|
|
624
|
+
() =>
|
|
625
|
+
props.field.textWhenTrue !== undefined ||
|
|
626
|
+
props.field.textWhenFalse !== undefined,
|
|
627
|
+
);
|
|
628
|
+
|
|
571
629
|
// A table-layout repeater is inherently wide — squeezing its own label into a
|
|
572
630
|
// narrow left column (as if it were a single-line input) reads badly, unlike
|
|
573
631
|
// a normal horizontal field. Its label always renders above, regardless of
|
|
@@ -53,6 +53,13 @@ const infoId = `dx-field-info-${useId()}`;
|
|
|
53
53
|
gap: 0.35rem;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/* Soften the label from the near-black body colour so it doesn't dominate the
|
|
57
|
+
row — but keep it a step darker than the (lighter, secondary-grey) hint so the
|
|
58
|
+
label still leads. */
|
|
59
|
+
.dx-field-label__text {
|
|
60
|
+
color: #495057; /* gray-700 */
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
.dx-field-label__info {
|
|
57
64
|
display: inline-flex;
|
|
58
65
|
align-items: center;
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
(no Inertia required).
|
|
13
13
|
-->
|
|
14
14
|
<template>
|
|
15
|
-
<BForm
|
|
15
|
+
<BForm
|
|
16
|
+
@submit.prevent="handleSubmit"
|
|
17
|
+
:class="{ 'dx-form--horizontal': layout === 'horizontal' }"
|
|
18
|
+
>
|
|
16
19
|
<!-- Form-level error message -->
|
|
17
20
|
<DAlert
|
|
18
21
|
v-if="resolvedForm.shouldShowMessage"
|