@omnitend/dashboard-for-laravel 0.21.0 → 0.23.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/DXDashboard.vue.d.ts +26 -5
- package/dist/components/extended/DXDashboardNavbar.vue.d.ts +23 -2
- package/dist/components/extended/DXField.vue.d.ts +4 -4
- package/dist/components/extended/DXTable.vue.d.ts +37 -2
- package/dist/components/extended/DXUserAvatar.vue.d.ts +40 -0
- package/dist/dashboard-for-laravel.js +8029 -7902
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +8 -8
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +23 -0
- package/dist/types/navigation.d.ts +13 -0
- package/docs/public/api-reference.json +164 -16
- package/docs/public/docs-map.md +3 -2
- package/docs/public/llms.txt +3 -2
- package/package.json +4 -1
- package/resources/css/theme.scss +17 -2
- package/resources/js/components/extended/DXDashboard.vue +61 -11
- package/resources/js/components/extended/DXDashboardNavbar.vue +108 -43
- package/resources/js/components/extended/DXField.vue +122 -26
- package/resources/js/components/extended/DXTable.vue +304 -133
- package/resources/js/components/extended/DXUserAvatar.vue +104 -0
- package/resources/js/index.ts +3 -0
- package/resources/js/types/index.ts +25 -0
- package/resources/js/types/navigation.ts +15 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -231,6 +231,29 @@ export interface FieldDefinition {
|
|
|
231
231
|
* applied as `disabled`.
|
|
232
232
|
*/
|
|
233
233
|
readonly?: MaybeFn<boolean>;
|
|
234
|
+
/**
|
|
235
|
+
* Display the value as static text instead of a control — no border, no
|
|
236
|
+
* input box (Bootstrap's `.form-control-plaintext`). For values a
|
|
237
|
+
* profile/settings page shows but never lets you edit, where a `readonly`
|
|
238
|
+
* input still reads as "you could edit this, but can't".
|
|
239
|
+
*
|
|
240
|
+
* Implies read-only, for every field type. Anything backed by a real input
|
|
241
|
+
* — the text family, textarea, currency, percentage, autocomplete — renders
|
|
242
|
+
* as static text; control types with no native readonly state
|
|
243
|
+
* (select/radio/checkbox/switch/file) are disabled instead, exactly as they
|
|
244
|
+
* are for `readonly`.
|
|
245
|
+
*
|
|
246
|
+
* Enforced over `inputProps`: unlike the field's other bindings, which
|
|
247
|
+
* `inputProps` may override, a plaintext field cannot be made editable
|
|
248
|
+
* again through it.
|
|
249
|
+
*/
|
|
250
|
+
plaintext?: MaybeFn<boolean>;
|
|
251
|
+
/**
|
|
252
|
+
* Only for `type: "password"`. Show the reveal (eye) toggle that switches
|
|
253
|
+
* the input between masked and plain text. Defaults to `true` — set
|
|
254
|
+
* `false` to render a bare password input.
|
|
255
|
+
*/
|
|
256
|
+
revealable?: boolean;
|
|
234
257
|
/**
|
|
235
258
|
* Conditionally show or hide this field. When omitted the field is
|
|
236
259
|
* always visible. Boolean or a function of the form model; evaluated
|
|
@@ -28,3 +28,16 @@ export interface NavigationGroup {
|
|
|
28
28
|
visible?: boolean;
|
|
29
29
|
}
|
|
30
30
|
export type Navigation = NavigationGroup[];
|
|
31
|
+
/**
|
|
32
|
+
* Horizontal alignment of the navbar search slot content within its region:
|
|
33
|
+
* `"start"` = flush left (after the title from `md` up), `"center"` = centred.
|
|
34
|
+
* Shared by DXDashboard (which forwards it) and DXDashboardNavbar.
|
|
35
|
+
*/
|
|
36
|
+
export type NavbarSearchAlign = "start" | "center";
|
|
37
|
+
/**
|
|
38
|
+
* What the navbar actions slot does below the `md` breakpoint: `"wrap"` moves
|
|
39
|
+
* it to its own full-width row (the bar grows), `"hide"` removes it entirely
|
|
40
|
+
* (for apps that relocate page actions into the page on phones).
|
|
41
|
+
* Shared by DXDashboard (which forwards it) and DXDashboardNavbar.
|
|
42
|
+
*/
|
|
43
|
+
export type NavbarActionsOnMobile = "wrap" | "hide";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-07-
|
|
2
|
+
"generated": "2026-07-11T08:44:15.505Z",
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@omnitend/dashboard-for-laravel",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.22.0"
|
|
6
6
|
},
|
|
7
7
|
"components": {
|
|
8
8
|
"base": [
|
|
@@ -1394,7 +1394,14 @@
|
|
|
1394
1394
|
"name": "fluid",
|
|
1395
1395
|
"type": "boolean",
|
|
1396
1396
|
"required": false,
|
|
1397
|
-
"description": "Render the page content full-width and left-aligned instead of the default\ncentred, reading-width
|
|
1397
|
+
"description": "Render the page content full-width and left-aligned instead of the default\ncentred, reading-width column. Use for data-heavy admin pages (wide tables)."
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
"name": "contentMaxWidth",
|
|
1401
|
+
"type": "string",
|
|
1402
|
+
"required": false,
|
|
1403
|
+
"default": "'1140px'",
|
|
1404
|
+
"description": "Max width of the centred content column (any CSS length). A genuine cap, so\nforms and text-heavy pages don't stretch to ~2000px on a wide display.\nIgnored when `fluid`. Set a large value (or use `fluid`) for full width."
|
|
1398
1405
|
},
|
|
1399
1406
|
{
|
|
1400
1407
|
"name": "contentClass",
|
|
@@ -1410,11 +1417,18 @@
|
|
|
1410
1417
|
"description": "User object for navbar dropdown"
|
|
1411
1418
|
},
|
|
1412
1419
|
{
|
|
1413
|
-
"name": "
|
|
1414
|
-
"type": "
|
|
1420
|
+
"name": "searchAlign",
|
|
1421
|
+
"type": "NavbarSearchAlign",
|
|
1415
1422
|
"required": false,
|
|
1416
|
-
"default": "'
|
|
1417
|
-
"description": "
|
|
1423
|
+
"default": "'start'",
|
|
1424
|
+
"description": "Horizontal alignment of the navbar search slot content (`\"start\"` = flush\nleft, `\"center\"` = centred), forwarded to DXDashboardNavbar."
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
"name": "actionsOnMobile",
|
|
1428
|
+
"type": "NavbarActionsOnMobile",
|
|
1429
|
+
"required": false,
|
|
1430
|
+
"default": "'wrap'",
|
|
1431
|
+
"description": "What the navbar actions slot does below `md`: `\"wrap\"` to its own\nfull-width row, `\"hide\"` to remove it (relocate actions into the page on\nphones). Forwarded to DXDashboardNavbar."
|
|
1418
1432
|
},
|
|
1419
1433
|
{
|
|
1420
1434
|
"name": "collapsibleGroups",
|
|
@@ -1454,6 +1468,22 @@
|
|
|
1454
1468
|
{
|
|
1455
1469
|
"name": "name",
|
|
1456
1470
|
"title": "binding"
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
"title": "binding",
|
|
1474
|
+
"type": {
|
|
1475
|
+
"name": "function"
|
|
1476
|
+
},
|
|
1477
|
+
"name": "toggleSidebar",
|
|
1478
|
+
"description": "Shows/hides the sidebar."
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
"title": "binding",
|
|
1482
|
+
"type": {
|
|
1483
|
+
"name": "boolean"
|
|
1484
|
+
},
|
|
1485
|
+
"name": "sidebarHidden",
|
|
1486
|
+
"description": "Whether the sidebar is currently hidden."
|
|
1457
1487
|
}
|
|
1458
1488
|
]
|
|
1459
1489
|
},
|
|
@@ -1469,7 +1499,7 @@
|
|
|
1469
1499
|
"name": "DXDashboardNavbar",
|
|
1470
1500
|
"category": "extended",
|
|
1471
1501
|
"filePath": "resources/js/components/extended/DXDashboardNavbar.vue",
|
|
1472
|
-
"description": "Top navigation bar for the dashboard shell: menu toggle, page title,
|
|
1502
|
+
"description": "Top navigation bar for the dashboard shell: menu toggle, page title, search (aligned per `searchAlign`, left by default), page-level actions, and the user menu. Usually rendered by `DXDashboard`, which forwards these slots with a `navbar-` prefix.",
|
|
1473
1503
|
"props": [
|
|
1474
1504
|
{
|
|
1475
1505
|
"name": "user",
|
|
@@ -1484,6 +1514,20 @@
|
|
|
1484
1514
|
"required": false,
|
|
1485
1515
|
"default": "\"\"",
|
|
1486
1516
|
"description": "Page title shown at the left of the navbar (hidden below the `md` breakpoint)."
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
"name": "searchAlign",
|
|
1520
|
+
"type": "NavbarSearchAlign",
|
|
1521
|
+
"required": false,
|
|
1522
|
+
"default": "\"start\"",
|
|
1523
|
+
"description": "Horizontal alignment of the search slot content within its region\n(`\"start\"` = flush left, `\"center\"` = centred). Applies at every size:\nthe region sits inline after the title from `md` up, and is its own\nfull-width row below."
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
"name": "actionsOnMobile",
|
|
1527
|
+
"type": "NavbarActionsOnMobile",
|
|
1528
|
+
"required": false,
|
|
1529
|
+
"default": "\"wrap\"",
|
|
1530
|
+
"description": "What the actions slot does below the `md` breakpoint: `\"wrap\"` moves it\nto its own full-width row (the bar grows), `\"hide\"` removes it entirely\n(for apps that relocate page actions into the page on phones)."
|
|
1487
1531
|
}
|
|
1488
1532
|
],
|
|
1489
1533
|
"events": [
|
|
@@ -1501,12 +1545,12 @@
|
|
|
1501
1545
|
},
|
|
1502
1546
|
{
|
|
1503
1547
|
"name": "search",
|
|
1504
|
-
"description": "Search input or component.
|
|
1548
|
+
"description": "Search input or component. Aligned per `searchAlign` within its region (inline in the bar from `md` up; its own full-width row below).",
|
|
1505
1549
|
"bindings": []
|
|
1506
1550
|
},
|
|
1507
1551
|
{
|
|
1508
1552
|
"name": "actions",
|
|
1509
|
-
"description": "Page-level primary actions (e.g. a Create button)
|
|
1553
|
+
"description": "Page-level primary actions (e.g. a Create button). Right-aligned next to the user menu from `md` up; below, wraps to its own full-width row or is hidden entirely per `actionsOnMobile`.",
|
|
1510
1554
|
"bindings": [
|
|
1511
1555
|
{
|
|
1512
1556
|
"title": "binding",
|
|
@@ -1534,7 +1578,7 @@
|
|
|
1534
1578
|
},
|
|
1535
1579
|
{
|
|
1536
1580
|
"name": "user-icon",
|
|
1537
|
-
"description": "Custom user avatar/icon in the dropdown trigger.",
|
|
1581
|
+
"description": "Custom user avatar/icon in the dropdown trigger. To decorate the default avatar (e.g. add a notification dot) rather than replace it, render `DXUserAvatar` — the same component used here, so the styling comes with it.",
|
|
1538
1582
|
"bindings": [
|
|
1539
1583
|
{
|
|
1540
1584
|
"title": "binding",
|
|
@@ -1543,6 +1587,14 @@
|
|
|
1543
1587
|
},
|
|
1544
1588
|
"name": "initial",
|
|
1545
1589
|
"description": "The first letter of the user's name."
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
"title": "binding",
|
|
1593
|
+
"type": {
|
|
1594
|
+
"name": "object"
|
|
1595
|
+
},
|
|
1596
|
+
"name": "user",
|
|
1597
|
+
"description": "The signed-in user."
|
|
1546
1598
|
}
|
|
1547
1599
|
]
|
|
1548
1600
|
},
|
|
@@ -1767,7 +1819,7 @@
|
|
|
1767
1819
|
"name": "DXField",
|
|
1768
1820
|
"category": "extended",
|
|
1769
1821
|
"filePath": "resources/js/components/extended/DXField.vue",
|
|
1770
|
-
"description": "Renders a single `FieldDefinition` of any type (text, select, autocomplete, checkbox, switch, repeater, currency, percentage, file/image, component, etc.) with its label, validation error, hint and help. Used by `DXForm` and `DXTable`'s edit modal; exposes `value`, `span`, `info`, `hint` and `repeater-row` slots for per-field customisation.",
|
|
1822
|
+
"description": "Renders a single `FieldDefinition` of any type (text, select, autocomplete, checkbox, switch, repeater, currency, percentage, file/image, component, etc.) with its label, validation error, hint and help. Used by `DXForm` and `DXTable`'s edit modal; exposes `value`, `span`, `info`, `info-popover`, `hint` and `repeater-row` slots for per-field customisation.",
|
|
1771
1823
|
"props": [
|
|
1772
1824
|
{
|
|
1773
1825
|
"name": "field",
|
|
@@ -1968,7 +2020,13 @@
|
|
|
1968
2020
|
}
|
|
1969
2021
|
],
|
|
1970
2022
|
"events": [],
|
|
1971
|
-
"slots": [
|
|
2023
|
+
"slots": [
|
|
2024
|
+
{
|
|
2025
|
+
"name": "popover",
|
|
2026
|
+
"description": "Rich popover body. Overrides the plain `info` text — use",
|
|
2027
|
+
"bindings": []
|
|
2028
|
+
}
|
|
2029
|
+
],
|
|
1972
2030
|
"methods": []
|
|
1973
2031
|
},
|
|
1974
2032
|
{
|
|
@@ -2823,6 +2881,39 @@
|
|
|
2823
2881
|
"required": false,
|
|
2824
2882
|
"description": "API endpoint for creating new items (e.g., \"/api/products\") — enables \"New\" button"
|
|
2825
2883
|
},
|
|
2884
|
+
{
|
|
2885
|
+
"name": "showCreateButton",
|
|
2886
|
+
"type": "boolean",
|
|
2887
|
+
"required": false,
|
|
2888
|
+
"default": "true",
|
|
2889
|
+
"description": "Render the built-in \"New {item}\" button in the card header (default\n`true` whenever `createUrl` is set). Set `false` to drive the create\nmodal from your own trigger elsewhere — e.g. a button in the dashboard\nnavbar's actions slot calling the exposed `openCreate()`. With no\n`title` and no `header` slot, the header is then dropped entirely\nrather than left empty."
|
|
2890
|
+
},
|
|
2891
|
+
{
|
|
2892
|
+
"name": "footClone",
|
|
2893
|
+
"type": "boolean",
|
|
2894
|
+
"required": false,
|
|
2895
|
+
"default": "false",
|
|
2896
|
+
"description": "Render a `<tfoot>` mirroring the header row, so `#foot(<key>)` slots can\nhold per-column totals that line up under their data (#99). Without it\nthere is no footer to put them in. For a fully custom footer, use the\n`custom-foot` slot instead."
|
|
2897
|
+
},
|
|
2898
|
+
{
|
|
2899
|
+
"name": "showEmpty",
|
|
2900
|
+
"type": "boolean",
|
|
2901
|
+
"required": false,
|
|
2902
|
+
"default": "true",
|
|
2903
|
+
"description": "Show a message row when there are no rows (default `true`). An empty\ntable body is indistinguishable from a broken one, so the message is on\nby default. Override the wording with `emptyText`, or the whole row with\nthe `empty` slot."
|
|
2904
|
+
},
|
|
2905
|
+
{
|
|
2906
|
+
"name": "emptyText",
|
|
2907
|
+
"type": "string",
|
|
2908
|
+
"required": false,
|
|
2909
|
+
"description": "Message shown when there are no rows. Defaults to \"No {items} found\", or\n\"No {items} match your filters\" when a column filter is active."
|
|
2910
|
+
},
|
|
2911
|
+
{
|
|
2912
|
+
"name": "expandedItems",
|
|
2913
|
+
"type": "Array",
|
|
2914
|
+
"required": false,
|
|
2915
|
+
"description": "Rows currently expanded, as a `v-model`. Pair with the `row-expansion`\nslot to render detail content under a row (#112) instead of forcing every\nper-row detail into a modal."
|
|
2916
|
+
},
|
|
2826
2917
|
{
|
|
2827
2918
|
"name": "clientSide",
|
|
2828
2919
|
"type": "boolean",
|
|
@@ -2891,6 +2982,11 @@
|
|
|
2891
2982
|
"description": "`v-model:sortBy` update, emitted with the normalized single-column sort array when sorting changes.",
|
|
2892
2983
|
"properties": []
|
|
2893
2984
|
},
|
|
2985
|
+
{
|
|
2986
|
+
"name": "update:expandedItems",
|
|
2987
|
+
"description": "`v-model:expandedItems` update, emitted with the rows currently expanded.",
|
|
2988
|
+
"properties": []
|
|
2989
|
+
},
|
|
2894
2990
|
{
|
|
2895
2991
|
"name": "update:filters",
|
|
2896
2992
|
"description": "`v-model:filters` update, emitted with the new filter map when a column filter changes.",
|
|
@@ -2915,7 +3011,7 @@
|
|
|
2915
3011
|
},
|
|
2916
3012
|
{
|
|
2917
3013
|
"name": "name",
|
|
2918
|
-
"description": "
|
|
3014
|
+
"description": "Any slot the underlying table supports, forwarded with its scope: `cell(<fieldKey>)` for a cell, `foot(<fieldKey>)` for a footer cell (needs `footClone`), `empty` for the no-rows message, `row-expansion` for expandable row detail, plus `custom-foot`, `top-row`, `bottom-row`, `thead-sub` and the `table-*` slots.",
|
|
2919
3015
|
"bindings": [
|
|
2920
3016
|
{
|
|
2921
3017
|
"name": "name",
|
|
@@ -3116,12 +3212,64 @@
|
|
|
3116
3212
|
}
|
|
3117
3213
|
],
|
|
3118
3214
|
"methods": []
|
|
3215
|
+
},
|
|
3216
|
+
{
|
|
3217
|
+
"name": "DXUserAvatar",
|
|
3218
|
+
"category": "extended",
|
|
3219
|
+
"filePath": "resources/js/components/extended/DXUserAvatar.vue",
|
|
3220
|
+
"description": "The circular user avatar shown in the dashboard navbar's user menu: a single initial on a solid disc, with an optional notification dot. It exists as its own component because `DXDashboardNavbar`'s `user-icon` slot is one consumers routinely *decorate* rather than replace — adding an unread badge, wrapping it in a link. The navbar's styles are scoped, so slot content (compiled in the consumer's scope) can't reuse them; without this component every override starts by re-implementing the avatar's CSS, which then drifts from the theme. Rendering it here means an override is one line and stays on theme.",
|
|
3221
|
+
"props": [
|
|
3222
|
+
{
|
|
3223
|
+
"name": "user",
|
|
3224
|
+
"type": "union",
|
|
3225
|
+
"required": false,
|
|
3226
|
+
"default": "null",
|
|
3227
|
+
"description": "The user whose initial is shown. The first letter of `name` is used."
|
|
3228
|
+
},
|
|
3229
|
+
{
|
|
3230
|
+
"name": "initial",
|
|
3231
|
+
"type": "string",
|
|
3232
|
+
"required": false,
|
|
3233
|
+
"default": "\"\"",
|
|
3234
|
+
"description": "Overrides the initial derived from `user.name` (e.g. two-letter initials)."
|
|
3235
|
+
},
|
|
3236
|
+
{
|
|
3237
|
+
"name": "badge",
|
|
3238
|
+
"type": "boolean",
|
|
3239
|
+
"required": false,
|
|
3240
|
+
"default": "false",
|
|
3241
|
+
"description": "Show a notification dot on the avatar (e.g. unread updates)."
|
|
3242
|
+
},
|
|
3243
|
+
{
|
|
3244
|
+
"name": "badgeVariant",
|
|
3245
|
+
"type": "ColorVariant",
|
|
3246
|
+
"required": false,
|
|
3247
|
+
"default": "\"danger\"",
|
|
3248
|
+
"description": "Colour of the notification dot."
|
|
3249
|
+
},
|
|
3250
|
+
{
|
|
3251
|
+
"name": "badgeLabel",
|
|
3252
|
+
"type": "string",
|
|
3253
|
+
"required": false,
|
|
3254
|
+
"default": "\"Unread notifications\"",
|
|
3255
|
+
"description": "Accessible text for the notification dot, announced to screen readers\n(the dot itself is a colour-only signal). Ignored unless `badge` is set."
|
|
3256
|
+
}
|
|
3257
|
+
],
|
|
3258
|
+
"events": [],
|
|
3259
|
+
"slots": [
|
|
3260
|
+
{
|
|
3261
|
+
"name": "default",
|
|
3262
|
+
"description": "Replaces the initial inside the disc (e.g. a photo or an icon).",
|
|
3263
|
+
"bindings": []
|
|
3264
|
+
}
|
|
3265
|
+
],
|
|
3266
|
+
"methods": []
|
|
3119
3267
|
}
|
|
3120
3268
|
]
|
|
3121
3269
|
},
|
|
3122
3270
|
"stats": {
|
|
3123
|
-
"totalComponents":
|
|
3271
|
+
"totalComponents": 74,
|
|
3124
3272
|
"baseComponents": 57,
|
|
3125
|
-
"extendedComponents":
|
|
3273
|
+
"extendedComponents": 17
|
|
3126
3274
|
}
|
|
3127
3275
|
}
|
package/docs/public/docs-map.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Documentation Map
|
|
2
2
|
|
|
3
3
|
> Auto-generated hierarchical overview of all documentation
|
|
4
|
-
> Last updated: 2026-07-
|
|
4
|
+
> Last updated: 2026-07-11T08:44:15.559Z
|
|
5
5
|
|
|
6
6
|
This file provides a complete map of all available documentation for AI agents and developers.
|
|
7
7
|
|
|
@@ -82,6 +82,7 @@ This file provides a complete map of all available documentation for AI agents a
|
|
|
82
82
|
- [DXStatCard](/components/extended/DXStatCard): A KPI / stat tile: a big formatted value with a title, optional subtitle, an
|
|
83
83
|
- [DXSwitch](/components/extended/DXSwitch): A "filled box" toggle switch built on `DFormCheckbox`: a bordered box sized like
|
|
84
84
|
- [DXTable](/components/extended/DXTable): A comprehensive data table component with built-in pagination, sorting, filtering, and CRUD operatio
|
|
85
|
+
- [DXUserAvatar](/components/extended/DXUserAvatar): The circular user avatar shown in the dashboard navbar's user menu: a single
|
|
85
86
|
|
|
86
87
|
### Examples
|
|
87
88
|
|
|
@@ -100,4 +101,4 @@ This file provides a complete map of all available documentation for AI agents a
|
|
|
100
101
|
|
|
101
102
|
---
|
|
102
103
|
|
|
103
|
-
**Total Pages**:
|
|
104
|
+
**Total Pages**: 77
|
package/docs/public/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Vue 3 dashboard components for Laravel with Bootstrap Vue Next
|
|
4
4
|
>
|
|
5
|
-
> A dual-package library (NPM + Composer) providing
|
|
5
|
+
> A dual-package library (NPM + Composer) providing 69 Vue 3 components for building Laravel dashboards with Bootstrap Vue Next.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -81,7 +81,7 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
|
|
|
81
81
|
- [DToaster](/components/base/dtoaster): Bootstrap Vue Next Toaster wrapper
|
|
82
82
|
- [DTooltip](/components/base/dtooltip): Bootstrap Vue Next Tooltip wrapper
|
|
83
83
|
|
|
84
|
-
## Extended Components (
|
|
84
|
+
## Extended Components (12 components)
|
|
85
85
|
|
|
86
86
|
Custom dashboard components with advanced functionality beyond Bootstrap Vue Next.
|
|
87
87
|
|
|
@@ -96,6 +96,7 @@ Custom dashboard components with advanced functionality beyond Bootstrap Vue Nex
|
|
|
96
96
|
- [DXStatCard](/components/extended/dxstatcard): Extended dashboard component
|
|
97
97
|
- [DXSwitch](/components/extended/dxswitch): Extended dashboard component
|
|
98
98
|
- [DXTable](/components/extended/dxtable): Data table with pagination, filtering, and sorting
|
|
99
|
+
- [DXUserAvatar](/components/extended/dxuseravatar): Extended dashboard component
|
|
99
100
|
|
|
100
101
|
## Composables
|
|
101
102
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnitend/dashboard-for-laravel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Vue 3 dashboard components for Laravel with Bootstrap Vue Next",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/dashboard-for-laravel.umd.cjs",
|
|
@@ -31,8 +31,11 @@
|
|
|
31
31
|
"dev": "vite build --watch",
|
|
32
32
|
"build": "vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
33
33
|
"typecheck": "vue-tsc --noEmit",
|
|
34
|
+
"pretest": "vite build",
|
|
34
35
|
"test": "vitest",
|
|
36
|
+
"pretest:ui": "vite build",
|
|
35
37
|
"test:ui": "vitest --ui",
|
|
38
|
+
"pretest:headless": "vite build",
|
|
36
39
|
"test:headless": "vitest --run --browser.headless",
|
|
37
40
|
"docs:dev": "astro dev",
|
|
38
41
|
"docs:build": "npm run docs:generate:ai && astro build",
|
package/resources/css/theme.scss
CHANGED
|
@@ -287,11 +287,26 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
.dashboard-navbar {
|
|
290
|
-
height:
|
|
290
|
+
// Floor, not a fixed height: below `md` the search (and actions) drop to
|
|
291
|
+
// their own rows and the bar must grow to contain them (#93). Single-row
|
|
292
|
+
// content is shorter than this, so desktop stays exactly this height,
|
|
293
|
+
// aligned with the sidebar header.
|
|
294
|
+
min-height: $dashboard-navbar-height;
|
|
291
295
|
// A light grey top bar over the white content panel (higher contrast than a
|
|
292
296
|
// grey-everywhere layout). The navbar markup drops its `bg-white` class so
|
|
293
297
|
// this wins without `!important`.
|
|
294
|
-
background-color:
|
|
298
|
+
background-color: var(--bs-light);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// The avatar dropdown trigger (DXDashboardNavbar sets this via toggle-class,
|
|
302
|
+
// so it lands on the BVN-rendered button — global rule, scoped CSS can't
|
|
303
|
+
// reach it). The themed $btn-padding-y (10px) would make it ~54px tall and
|
|
304
|
+
// blow the navbar's single-row content budget: 64px header minus the bar's
|
|
305
|
+
// 16px padding = 48px. 6px keeps a ~46px tap target (≥ the 44px WCAG
|
|
306
|
+
// guideline) while still fitting the budget.
|
|
307
|
+
.dashboard-navbar__user-menu-toggle {
|
|
308
|
+
padding-top: 0.375rem;
|
|
309
|
+
padding-bottom: 0.375rem;
|
|
295
310
|
}
|
|
296
311
|
|
|
297
312
|
// ----------------------------------------------------------------------------
|
|
@@ -25,8 +25,17 @@
|
|
|
25
25
|
:key="strippedName"
|
|
26
26
|
#[strippedName]="slotProps"
|
|
27
27
|
>
|
|
28
|
-
<!--
|
|
29
|
-
|
|
28
|
+
<!--
|
|
29
|
+
@slot Forwards any `sidebar-*` slot to DXDashboardSidebar with the `sidebar-` prefix stripped (e.g. `sidebar-brand` becomes the sidebar's `brand` slot).
|
|
30
|
+
@binding {function} toggleSidebar Shows/hides the sidebar — so slot content (e.g. a close affordance in the brand row) can drive it.
|
|
31
|
+
@binding {boolean} sidebarHidden Whether the sidebar is currently hidden.
|
|
32
|
+
-->
|
|
33
|
+
<slot
|
|
34
|
+
:name="originalName"
|
|
35
|
+
v-bind="slotProps"
|
|
36
|
+
:toggleSidebar="toggleSidebar"
|
|
37
|
+
:sidebarHidden="hidden"
|
|
38
|
+
/>
|
|
30
39
|
</template>
|
|
31
40
|
</DXDashboardSidebar>
|
|
32
41
|
|
|
@@ -36,7 +45,8 @@
|
|
|
36
45
|
<DXDashboardNavbar
|
|
37
46
|
:page-title="pageTitle"
|
|
38
47
|
:user="user"
|
|
39
|
-
:
|
|
48
|
+
:search-align="searchAlign"
|
|
49
|
+
:actions-on-mobile="actionsOnMobile"
|
|
40
50
|
@toggle-sidebar="toggleSidebar"
|
|
41
51
|
>
|
|
42
52
|
<!-- Dynamically forward all navbar-* slots by stripping the prefix -->
|
|
@@ -45,8 +55,17 @@
|
|
|
45
55
|
:key="strippedName"
|
|
46
56
|
#[strippedName]="slotProps"
|
|
47
57
|
>
|
|
48
|
-
<!--
|
|
49
|
-
|
|
58
|
+
<!--
|
|
59
|
+
@slot Forwards any `navbar-*` slot to DXDashboardNavbar with the `navbar-` prefix stripped (e.g. `navbar-actions` becomes the navbar's `actions` slot).
|
|
60
|
+
@binding {function} toggleSidebar Shows/hides the sidebar.
|
|
61
|
+
@binding {boolean} sidebarHidden Whether the sidebar is currently hidden.
|
|
62
|
+
-->
|
|
63
|
+
<slot
|
|
64
|
+
:name="originalName"
|
|
65
|
+
v-bind="slotProps"
|
|
66
|
+
:toggleSidebar="toggleSidebar"
|
|
67
|
+
:sidebarHidden="hidden"
|
|
68
|
+
/>
|
|
50
69
|
</template>
|
|
51
70
|
</DXDashboardNavbar>
|
|
52
71
|
|
|
@@ -80,10 +99,16 @@ import DXDashboardNavbar from './DXDashboardNavbar.vue';
|
|
|
80
99
|
import DContainer from '../base/DContainer.vue';
|
|
81
100
|
import DRow from '../base/DRow.vue';
|
|
82
101
|
import DCol from '../base/DCol.vue';
|
|
83
|
-
import type { Navigation } from '../../types/navigation';
|
|
102
|
+
import type { Navigation, NavbarActionsOnMobile, NavbarSearchAlign } from '../../types/navigation';
|
|
84
103
|
|
|
85
104
|
const slots = useSlots();
|
|
86
105
|
|
|
106
|
+
// Slot-binding precedence: the forwarded slots bind the child's own slot props
|
|
107
|
+
// FIRST and `toggleSidebar`/`sidebarHidden` after, so ours win a name clash.
|
|
108
|
+
// That's deliberate — the dashboard guarantees those two bindings on every
|
|
109
|
+
// forwarded slot, and a child that later grew a same-named prop must not be
|
|
110
|
+
// able to silently take the guarantee away. No child uses those names today.
|
|
111
|
+
|
|
87
112
|
interface Props {
|
|
88
113
|
/** Navigation structure for sidebar */
|
|
89
114
|
navigation: Navigation;
|
|
@@ -116,8 +141,18 @@ interface Props {
|
|
|
116
141
|
/** User object for navbar dropdown */
|
|
117
142
|
user?: { name: string; email: string } | null;
|
|
118
143
|
|
|
119
|
-
/**
|
|
120
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Horizontal alignment of the navbar search slot content (`"start"` = flush
|
|
146
|
+
* left, `"center"` = centred), forwarded to DXDashboardNavbar.
|
|
147
|
+
*/
|
|
148
|
+
searchAlign?: NavbarSearchAlign;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* What the navbar actions slot does below `md`: `"wrap"` to its own
|
|
152
|
+
* full-width row, `"hide"` to remove it (relocate actions into the page on
|
|
153
|
+
* phones). Forwarded to DXDashboardNavbar.
|
|
154
|
+
*/
|
|
155
|
+
actionsOnMobile?: NavbarActionsOnMobile;
|
|
121
156
|
|
|
122
157
|
/**
|
|
123
158
|
* Turn sidebar group headers into accordion toggles that collapse/expand
|
|
@@ -147,12 +182,13 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
147
182
|
title: 'Dashboard',
|
|
148
183
|
pageTitle: '',
|
|
149
184
|
user: null,
|
|
150
|
-
logoutUrl: '/logout',
|
|
151
185
|
collapsibleGroups: false,
|
|
152
186
|
autoCollapseInactiveGroups: true,
|
|
153
187
|
storageKey: 'dashboard-sidebar-hidden',
|
|
154
188
|
dashboardId: '',
|
|
155
189
|
contentMaxWidth: '1140px',
|
|
190
|
+
searchAlign: 'start',
|
|
191
|
+
actionsOnMobile: 'wrap',
|
|
156
192
|
});
|
|
157
193
|
|
|
158
194
|
const collapsed = ref(false);
|
|
@@ -240,12 +276,26 @@ const toggleSidebar = () => {
|
|
|
240
276
|
console.error('Error saving sidebar state:', error);
|
|
241
277
|
}
|
|
242
278
|
};
|
|
279
|
+
|
|
280
|
+
defineExpose({
|
|
281
|
+
/**
|
|
282
|
+
* Show/hide the sidebar (same as clicking the navbar's hamburger). The
|
|
283
|
+
* dashboard owns the visibility state, so this is the supported way to drive
|
|
284
|
+
* it from outside — page content, a custom brand row, a keyboard shortcut.
|
|
285
|
+
* Also available as a slot binding on every forwarded `sidebar-*`/`navbar-*`
|
|
286
|
+
* slot, which is usually more convenient.
|
|
287
|
+
*/
|
|
288
|
+
toggleSidebar,
|
|
289
|
+
|
|
290
|
+
/** Whether the sidebar is currently hidden. */
|
|
291
|
+
sidebarHidden: computed(() => hidden.value),
|
|
292
|
+
});
|
|
243
293
|
</script>
|
|
244
294
|
|
|
245
295
|
<style scoped>
|
|
246
296
|
.dashboard-layout {
|
|
247
297
|
min-height: 100vh;
|
|
248
|
-
background-color:
|
|
298
|
+
background-color: var(--bs-light);
|
|
249
299
|
}
|
|
250
300
|
|
|
251
301
|
.dashboard-content {
|
|
@@ -259,6 +309,6 @@ const toggleSidebar = () => {
|
|
|
259
309
|
max-width: 100%;
|
|
260
310
|
/* A white content panel under the light grey top bar / layout, so forms and
|
|
261
311
|
content sit on white (higher contrast than a grey-everywhere dashboard). */
|
|
262
|
-
background-color:
|
|
312
|
+
background-color: var(--bs-white);
|
|
263
313
|
}
|
|
264
314
|
</style>
|