@revenexx/studio-shared 0.3.3 → 0.4.1
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/module.d.mts +7 -3
- package/dist/module.json +2 -2
- package/dist/module.mjs +10 -4
- package/dist/runtime/components/Dashboard/DashboardConfirmDialog.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardConfirmDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardConfirmDialog.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardControls.d.vue.ts +8 -7
- package/dist/runtime/components/Dashboard/DashboardControls.vue.d.ts +8 -7
- package/dist/runtime/components/Dashboard/DashboardGrid.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardGrid.vue +45 -1
- package/dist/runtime/components/Dashboard/DashboardGrid.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardNameDialog.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardNameDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardNameDialog.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardPickerDialog.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardPickerDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardPickerDialog.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardShareDialog.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardShareDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardShareDialog.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardTopBar.d.vue.ts +9 -4
- package/dist/runtime/components/Dashboard/DashboardTopBar.vue.d.ts +9 -4
- package/dist/runtime/components/Dashboard/DashboardWidgetConfigDialog.d.vue.ts +8 -6
- package/dist/runtime/components/Dashboard/DashboardWidgetConfigDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetConfigDialog.vue.d.ts +8 -6
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.d.vue.ts +5 -4
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue +14 -3
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue.d.ts +5 -4
- package/dist/runtime/components/Dashboard/DashboardWidgetHost.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetHost.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetIcon.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetIcon.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetLibrary.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetLibrary.vue.d.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetPreview.d.vue.ts +2 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetPreview.vue.d.ts +2 -1
- package/dist/runtime/components/DataTable/ColumnsMenu.d.vue.ts +2 -1
- package/dist/runtime/components/DataTable/ColumnsMenu.vue.d.ts +2 -1
- package/dist/runtime/components/DataTable/DataTable.d.vue.ts +120 -37
- package/dist/runtime/components/DataTable/DataTable.vue +493 -53
- package/dist/runtime/components/DataTable/DataTable.vue.d.ts +120 -37
- package/dist/runtime/components/DataTable/FacetChips.d.vue.ts +2 -1
- package/dist/runtime/components/DataTable/FacetChips.vue.d.ts +2 -1
- package/dist/runtime/components/DataTable/FacetPanel.d.vue.ts +6 -5
- package/dist/runtime/components/DataTable/FacetPanel.vue +57 -8
- package/dist/runtime/components/DataTable/FacetPanel.vue.d.ts +6 -5
- package/dist/runtime/components/DataTable/FilterMenu.d.vue.ts +6 -5
- package/dist/runtime/components/DataTable/FilterMenu.vue +5 -5
- package/dist/runtime/components/DataTable/FilterMenu.vue.d.ts +6 -5
- package/dist/runtime/components/DataTable/SavedViewsMenu.d.vue.ts +2 -1
- package/dist/runtime/components/DataTable/SavedViewsMenu.vue +61 -12
- package/dist/runtime/components/DataTable/SavedViewsMenu.vue.d.ts +2 -1
- package/dist/runtime/components/DataTable/SortMenu.d.vue.ts +4 -2
- package/dist/runtime/components/DataTable/SortMenu.vue +4 -1
- package/dist/runtime/components/DataTable/SortMenu.vue.d.ts +4 -2
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.d.vue.ts +23 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue +29 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue.d.ts +23 -0
- package/dist/runtime/components/DataTable/ViewModeSwitch.d.vue.ts +4 -2
- package/dist/runtime/components/DataTable/ViewModeSwitch.vue.d.ts +4 -2
- package/dist/runtime/components/DataTable/types.d.ts +17 -0
- package/dist/runtime/components/Form/FieldCell.d.vue.ts +32 -0
- package/dist/runtime/components/Form/FieldCell.vue +46 -0
- package/dist/runtime/components/Form/FieldCell.vue.d.ts +32 -0
- package/dist/runtime/components/Form/FieldGrid.d.vue.ts +13 -0
- package/dist/runtime/components/Form/FieldGrid.vue +11 -0
- package/dist/runtime/components/Form/FieldGrid.vue.d.ts +13 -0
- package/dist/runtime/components/Form/FormContextCard.d.vue.ts +33 -0
- package/dist/runtime/components/Form/FormContextCard.vue +56 -0
- package/dist/runtime/components/Form/FormContextCard.vue.d.ts +33 -0
- package/dist/runtime/components/Form/FormLayout.d.vue.ts +47 -0
- package/dist/runtime/components/Form/FormLayout.vue +169 -0
- package/dist/runtime/components/Form/FormLayout.vue.d.ts +47 -0
- package/dist/runtime/components/Form/FormSection.d.vue.ts +25 -0
- package/dist/runtime/components/Form/FormSection.vue +48 -0
- package/dist/runtime/components/Form/FormSection.vue.d.ts +25 -0
- package/dist/runtime/components/Form/SaveBar.d.vue.ts +44 -0
- package/dist/runtime/components/Form/SaveBar.vue +71 -0
- package/dist/runtime/components/Form/SaveBar.vue.d.ts +44 -0
- package/dist/runtime/components/Media/MediaFolderTree.d.vue.ts +6 -5
- package/dist/runtime/components/Media/MediaFolderTree.vue +1 -2
- package/dist/runtime/components/Media/MediaFolderTree.vue.d.ts +6 -5
- package/dist/runtime/components/Media/MediaPickerDialog.d.vue.ts +13 -1
- package/dist/runtime/components/Media/MediaPickerDialog.vue +206 -54
- package/dist/runtime/components/Media/MediaPickerDialog.vue.d.ts +13 -1
- package/dist/runtime/components/Media/MediaUploader.d.vue.ts +2 -1
- package/dist/runtime/components/Media/MediaUploader.vue +1 -1
- package/dist/runtime/components/Media/MediaUploader.vue.d.ts +2 -1
- package/dist/runtime/components/Shared/AppIcon.d.vue.ts +21 -0
- package/dist/runtime/components/Shared/AppIcon.vue +47 -0
- package/dist/runtime/components/Shared/AppIcon.vue.d.ts +21 -0
- package/dist/runtime/components/Shared/BuildLogsFlyout.d.vue.ts +2 -1
- package/dist/runtime/components/Shared/BuildLogsFlyout.vue.d.ts +2 -1
- package/dist/runtime/components/Shared/CardSizeToggle.d.vue.ts +11 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue +19 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue.d.ts +11 -0
- package/dist/runtime/components/Shared/DetailSheet.d.vue.ts +60 -0
- package/dist/runtime/components/Shared/DetailSheet.vue +211 -0
- package/dist/runtime/components/Shared/DetailSheet.vue.d.ts +60 -0
- package/dist/runtime/components/Shared/EmptyNote.d.vue.ts +19 -0
- package/dist/runtime/components/Shared/EmptyNote.vue +25 -0
- package/dist/runtime/components/Shared/EmptyNote.vue.d.ts +19 -0
- package/dist/runtime/components/Shared/FloatingPanel.d.vue.ts +7 -6
- package/dist/runtime/components/Shared/FloatingPanel.vue.d.ts +7 -6
- package/dist/runtime/components/Shared/GitDeploymentSettings.d.vue.ts +2 -1
- package/dist/runtime/components/Shared/GitDeploymentSettings.vue.d.ts +2 -1
- package/dist/runtime/components/Shared/KpiTile.d.vue.ts +8 -1
- package/dist/runtime/components/Shared/KpiTile.vue +10 -9
- package/dist/runtime/components/Shared/KpiTile.vue.d.ts +8 -1
- package/dist/runtime/components/Shared/ListSurface.d.vue.ts +3 -2
- package/dist/runtime/components/Shared/ListSurface.vue.d.ts +3 -2
- package/dist/runtime/components/Shared/PageHeader.d.vue.ts +7 -6
- package/dist/runtime/components/Shared/PageHeader.vue +15 -4
- package/dist/runtime/components/Shared/PageHeader.vue.d.ts +7 -6
- package/dist/runtime/components/Shared/RecordLayout.d.vue.ts +8 -7
- package/dist/runtime/components/Shared/RecordLayout.vue +1 -2
- package/dist/runtime/components/Shared/RecordLayout.vue.d.ts +8 -7
- package/dist/runtime/components/Shared/RecordRailCard.d.vue.ts +3 -2
- package/dist/runtime/components/Shared/RecordRailCard.vue +3 -3
- package/dist/runtime/components/Shared/RecordRailCard.vue.d.ts +3 -2
- package/dist/runtime/components/Shared/SelectionBar.d.vue.ts +22 -0
- package/dist/runtime/components/Shared/SelectionBar.vue +40 -0
- package/dist/runtime/components/Shared/SelectionBar.vue.d.ts +22 -0
- package/dist/runtime/components/Shared/SidebarNav.d.vue.ts +39 -4
- package/dist/runtime/components/Shared/SidebarNav.vue +71 -25
- package/dist/runtime/components/Shared/SidebarNav.vue.d.ts +39 -4
- package/dist/runtime/components/Shared/SidebarNavAreas.d.vue.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue +291 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue.d.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavLink.d.vue.ts +3 -10
- package/dist/runtime/components/Shared/SidebarNavLink.vue +31 -5
- package/dist/runtime/components/Shared/SidebarNavLink.vue.d.ts +3 -10
- package/dist/runtime/components/Shared/SortHeader.d.vue.ts +3 -2
- package/dist/runtime/components/Shared/SortHeader.vue +6 -2
- package/dist/runtime/components/Shared/SortHeader.vue.d.ts +3 -2
- package/dist/runtime/components/Shared/StateCard.d.vue.ts +6 -5
- package/dist/runtime/components/Shared/StateCard.vue +1 -1
- package/dist/runtime/components/Shared/StateCard.vue.d.ts +6 -5
- package/dist/runtime/components/Shared/StudioCard.d.vue.ts +5 -4
- package/dist/runtime/components/Shared/StudioCard.vue.d.ts +5 -4
- package/dist/runtime/components/Shared/TabBar.d.vue.ts +4 -21
- package/dist/runtime/components/Shared/TabBar.vue +30 -13
- package/dist/runtime/components/Shared/TabBar.vue.d.ts +4 -21
- package/dist/runtime/components/Shared/ViewTab.d.vue.ts +2 -1
- package/dist/runtime/components/Shared/ViewTab.vue.d.ts +2 -1
- package/dist/runtime/components/Shared/Wizard.d.vue.ts +20 -7
- package/dist/runtime/components/Shared/Wizard.vue +9 -5
- package/dist/runtime/components/Shared/Wizard.vue.d.ts +20 -7
- package/dist/runtime/composables/useDetailSheet.d.ts +20 -0
- package/dist/runtime/composables/useDetailSheet.js +50 -0
- package/dist/runtime/composables/useMediaLibrary.d.ts +12 -0
- package/dist/runtime/composables/usePlatformTenant.d.ts +6 -0
- package/dist/runtime/composables/useSavedViews.d.ts +11 -1
- package/dist/runtime/composables/useSavedViews.js +4 -4
- package/dist/runtime/composables/useWidgetFigures.d.ts +12 -0
- package/dist/runtime/composables/useWidgetFigures.js +24 -0
- package/dist/runtime/composables/useWidgetHeader.d.ts +15 -0
- package/dist/runtime/composables/useWidgetHeader.js +15 -0
- package/dist/runtime/lib/activeTenant.d.ts +58 -0
- package/dist/runtime/lib/activeTenant.js +45 -0
- package/dist/runtime/lib/appIcon.d.ts +48 -0
- package/dist/runtime/lib/appIcon.js +27 -0
- package/dist/runtime/lib/auditEnvelope.d.ts +43 -0
- package/dist/runtime/lib/auditEnvelope.js +55 -0
- package/dist/runtime/lib/cardSize.d.ts +13 -0
- package/dist/runtime/lib/cardSize.js +20 -0
- package/dist/runtime/lib/dashboardIcons.js +2 -0
- package/dist/runtime/lib/dataTableFilters.d.ts +22 -0
- package/dist/runtime/lib/dataTableFilters.js +5 -0
- package/dist/runtime/lib/detailSheet.d.ts +43 -0
- package/dist/runtime/lib/detailSheet.js +34 -0
- package/dist/runtime/lib/facets.d.ts +13 -0
- package/dist/runtime/lib/formLayout.d.ts +164 -0
- package/dist/runtime/lib/formLayout.js +117 -0
- package/dist/runtime/lib/formLayoutContext.d.ts +26 -0
- package/dist/runtime/lib/formLayoutContext.js +1 -0
- package/dist/runtime/lib/gridTracks.d.ts +14 -1
- package/dist/runtime/lib/gridTracks.js +13 -2
- package/dist/runtime/lib/isoLists.d.ts +37 -2
- package/dist/runtime/lib/isoLists.js +54 -1
- package/dist/runtime/lib/notice.d.ts +14 -0
- package/dist/runtime/lib/notice.js +19 -0
- package/dist/runtime/lib/pageSize.d.ts +15 -0
- package/dist/runtime/lib/pageSize.js +26 -0
- package/dist/runtime/lib/rowMove.d.ts +38 -0
- package/dist/runtime/lib/rowMove.js +20 -0
- package/dist/runtime/lib/sidebarAreas.d.ts +46 -0
- package/dist/runtime/lib/sidebarAreas.js +25 -0
- package/dist/runtime/lib/sidebarNav.d.ts +21 -2
- package/dist/runtime/lib/sidebarNav.js +23 -4
- package/dist/runtime/lib/solarIconMap.d.ts +16 -0
- package/dist/runtime/lib/solarIconMap.js +326 -0
- package/dist/runtime/lib/solarIcons.d.ts +37 -0
- package/dist/runtime/lib/solarIcons.js +25 -0
- package/dist/runtime/lib/swipeToClose.d.ts +25 -0
- package/dist/runtime/lib/swipeToClose.js +118 -0
- package/dist/runtime/lib/tableExport.d.ts +31 -0
- package/dist/runtime/lib/tableExport.js +143 -0
- package/dist/runtime/lib/talkback.d.ts +5 -0
- package/dist/runtime/lib/talkback.js +8 -0
- package/dist/runtime/lib/talkbackTokenBatch.d.ts +35 -0
- package/dist/runtime/lib/talkbackTokenBatch.js +101 -0
- package/dist/runtime/types/nav.d.ts +9 -0
- package/dist/types.d.mts +8 -0
- package/package.json +4 -3
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import {
|
|
3
|
+
AlignVerticalSpacing,
|
|
4
|
+
AltArrowRight,
|
|
3
5
|
Eye,
|
|
4
6
|
EyeClosed,
|
|
5
7
|
Filter,
|
|
8
|
+
HamburgerMenu as DragHandle,
|
|
6
9
|
ListArrowDownMinimalistic,
|
|
7
10
|
Magnifier as Search,
|
|
8
11
|
SidebarMinimalistic,
|
|
@@ -18,14 +21,18 @@ import {
|
|
|
18
21
|
} from "@revenexx/studio";
|
|
19
22
|
import { orderColumnsBy } from "../../lib/columnOrder";
|
|
20
23
|
import { initiallyHidden, visibleColumnsOf } from "../../lib/columnVisibility";
|
|
21
|
-
import {
|
|
22
|
-
import { gridTemplateColumns } from "../../lib/gridTracks";
|
|
24
|
+
import { facetCounts, matchesFilter } from "../../lib/dataTableFilters";
|
|
25
|
+
import { gridTemplateColumns, headerFloor } from "../../lib/gridTracks";
|
|
26
|
+
import { dropEdge, dropTargetIndex, moveKey, stepTarget } from "../../lib/rowMove";
|
|
23
27
|
import SortHeader from "../Shared/SortHeader.vue";
|
|
24
28
|
import FacetChips from "./FacetChips.vue";
|
|
25
29
|
import FacetPanel from "./FacetPanel.vue";
|
|
26
30
|
import FilterMenu from "./FilterMenu.vue";
|
|
27
31
|
import SavedViewsMenu from "./SavedViewsMenu.vue";
|
|
32
|
+
import ToolbarLabelTrigger from "./ToolbarLabelTrigger.vue";
|
|
28
33
|
import SortMenu from "./SortMenu.vue";
|
|
34
|
+
import { DEFAULT_PAGE_SIZE, pageSizeOptions as pageSizeChoices, readPageSize, writePageSize } from "../../lib/pageSize";
|
|
35
|
+
const RIGHT_ALIGNED = "text-right pr-4";
|
|
29
36
|
const props = defineProps({
|
|
30
37
|
data: { type: Array, required: true },
|
|
31
38
|
columns: { type: Array, required: true },
|
|
@@ -40,6 +47,7 @@ const props = defineProps({
|
|
|
40
47
|
viewModes: { type: [Array, null], required: false, default: null },
|
|
41
48
|
rail: { type: [Boolean, Object], required: false, default: false },
|
|
42
49
|
scrollBody: { type: [Boolean, String, Object], required: false },
|
|
50
|
+
reserveBottom: { type: Number, required: false },
|
|
43
51
|
pagination: { type: [Boolean, Object], required: false, default: true },
|
|
44
52
|
defaultSort: { type: Object, required: false },
|
|
45
53
|
serverMode: { type: Boolean, required: false, default: false },
|
|
@@ -47,11 +55,21 @@ const props = defineProps({
|
|
|
47
55
|
loading: { type: Boolean, required: false, default: false },
|
|
48
56
|
emptyText: { type: String, required: false },
|
|
49
57
|
groupBy: { type: [Function, null], required: false, default: null },
|
|
50
|
-
groupEmptyLabel: { type: String, required: false }
|
|
58
|
+
groupEmptyLabel: { type: String, required: false },
|
|
59
|
+
activeRowKey: { type: [String, Number, null], required: false },
|
|
60
|
+
rowClass: { type: [Function, null], required: false, default: null },
|
|
61
|
+
reorderable: { type: Boolean, required: false, default: false },
|
|
62
|
+
reorderDisabled: { type: [String, null], required: false, default: null },
|
|
63
|
+
mobileCards: { type: Boolean, required: false, default: true },
|
|
64
|
+
densityKey: { type: String, required: false, default: "cockpit.datatable.density" },
|
|
65
|
+
pageSizeKey: { type: [String, null], required: false, default: null },
|
|
66
|
+
embedded: { type: Boolean, required: false, default: false },
|
|
67
|
+
toolbar: { type: Boolean, required: false, default: true }
|
|
51
68
|
});
|
|
52
|
-
const emit = defineEmits(["rowClick", "stateChange"]);
|
|
69
|
+
const emit = defineEmits(["rowClick", "stateChange", "orderChange", "rowMove"]);
|
|
70
|
+
defineSlots();
|
|
53
71
|
const t = useT();
|
|
54
|
-
const query =
|
|
72
|
+
const query = defineModel("query", { type: String, ...{ default: "" } });
|
|
55
73
|
const sort = defineModel("sort", { type: Object, ...{
|
|
56
74
|
default: () => ({
|
|
57
75
|
column: null,
|
|
@@ -61,19 +79,66 @@ const sort = defineModel("sort", { type: Object, ...{
|
|
|
61
79
|
const page = defineModel("page", { type: Number, ...{ default: 0 } });
|
|
62
80
|
const viewMode = defineModel("viewMode", { type: String, ...{ default: "list" } });
|
|
63
81
|
const railOpen = defineModel("railOpen", { type: Boolean, ...{ default: true } });
|
|
82
|
+
const density = defineModel("density", { type: String, ...{ default: "standard" } });
|
|
83
|
+
if (import.meta.client) {
|
|
84
|
+
try {
|
|
85
|
+
const stored = localStorage.getItem(props.densityKey);
|
|
86
|
+
if (stored === "compact" || stored === "standard") density.value = stored;
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function setDensity(next) {
|
|
91
|
+
density.value = next;
|
|
92
|
+
try {
|
|
93
|
+
localStorage.setItem(props.densityKey, next);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const narrow = ref(false);
|
|
98
|
+
let narrowMql = null;
|
|
99
|
+
const onNarrow = (e) => {
|
|
100
|
+
narrow.value = e.matches;
|
|
101
|
+
};
|
|
102
|
+
onMounted(() => {
|
|
103
|
+
narrowMql = window.matchMedia("(max-width: 767px)");
|
|
104
|
+
narrow.value = narrowMql.matches;
|
|
105
|
+
narrowMql.addEventListener("change", onNarrow);
|
|
106
|
+
});
|
|
107
|
+
onBeforeUnmount(() => narrowMql?.removeEventListener("change", onNarrow));
|
|
108
|
+
const cardMode = computed(() => props.mobileCards && narrow.value);
|
|
109
|
+
const CONTROL_KEYS = /* @__PURE__ */ new Set(["__select", "__actions", "__move"]);
|
|
110
|
+
const STATUS_KEY = /(^|_)(status|state|phase|stage|lifecycle)(_|$)/i;
|
|
111
|
+
const cardLayout = computed(() => {
|
|
112
|
+
const cols = visibleColumns.value;
|
|
113
|
+
const data = cols.filter((c) => !CONTROL_KEYS.has(c.key) && c.card !== "hidden");
|
|
114
|
+
const title = data.find((c) => c.card === "title") ?? data.find((c) => c.primary) ?? data[0] ?? null;
|
|
115
|
+
const status = data.find((c) => c.card === "status") ?? data.find((c) => c !== title && c.card !== "meta" && STATUS_KEY.test(c.key)) ?? null;
|
|
116
|
+
const explicitMeta = data.filter((c) => c.card === "meta");
|
|
117
|
+
const meta = (explicitMeta.length ? explicitMeta : data.filter((c) => c !== title && c !== status)).slice(0, 4);
|
|
118
|
+
return {
|
|
119
|
+
select: cols.find((c) => c.key === "__select") ?? null,
|
|
120
|
+
actions: cols.find((c) => c.key === "__actions") ?? null,
|
|
121
|
+
title,
|
|
122
|
+
status,
|
|
123
|
+
meta
|
|
124
|
+
};
|
|
125
|
+
});
|
|
64
126
|
const facetSelection = defineModel("facetSelection", { type: Object, ...{ default: () => ({}) } });
|
|
65
127
|
const panelFacets = computed(() => props.facets);
|
|
66
128
|
if (props.defaultSort && sort.value.column == null) {
|
|
67
129
|
sort.value = { column: props.defaultSort.column, direction: props.defaultSort.direction };
|
|
68
130
|
}
|
|
131
|
+
const pageSizeTable = computed(() => props.pageSizeKey ?? props.savedViews?.storageKey ?? null);
|
|
69
132
|
const pageSize = ref(
|
|
70
|
-
typeof props.pagination === "object" && props.pagination?.pageSize ? props.pagination.pageSize :
|
|
133
|
+
readPageSize(pageSizeTable.value) ?? (typeof props.pagination === "object" && props.pagination?.pageSize ? props.pagination.pageSize : DEFAULT_PAGE_SIZE)
|
|
71
134
|
);
|
|
72
|
-
const pageSizeOptions = computed(() =>
|
|
135
|
+
const pageSizeOptions = computed(() => pageSizeChoices(pageSize.value));
|
|
136
|
+
watch(pageSize, (n) => writePageSize(pageSizeTable.value, n));
|
|
73
137
|
const hidden = ref(initiallyHidden(props.columns));
|
|
74
138
|
const columnOrder = ref([]);
|
|
75
139
|
const arrangedColumns = computed(() => orderColumnsBy(props.columns, columnOrder.value));
|
|
76
140
|
const visibleColumns = computed(() => visibleColumnsOf(arrangedColumns.value, hidden.value));
|
|
141
|
+
defineExpose({ visibleColumns });
|
|
77
142
|
const pickerColumns = computed(() => arrangedColumns.value.filter((c) => (c.label ?? "").trim().length > 0).map((c) => ({
|
|
78
143
|
key: c.key,
|
|
79
144
|
label: c.label ?? c.key,
|
|
@@ -120,22 +185,22 @@ const filterFacets = computed(() => filterDims.value.map((d) => {
|
|
|
120
185
|
};
|
|
121
186
|
}));
|
|
122
187
|
function dimCounts(d) {
|
|
123
|
-
return
|
|
188
|
+
return facetCounts(queried.value, filterDims.value, activeFilters.value, d);
|
|
124
189
|
}
|
|
125
|
-
const
|
|
126
|
-
if (props.serverMode || !filterDims.value.length) return props.data;
|
|
127
|
-
const active = filterDims.value.filter((d) => activeFilters.value[d.key]?.length);
|
|
128
|
-
if (!active.length) return props.data;
|
|
129
|
-
return props.data.filter((row) => active.every((d) => matchesFilter(d.getter, row, activeFilters.value[d.key])));
|
|
130
|
-
});
|
|
131
|
-
const searched = computed(() => {
|
|
190
|
+
const queried = computed(() => {
|
|
132
191
|
if (props.serverMode) return props.data;
|
|
133
192
|
const q = query.value.trim().toLowerCase();
|
|
134
|
-
if (!q) return
|
|
135
|
-
return
|
|
193
|
+
if (!q) return props.data;
|
|
194
|
+
return props.data.filter(
|
|
136
195
|
(row) => props.columns.some((col) => searchOf(col, row).includes(q))
|
|
137
196
|
);
|
|
138
197
|
});
|
|
198
|
+
const searched = computed(() => {
|
|
199
|
+
if (props.serverMode || !filterDims.value.length) return queried.value;
|
|
200
|
+
const active = filterDims.value.filter((d) => activeFilters.value[d.key]?.length);
|
|
201
|
+
if (!active.length) return queried.value;
|
|
202
|
+
return queried.value.filter((row) => active.every((d) => matchesFilter(d.getter, row, activeFilters.value[d.key])));
|
|
203
|
+
});
|
|
139
204
|
function sortKey(col, row) {
|
|
140
205
|
if (col.sortGetter) return col.sortGetter(row);
|
|
141
206
|
const raw = row[col.key];
|
|
@@ -164,9 +229,24 @@ const sorted = computed(() => {
|
|
|
164
229
|
return 0;
|
|
165
230
|
});
|
|
166
231
|
});
|
|
232
|
+
watch(sorted, (rows) => emit("orderChange", rows.map(rowKeyFor)), { immediate: true });
|
|
167
233
|
const totalCount = computed(
|
|
168
234
|
() => props.serverMode ? props.total ?? props.data.length : sorted.value.length
|
|
169
235
|
);
|
|
236
|
+
const activeNarrowing = computed(() => filterDims.value.map((d) => ({
|
|
237
|
+
label: d.label,
|
|
238
|
+
values: (activeFilters.value[d.key] ?? []).map((v) => d.options.find((o) => o.value === v)?.label ?? v)
|
|
239
|
+
})).filter((d) => d.values.length > 0));
|
|
240
|
+
function clearNarrowing() {
|
|
241
|
+
query.value = "";
|
|
242
|
+
activeFilters.value = {};
|
|
243
|
+
facetSelection.value = {};
|
|
244
|
+
}
|
|
245
|
+
const liveStatus = computed(() => {
|
|
246
|
+
if (!showTable.value) return "";
|
|
247
|
+
if (props.loading) return t("shared.datatable.state.loading");
|
|
248
|
+
return totalCount.value === 0 ? t("shared.datatable.footer.noresults") : t("shared.datatable.footer.showing", { start: rangeStart.value, end: rangeEnd.value, total: totalCount.value });
|
|
249
|
+
});
|
|
170
250
|
const paginated = computed(() => {
|
|
171
251
|
if (props.serverMode || !props.pagination) return sorted.value;
|
|
172
252
|
const start = page.value * pageSize.value;
|
|
@@ -240,7 +320,94 @@ function rowKeyFor(row) {
|
|
|
240
320
|
if (typeof props.rowKey === "function") return props.rowKey(row);
|
|
241
321
|
return row[props.rowKey];
|
|
242
322
|
}
|
|
243
|
-
const gridTemplate = computed(() => `grid-template-columns: ${gridTemplateColumns(
|
|
323
|
+
const gridTemplate = computed(() => `grid-template-columns: ${gridTemplateColumns(
|
|
324
|
+
renderColumns.value.map((c) => c.width),
|
|
325
|
+
void 0,
|
|
326
|
+
// A flexible column keeps room for its one-line heading and the (?)/sort icons beside it.
|
|
327
|
+
renderColumns.value.map((c) => c.primary ? c.floor ?? PRIMARY_FLOOR : c.floor ?? headerFloor(c.label, { icons: (c.sortable ? 1 : 0) + 1, maxChars: HEADER_NOWRAP_MAX }))
|
|
328
|
+
)};`);
|
|
329
|
+
const PRIMARY_FLOOR = "260px";
|
|
330
|
+
const pinnedCount = computed(() => {
|
|
331
|
+
if (cardMode.value) return 0;
|
|
332
|
+
const i = renderColumns.value.findIndex((c) => c.primary);
|
|
333
|
+
return i < 0 ? 0 : i + 1;
|
|
334
|
+
});
|
|
335
|
+
const pinnedOffsets = ref([]);
|
|
336
|
+
const scrolledX = ref(false);
|
|
337
|
+
const moreRight = ref(false);
|
|
338
|
+
function measurePinned() {
|
|
339
|
+
const row = headerRowEl.value;
|
|
340
|
+
if (!row || !pinnedCount.value) {
|
|
341
|
+
pinnedOffsets.value = [];
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const cells = Array.from(row.querySelectorAll(':scope > [role="columnheader"]'));
|
|
345
|
+
const rowLeft = row.getBoundingClientRect().left;
|
|
346
|
+
const style = getComputedStyle(row);
|
|
347
|
+
const pad = Number.parseFloat(style.paddingLeft) || 0;
|
|
348
|
+
const gap = Number.parseFloat(style.columnGap) || 0;
|
|
349
|
+
pinnedOffsets.value = cells.slice(0, pinnedCount.value).map((cell, i) => {
|
|
350
|
+
const left = cell.getBoundingClientRect().left - rowLeft + (Number.parseFloat(cell.style.marginLeft) ? -Number.parseFloat(cell.style.marginLeft) : 0);
|
|
351
|
+
const gutter = i === 0 ? pad : gap;
|
|
352
|
+
return { left: left - gutter, gutter };
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
function pinnedStyle(index) {
|
|
356
|
+
const o = pinnedOffsets.value[index];
|
|
357
|
+
if (!o || index >= pinnedCount.value) return void 0;
|
|
358
|
+
return {
|
|
359
|
+
position: "sticky",
|
|
360
|
+
left: `${o.left}px`,
|
|
361
|
+
marginLeft: `-${o.gutter}px`,
|
|
362
|
+
paddingLeft: `${o.gutter}px`,
|
|
363
|
+
backgroundColor: "inherit",
|
|
364
|
+
zIndex: "1"
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
const HEADER_NOWRAP_MAX = 18;
|
|
368
|
+
function headerNoWrap(col) {
|
|
369
|
+
return (col.label ?? "").length <= HEADER_NOWRAP_MAX ? "whitespace-nowrap" : "";
|
|
370
|
+
}
|
|
371
|
+
function rightPinStyle(col) {
|
|
372
|
+
if (!col.pinRight || cardMode.value) return void 0;
|
|
373
|
+
return { position: "sticky", right: "0px", backgroundColor: "inherit", zIndex: "1" };
|
|
374
|
+
}
|
|
375
|
+
function rightPinClass(col) {
|
|
376
|
+
return col.pinRight && moreRight.value ? "shadow-[-6px_0_8px_-6px_rgba(11,5,34,0.18)]" : "";
|
|
377
|
+
}
|
|
378
|
+
function pinnedClass(index) {
|
|
379
|
+
return index === pinnedCount.value - 1 && scrolledX.value ? "shadow-[6px_0_8px_-6px_rgba(11,5,34,0.18)]" : "";
|
|
380
|
+
}
|
|
381
|
+
function syncScrollX() {
|
|
382
|
+
const el = scrollEl.value;
|
|
383
|
+
if (!el) return;
|
|
384
|
+
scrolledX.value = el.scrollLeft > 0;
|
|
385
|
+
moreRight.value = el.scrollWidth - el.clientWidth - el.scrollLeft > 2;
|
|
386
|
+
}
|
|
387
|
+
function scrollRight() {
|
|
388
|
+
scrollEl.value?.scrollBy({ left: Math.max(240, (scrollEl.value?.clientWidth ?? 0) * 0.6), behavior: "smooth" });
|
|
389
|
+
}
|
|
390
|
+
let pinObserver = null;
|
|
391
|
+
onMounted(() => {
|
|
392
|
+
pinObserver = new ResizeObserver(() => {
|
|
393
|
+
measurePinned();
|
|
394
|
+
syncScrollX();
|
|
395
|
+
});
|
|
396
|
+
if (scrollEl.value) pinObserver.observe(scrollEl.value);
|
|
397
|
+
if (headerRowEl.value) pinObserver.observe(headerRowEl.value);
|
|
398
|
+
nextTick(() => {
|
|
399
|
+
measurePinned();
|
|
400
|
+
syncScrollX();
|
|
401
|
+
});
|
|
402
|
+
watch([() => renderColumns.value.map((c) => `${c.key}:${c.width ?? ""}`).join("|"), () => props.data, cardMode, density], () => {
|
|
403
|
+
nextTick(() => {
|
|
404
|
+
if (headerRowEl.value && pinObserver) pinObserver.observe(headerRowEl.value);
|
|
405
|
+
measurePinned();
|
|
406
|
+
syncScrollX();
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
onBeforeUnmount(() => pinObserver?.disconnect());
|
|
244
411
|
const SUBGRID_ROW = "grid-column: 1 / -1; grid-template-columns: subgrid;";
|
|
245
412
|
const placeholder = computed(
|
|
246
413
|
() => typeof props.search === "object" ? props.search.placeholder ?? t("shared.datatable.toolbar.search.placeholder.default") : t("shared.datatable.toolbar.search.placeholder.default")
|
|
@@ -251,7 +418,7 @@ const searchLabel = computed(() => {
|
|
|
251
418
|
});
|
|
252
419
|
const slots = useSlots();
|
|
253
420
|
const showToolbar = computed(
|
|
254
|
-
() => props.search || props.columnsMenu || props.filter || !!props.filterTabs || !!props.savedViews || !!props.viewModes?.length || !!props.rail || !!slots.actions || !!slots.scope || !!slots["toolbar-left"] || !!slots["toolbar-right"]
|
|
421
|
+
() => props.toolbar && (props.search || props.columnsMenu || props.filter || !!props.filterTabs || !!props.savedViews || !!props.viewModes?.length || !!props.rail || !!slots.actions || !!slots.scope || !!slots["toolbar-left"] || !!slots["toolbar-right"])
|
|
255
422
|
);
|
|
256
423
|
const railLabel = computed(
|
|
257
424
|
() => (typeof props.rail === "object" ? props.rail.label : void 0) ?? null
|
|
@@ -282,7 +449,7 @@ function measureFit() {
|
|
|
282
449
|
if (!el) return;
|
|
283
450
|
const container = scrollParent(el);
|
|
284
451
|
const offset = el.getBoundingClientRect().top - container.getBoundingClientRect().top + container.scrollTop;
|
|
285
|
-
const reserve = (footerEl.value?.offsetHeight ?? 0) + BOTTOM_GAP_PX;
|
|
452
|
+
const reserve = (footerEl.value?.offsetHeight ?? 0) + BOTTOM_GAP_PX + (props.reserveBottom ?? 0);
|
|
286
453
|
const overflow = Math.max(container.scrollHeight - container.clientHeight, 0);
|
|
287
454
|
const available = Math.max(
|
|
288
455
|
Math.floor(container.clientHeight - offset - reserve - overflow) - 1,
|
|
@@ -317,6 +484,7 @@ if (import.meta.client) {
|
|
|
317
484
|
schedule();
|
|
318
485
|
syncThumb();
|
|
319
486
|
}));
|
|
487
|
+
watch(() => props.reserveBottom, () => nextTick(schedule));
|
|
320
488
|
onMounted(() => {
|
|
321
489
|
nextTick(syncThumb);
|
|
322
490
|
window.addEventListener("resize", syncThumb);
|
|
@@ -346,6 +514,7 @@ function syncThumb() {
|
|
|
346
514
|
}
|
|
347
515
|
function onRowsScroll() {
|
|
348
516
|
syncThumb();
|
|
517
|
+
syncScrollX();
|
|
349
518
|
}
|
|
350
519
|
function startThumbDrag(event) {
|
|
351
520
|
const el = scrollEl.value;
|
|
@@ -380,7 +549,7 @@ const scrollStyle = computed(() => {
|
|
|
380
549
|
const configured = typeof props.scrollBody === "object" ? props.scrollBody.maxHeight : void 0;
|
|
381
550
|
return { maxHeight: configured ?? "calc(100vh - 22rem)" };
|
|
382
551
|
});
|
|
383
|
-
const showFooter = computed(() => props.pagination !== false && !props.groupBy);
|
|
552
|
+
const showFooter = computed(() => props.pagination !== false && !props.groupBy && !(totalCount.value === 0 && !props.loading));
|
|
384
553
|
const lastPage = computed(
|
|
385
554
|
() => pageSize.value > 0 ? Math.max(0, Math.ceil(totalCount.value / pageSize.value) - 1) : 0
|
|
386
555
|
);
|
|
@@ -394,6 +563,88 @@ function prevPage() {
|
|
|
394
563
|
function nextPage() {
|
|
395
564
|
if (page.value < lastPage.value) page.value += 1;
|
|
396
565
|
}
|
|
566
|
+
const MOVE_COLUMN = "__move";
|
|
567
|
+
const renderColumns = computed(() => props.reorderable ? [{ key: MOVE_COLUMN, label: "", width: "max-content" }, ...visibleColumns.value] : visibleColumns.value);
|
|
568
|
+
const reorderBlocked = computed(() => {
|
|
569
|
+
if (!props.reorderable) return null;
|
|
570
|
+
if (props.reorderDisabled) return props.reorderDisabled;
|
|
571
|
+
if (!props.serverMode && query.value.trim()) return t("shared.datatable.reorder.blocked.search");
|
|
572
|
+
if (Object.values(activeFilters.value).some((v) => v.length)) return t("shared.datatable.reorder.blocked.filter");
|
|
573
|
+
if (props.groupBy) return t("shared.datatable.reorder.blocked.group");
|
|
574
|
+
return null;
|
|
575
|
+
});
|
|
576
|
+
const dragKey = ref(null);
|
|
577
|
+
const dropAt = ref(null);
|
|
578
|
+
const moveStatus = ref("");
|
|
579
|
+
function orderedKeys() {
|
|
580
|
+
return sorted.value.map(rowKeyFor);
|
|
581
|
+
}
|
|
582
|
+
function commitMove(keys, from, to) {
|
|
583
|
+
emit("rowMove", { key: keys[from], from, to, keys: moveKey(keys, from, to) });
|
|
584
|
+
moveStatus.value = t("shared.datatable.reorder.moved", { position: to + 1, total: keys.length });
|
|
585
|
+
}
|
|
586
|
+
function finishDrag() {
|
|
587
|
+
dragKey.value = null;
|
|
588
|
+
dropAt.value = null;
|
|
589
|
+
}
|
|
590
|
+
function onHandleDragStart(event, row) {
|
|
591
|
+
if (reorderBlocked.value) {
|
|
592
|
+
event.preventDefault();
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
const key = rowKeyFor(row);
|
|
596
|
+
dragKey.value = key;
|
|
597
|
+
if (event.dataTransfer) {
|
|
598
|
+
event.dataTransfer.effectAllowed = "move";
|
|
599
|
+
event.dataTransfer.setData("text/plain", String(key));
|
|
600
|
+
const rowEl = event.target?.closest('[role="row"]');
|
|
601
|
+
if (rowEl) event.dataTransfer.setDragImage(rowEl, 16, 16);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function onRowDragOver(event, row) {
|
|
605
|
+
if (dragKey.value == null) return;
|
|
606
|
+
event.preventDefault();
|
|
607
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
|
|
608
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
609
|
+
dropAt.value = { key: rowKeyFor(row), edge: dropEdge(event.clientY, rect.top, rect.height) };
|
|
610
|
+
}
|
|
611
|
+
function onRowDrop(event, row) {
|
|
612
|
+
if (dragKey.value == null) return;
|
|
613
|
+
event.preventDefault();
|
|
614
|
+
const keys = orderedKeys();
|
|
615
|
+
const from = keys.indexOf(dragKey.value);
|
|
616
|
+
const target = keys.indexOf(rowKeyFor(row));
|
|
617
|
+
const edge = dropAt.value?.edge ?? "before";
|
|
618
|
+
finishDrag();
|
|
619
|
+
const to = dropTargetIndex(from, target, edge);
|
|
620
|
+
if (to !== null) commitMove(keys, from, to);
|
|
621
|
+
}
|
|
622
|
+
function onHandleKeydown(event, row) {
|
|
623
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
624
|
+
event.preventDefault();
|
|
625
|
+
if (reorderBlocked.value) return;
|
|
626
|
+
const keys = orderedKeys();
|
|
627
|
+
const key = rowKeyFor(row);
|
|
628
|
+
const from = keys.indexOf(key);
|
|
629
|
+
const to = stepTarget(from, event.key === "ArrowUp" ? -1 : 1, keys.length);
|
|
630
|
+
if (to === null) return;
|
|
631
|
+
commitMove(keys, from, to);
|
|
632
|
+
const handle = event.currentTarget;
|
|
633
|
+
const root = handle.closest('[role="table"]');
|
|
634
|
+
void nextTick(() => setTimeout(() => {
|
|
635
|
+
const again = root?.querySelector(`[data-move-key="${CSS.escape(String(key))}"]`);
|
|
636
|
+
again?.focus();
|
|
637
|
+
}, 0));
|
|
638
|
+
}
|
|
639
|
+
function dropClass(row) {
|
|
640
|
+
const at = dropAt.value;
|
|
641
|
+
if (!at || dragKey.value == null || at.key !== rowKeyFor(row)) return "";
|
|
642
|
+
return at.edge === "before" ? "shadow-[inset_0_2px_0_0_var(--color-primary)]" : "shadow-[inset_0_-2px_0_0_var(--color-primary)]";
|
|
643
|
+
}
|
|
644
|
+
function rowGround(row) {
|
|
645
|
+
if (props.activeRowKey != null && rowKeyFor(row) === props.activeRowKey) return "bg-[#f5f1fe]";
|
|
646
|
+
return props.rowClass?.(row) || "bg-gray-50";
|
|
647
|
+
}
|
|
397
648
|
function defaultCell(col, row) {
|
|
398
649
|
const v = col.sortGetter ? col.sortGetter(row) : row[col.key];
|
|
399
650
|
if (v == null) return "\u2014";
|
|
@@ -402,7 +653,7 @@ function defaultCell(col, row) {
|
|
|
402
653
|
</script>
|
|
403
654
|
|
|
404
655
|
<template>
|
|
405
|
-
<div class="rounded-lg border border-black/[0.06]
|
|
656
|
+
<div class="overflow-hidden flex flex-col" :class="embedded ? 'bg-white' : 'rounded-lg border border-black/[0.06]'">
|
|
406
657
|
<!-- Toolbar ------------------------------------------------------ -->
|
|
407
658
|
<!-- The single control row of a list surface.
|
|
408
659
|
|
|
@@ -439,9 +690,11 @@ function defaultCell(col, row) {
|
|
|
439
690
|
in it. -->
|
|
440
691
|
<div
|
|
441
692
|
v-if="showToolbar"
|
|
442
|
-
class="flex flex-wrap items-center justify-between gap-2 px-4 py-3
|
|
693
|
+
class="flex flex-wrap items-center justify-between gap-2 px-4 py-3 xl:flex-nowrap"
|
|
694
|
+
:class="embedded ? 'bg-white' : 'bg-gradient-to-r from-violet-50/80 via-white to-violet-50/60'"
|
|
443
695
|
>
|
|
444
|
-
|
|
696
|
+
<!-- One line on a wide screen (UI-F10): the search gives way first. -->
|
|
697
|
+
<div class="flex min-w-0 flex-wrap items-center gap-2 max-sm:w-full xl:flex-1 xl:flex-nowrap">
|
|
445
698
|
<Button
|
|
446
699
|
v-if="rail"
|
|
447
700
|
variant="outline"
|
|
@@ -469,7 +722,7 @@ function defaultCell(col, row) {
|
|
|
469
722
|
v-model="query"
|
|
470
723
|
:placeholder="placeholder"
|
|
471
724
|
:label="searchLabel"
|
|
472
|
-
class="w-
|
|
725
|
+
class="w-full min-w-40 max-w-full shrink sm:w-[21rem] xl:w-auto xl:flex-1 xl:max-w-[21rem]"
|
|
473
726
|
>
|
|
474
727
|
<template #icon>
|
|
475
728
|
<Search :size="14" weight="Linear" />
|
|
@@ -501,8 +754,20 @@ function defaultCell(col, row) {
|
|
|
501
754
|
:reset-label="t('shared.datatable.toolbar.filter.reset')"
|
|
502
755
|
@update:model-value="applyPanelSelection"
|
|
503
756
|
>
|
|
504
|
-
|
|
505
|
-
|
|
757
|
+
<!-- D7 (Charge 2): tool buttons carry their word on desktop, the
|
|
758
|
+
glyph alone on phones. studio's trigger is icon-only by design
|
|
759
|
+
(ToolbarFilterTrigger icon-only), so the dummy draws its own
|
|
760
|
+
trigger through the panel's `trigger` slot. -->
|
|
761
|
+
<template #trigger="{ count }">
|
|
762
|
+
<ToolbarLabelTrigger
|
|
763
|
+
:active="count > 0"
|
|
764
|
+
:count="count"
|
|
765
|
+
:label="t('shared.datatable.toolbar.filter.action')"
|
|
766
|
+
>
|
|
767
|
+
<template #icon>
|
|
768
|
+
<Filter :size="14" weight="BoldDuotone" />
|
|
769
|
+
</template>
|
|
770
|
+
</ToolbarLabelTrigger>
|
|
506
771
|
</template>
|
|
507
772
|
</FilterPanel>
|
|
508
773
|
<!--
|
|
@@ -517,8 +782,14 @@ function defaultCell(col, row) {
|
|
|
517
782
|
v-model="facetSelection"
|
|
518
783
|
:facets="facets"
|
|
519
784
|
/>
|
|
785
|
+
<!--
|
|
786
|
+
No `#filter-menu`, no trigger: `filter` alone used to draw a Filter
|
|
787
|
+
button that opened on "No filters defined" — a control promising to
|
|
788
|
+
narrow the list and refusing to (PO-313). The other two routes draw
|
|
789
|
+
only when the surface declared facets or dimensions.
|
|
790
|
+
-->
|
|
520
791
|
<FilterMenu
|
|
521
|
-
v-if="filter && !panelFacets.length"
|
|
792
|
+
v-if="filter && slots['filter-menu'] && !panelFacets.length"
|
|
522
793
|
:width="typeof filter === 'object' ? filter.width : void 0"
|
|
523
794
|
:active="typeof filter === 'object' ? filter.active : void 0"
|
|
524
795
|
:count="typeof filter === 'object' ? filter.count : void 0"
|
|
@@ -540,10 +811,16 @@ function defaultCell(col, row) {
|
|
|
540
811
|
:model-value="pickerColumns"
|
|
541
812
|
:label="t('shared.datatable.columnsmenu.tooltip')"
|
|
542
813
|
:heading="t('shared.datatable.columnsmenu.heading')"
|
|
814
|
+
class="w-8 gap-1.5 px-0 [&_span.bg-primary]:hidden"
|
|
543
815
|
@update:model-value="onPickerUpdate"
|
|
544
816
|
>
|
|
817
|
+
<!-- No count on the trigger (Michael: no count badges, PE-1082): the
|
|
818
|
+
studio picker draws one; hidden here until it has a prop.
|
|
819
|
+
D7: the word rides in the icon slot — studio's picker has no
|
|
820
|
+
label slot yet (see the studio change list in the ledger). -->
|
|
545
821
|
<template #icon>
|
|
546
822
|
<Columns :size="15" weight="BoldDuotone" />
|
|
823
|
+
<span class="sr-only">{{ t("shared.datatable.columnsmenu.tooltip") }}</span>
|
|
547
824
|
</template>
|
|
548
825
|
<template #handle>
|
|
549
826
|
<ListArrowDownMinimalistic :size="15" weight="Linear" />
|
|
@@ -555,6 +832,33 @@ function defaultCell(col, row) {
|
|
|
555
832
|
<EyeClosed :size="16" weight="Linear" />
|
|
556
833
|
</template>
|
|
557
834
|
</ColumnPicker>
|
|
835
|
+
<!-- Row height (D4, Charge 2): standard 44px, compact 36px. -->
|
|
836
|
+
<SegmentedToggle
|
|
837
|
+
v-if="showTable && !cardMode"
|
|
838
|
+
:model-value="density"
|
|
839
|
+
variant="inset"
|
|
840
|
+
:aria-label="t('shared.datatable.toolbar.density.label')"
|
|
841
|
+
@update:model-value="(v) => v && setDensity(v)"
|
|
842
|
+
>
|
|
843
|
+
<SegmentedToggleItem
|
|
844
|
+
value="standard"
|
|
845
|
+
:aria-label="t('shared.datatable.toolbar.density.standard')"
|
|
846
|
+
:title="t('shared.datatable.toolbar.density.standard')"
|
|
847
|
+
class="transition-colors data-[state=on]:text-primary data-[state=off]:hover:text-primary!"
|
|
848
|
+
>
|
|
849
|
+
<AlignVerticalSpacing :size="14" weight="Linear" />
|
|
850
|
+
<span class="sr-only">{{ t("shared.datatable.toolbar.density.standard") }}</span>
|
|
851
|
+
</SegmentedToggleItem>
|
|
852
|
+
<SegmentedToggleItem
|
|
853
|
+
value="compact"
|
|
854
|
+
:aria-label="t('shared.datatable.toolbar.density.compact')"
|
|
855
|
+
:title="t('shared.datatable.toolbar.density.compact')"
|
|
856
|
+
class="transition-colors data-[state=on]:text-primary data-[state=off]:hover:text-primary!"
|
|
857
|
+
>
|
|
858
|
+
<DragHandle :size="14" weight="Linear" />
|
|
859
|
+
<span class="sr-only">{{ t("shared.datatable.toolbar.density.compact") }}</span>
|
|
860
|
+
</SegmentedToggleItem>
|
|
861
|
+
</SegmentedToggle>
|
|
558
862
|
<!--
|
|
559
863
|
Saved views, beside the columns picker rather than out past the market
|
|
560
864
|
scope and the view-mode switch.
|
|
@@ -656,41 +960,55 @@ function defaultCell(col, row) {
|
|
|
656
960
|
that. A static table read with a screen reader's own table commands is
|
|
657
961
|
what these lists actually are, and both roles announce the column
|
|
658
962
|
heading with the cell, which is the thing that was missing. -->
|
|
659
|
-
<div :class="scrollBody ? 'relative flex min-h-0 flex-col' : ''">
|
|
963
|
+
<div :class="scrollBody && !cardMode ? 'relative flex min-h-0 flex-col' : 'relative'">
|
|
660
964
|
<div
|
|
661
965
|
ref="scrollEl"
|
|
662
|
-
:class="scrollBody ? 'rx-rows min-h-0 overflow-auto' : 'overflow-x-auto'"
|
|
663
|
-
:style="scrollStyle"
|
|
966
|
+
:class="scrollBody && !cardMode ? 'rx-rows min-h-0 overflow-auto' : 'overflow-x-auto'"
|
|
967
|
+
:style="cardMode ? void 0 : scrollStyle"
|
|
664
968
|
@scroll="onRowsScroll"
|
|
665
969
|
>
|
|
666
970
|
<div
|
|
667
971
|
:role="showTable ? 'table' : void 0"
|
|
668
972
|
:aria-busy="showTable && loading ? 'true' : void 0"
|
|
669
|
-
:class="showTable ? 'grid min-w-min gap-x-2' : ''"
|
|
670
|
-
:style="showTable ? gridTemplate : void 0"
|
|
973
|
+
:class="showTable && !cardMode ? 'grid min-w-min gap-x-2' : ''"
|
|
974
|
+
:style="showTable && !cardMode ? gridTemplate : void 0"
|
|
671
975
|
>
|
|
672
976
|
<!-- Header row -------------------------------------------------- -->
|
|
673
977
|
<div
|
|
674
|
-
v-if="showTable"
|
|
978
|
+
v-if="showTable && !cardMode"
|
|
675
979
|
ref="headerRowEl"
|
|
676
980
|
role="row"
|
|
677
|
-
|
|
678
|
-
|
|
981
|
+
data-rx-head
|
|
982
|
+
class="grid items-center gap-x-2 border-gray-200 px-4 py-2.5 text-sm font-medium uppercase tracking-normal text-muted-foreground"
|
|
983
|
+
:class="[
|
|
984
|
+
scrollBody ? 'sticky top-0 z-10' : '',
|
|
985
|
+
embedded ? 'bg-gray-100' : 'rounded-t-lg bg-gray-100',
|
|
986
|
+
// Embedded with the search row closed, the card head\'s own bottom
|
|
987
|
+
// edge is already the line above the headings; a second one here drew
|
|
988
|
+
// a double rule (Michael 14.10.).
|
|
989
|
+
embedded && !showToolbar ? '' : 'border-t'
|
|
990
|
+
]"
|
|
679
991
|
:style="SUBGRID_ROW"
|
|
680
992
|
>
|
|
993
|
+
<!-- The handle column's heading: nothing to see, but a columnheader the
|
|
994
|
+
handles' cells can be named by. -->
|
|
995
|
+
<div v-if="reorderable" role="columnheader" class="w-6" :style="pinnedStyle(0)">
|
|
996
|
+
<span class="sr-only">{{ t("shared.datatable.reorder.column") }}</span>
|
|
997
|
+
</div>
|
|
681
998
|
<!-- `columnheader` is what names every cell underneath it, so this is
|
|
682
999
|
the half of the fix that does the work. `aria-sort` goes with it:
|
|
683
1000
|
a heading that carries a sort button and says nothing about the
|
|
684
1001
|
current direction is a control whose state is visible only to
|
|
685
1002
|
people who can see the arrow. -->
|
|
686
1003
|
<div
|
|
687
|
-
v-for="col in visibleColumns"
|
|
1004
|
+
v-for="(col, ci) in visibleColumns"
|
|
688
1005
|
:key="col.key"
|
|
689
1006
|
role="columnheader"
|
|
690
1007
|
:aria-sort="ariaSortFor(col)"
|
|
691
1008
|
:title="col.label || void 0"
|
|
692
1009
|
class="min-w-0"
|
|
693
|
-
:class="col.alignRight ? '
|
|
1010
|
+
:class="[col.alignRight ? RIGHT_ALIGNED : '', pinnedClass(ci + (reorderable ? 1 : 0)), rightPinClass(col)]"
|
|
1011
|
+
:style="rightPinStyle(col) ?? pinnedStyle(ci + (reorderable ? 1 : 0))"
|
|
694
1012
|
>
|
|
695
1013
|
<!-- `#header-<key>` lets a page take over a header cell (e.g. a
|
|
696
1014
|
select-all checkbox in a selection column). Default: sortable
|
|
@@ -704,19 +1022,74 @@ function defaultCell(col, row) {
|
|
|
704
1022
|
:align-right="col.alignRight"
|
|
705
1023
|
@toggle="toggleSort"
|
|
706
1024
|
>
|
|
707
|
-
{{ col.label }}
|
|
1025
|
+
<span :class="headerNoWrap(col)">{{ col.label }}</span>
|
|
708
1026
|
</SortHeader>
|
|
709
1027
|
<!-- `normal-case` to match SortHeader, whose button does not inherit
|
|
710
1028
|
the row's uppercase. Without it a column reads "LAST CHECK"
|
|
711
1029
|
beside "Channel" and "Provider" for no reason a reader can see —
|
|
712
1030
|
the header shouts wherever a column happens not to be sortable. -->
|
|
713
|
-
<span v-else class="block
|
|
1031
|
+
<span v-else class="block break-normal leading-tight normal-case" :class="headerNoWrap(col)">{{ col.label }}</span>
|
|
714
1032
|
</slot>
|
|
715
1033
|
</div>
|
|
716
1034
|
</div>
|
|
717
1035
|
|
|
718
1036
|
<!-- Body --------------------------------------------------------- -->
|
|
719
|
-
|
|
1037
|
+
<!-- Phone (R4, Charge 2): one card per row. Title and status on the first
|
|
1038
|
+
line, then up to four key facts in two lines, in column priority. The
|
|
1039
|
+
same cell slots render inside, so a card shows exactly what the row
|
|
1040
|
+
would. -->
|
|
1041
|
+
<template v-if="showTable && cardMode">
|
|
1042
|
+
<div
|
|
1043
|
+
v-for="entry in renderRows"
|
|
1044
|
+
:key="entry.key"
|
|
1045
|
+
:role="entry.kind === 'header' ? void 0 : 'button'"
|
|
1046
|
+
:data-row="entry.kind === 'header' ? void 0 : ''"
|
|
1047
|
+
:tabindex="entry.kind === 'header' ? void 0 : 0"
|
|
1048
|
+
class="border-t border-black/[0.04]"
|
|
1049
|
+
:class="entry.kind === 'header' ? 'bg-gray-100/70 px-4 py-1.5 text-xs font-medium uppercase tracking-wide text-muted-foreground' : ['group cursor-pointer px-4 py-3', rowGround(entry.row)]"
|
|
1050
|
+
@click="entry.kind !== 'header' && emit('rowClick', entry.row)"
|
|
1051
|
+
@keydown.enter="entry.kind !== 'header' && emit('rowClick', entry.row)"
|
|
1052
|
+
>
|
|
1053
|
+
<template v-if="entry.kind === 'header'">
|
|
1054
|
+
{{ entry.label }} <span class="tabular-nums normal-case text-muted-foreground/70">{{ entry.count }}</span>
|
|
1055
|
+
</template>
|
|
1056
|
+
<template v-else>
|
|
1057
|
+
<div class="flex items-start gap-3">
|
|
1058
|
+
<div v-if="cardLayout.select" class="pt-0.5" @click.stop>
|
|
1059
|
+
<slot :name="`cell-${cardLayout.select.key}`" :row="entry.row" />
|
|
1060
|
+
</div>
|
|
1061
|
+
<div class="min-w-0 flex-1">
|
|
1062
|
+
<div class="flex items-start justify-between gap-2">
|
|
1063
|
+
<div v-if="cardLayout.title" class="min-w-0 flex-1 text-sm font-semibold text-[#0B0522] [&_*]:max-w-full">
|
|
1064
|
+
<slot :name="`cell-${cardLayout.title.key}`" :row="entry.row">
|
|
1065
|
+
<span class="block truncate">{{ defaultCell(cardLayout.title, entry.row) }}</span>
|
|
1066
|
+
</slot>
|
|
1067
|
+
</div>
|
|
1068
|
+
<div v-if="cardLayout.status" class="shrink-0">
|
|
1069
|
+
<slot :name="`cell-${cardLayout.status.key}`" :row="entry.row">
|
|
1070
|
+
<span class="text-sm">{{ defaultCell(cardLayout.status, entry.row) }}</span>
|
|
1071
|
+
</slot>
|
|
1072
|
+
</div>
|
|
1073
|
+
<div v-if="cardLayout.actions" class="-mr-1 shrink-0" @click.stop>
|
|
1074
|
+
<slot :name="`cell-${cardLayout.actions.key}`" :row="entry.row" />
|
|
1075
|
+
</div>
|
|
1076
|
+
</div>
|
|
1077
|
+
<dl v-if="cardLayout.meta.length" class="mt-1.5 grid grid-cols-2 gap-x-3 gap-y-1">
|
|
1078
|
+
<div v-for="m in cardLayout.meta" :key="m.key" class="min-w-0">
|
|
1079
|
+
<dt class="truncate text-xs text-muted-foreground">{{ m.label }}</dt>
|
|
1080
|
+
<dd class="min-w-0 truncate text-sm">
|
|
1081
|
+
<slot :name="`cell-${m.key}`" :row="entry.row">
|
|
1082
|
+
<span class="block truncate">{{ defaultCell(m, entry.row) }}</span>
|
|
1083
|
+
</slot>
|
|
1084
|
+
</dd>
|
|
1085
|
+
</div>
|
|
1086
|
+
</dl>
|
|
1087
|
+
</div>
|
|
1088
|
+
</div>
|
|
1089
|
+
</template>
|
|
1090
|
+
</div>
|
|
1091
|
+
</template>
|
|
1092
|
+
<template v-for="entry in showTable && !cardMode ? renderRows : []" :key="entry.key">
|
|
720
1093
|
<!-- Group header (groupBy mode) — a row of one cell that spans the lot.
|
|
721
1094
|
The flex moves one element in, onto the cell: a `row` may hold
|
|
722
1095
|
cells and the label and the count are neither. -->
|
|
@@ -728,24 +1101,50 @@ function defaultCell(col, row) {
|
|
|
728
1101
|
<!-- Spans every column like the rows do, so a table wide enough to
|
|
729
1102
|
scroll does not show this band stopping short of the rows it
|
|
730
1103
|
groups. No subgrid: it holds one cell, not a set of columns. -->
|
|
731
|
-
<div role="cell" :aria-colspan="
|
|
732
|
-
{{ entry.label }}
|
|
1104
|
+
<div role="cell" :aria-colspan="renderColumns.length" class="flex items-center gap-2">
|
|
1105
|
+
<slot name="group-header" :label="entry.label">{{ entry.label }}</slot>
|
|
733
1106
|
<span class="tabular-nums normal-case text-muted-foreground/70">{{ entry.count }}</span>
|
|
734
1107
|
</div>
|
|
735
1108
|
</div>
|
|
736
1109
|
<div
|
|
737
1110
|
v-else
|
|
738
1111
|
role="row"
|
|
739
|
-
|
|
1112
|
+
data-row
|
|
1113
|
+
class="group grid items-center gap-x-2 border-t border-black/[0.04] px-4 cursor-pointer transition-colors"
|
|
1114
|
+
:class="[density === 'compact' ? 'min-h-9 py-1' : 'min-h-11 py-2', rowGround(entry.row), dropClass(entry.row), dragKey != null && dragKey === rowKeyFor(entry.row) ? 'opacity-50' : '']"
|
|
1115
|
+
:aria-current="activeRowKey != null && rowKeyFor(entry.row) === activeRowKey ? 'true' : void 0"
|
|
740
1116
|
:style="SUBGRID_ROW"
|
|
741
1117
|
@click="emit('rowClick', entry.row)"
|
|
1118
|
+
@dragover="onRowDragOver($event, entry.row)"
|
|
1119
|
+
@drop="onRowDrop($event, entry.row)"
|
|
742
1120
|
>
|
|
1121
|
+
<!-- The grip. A button, so it is reachable and the arrow keys can move
|
|
1122
|
+
the row; `draggable` on it rather than on the row, so selecting a
|
|
1123
|
+
cell's text or clicking an inline input never starts a drag. -->
|
|
1124
|
+
<div v-if="reorderable" role="cell" class="flex items-center" :style="pinnedStyle(0)" @click.stop>
|
|
1125
|
+
<button
|
|
1126
|
+
type="button"
|
|
1127
|
+
:data-move-key="String(rowKeyFor(entry.row))"
|
|
1128
|
+
:draggable="!reorderBlocked"
|
|
1129
|
+
:aria-disabled="reorderBlocked ? 'true' : void 0"
|
|
1130
|
+
:aria-label="t('shared.datatable.reorder.handle')"
|
|
1131
|
+
:title="reorderBlocked ?? t('shared.datatable.reorder.hint')"
|
|
1132
|
+
class="inline-flex size-6 items-center justify-center rounded-md text-muted-foreground transition-colors"
|
|
1133
|
+
:class="reorderBlocked ? 'cursor-not-allowed opacity-30' : 'cursor-grab hover:bg-muted hover:text-primary active:cursor-grabbing'"
|
|
1134
|
+
@dragstart="onHandleDragStart($event, entry.row)"
|
|
1135
|
+
@dragend="finishDrag"
|
|
1136
|
+
@keydown="onHandleKeydown($event, entry.row)"
|
|
1137
|
+
>
|
|
1138
|
+
<DragHandle :size="14" weight="Linear" />
|
|
1139
|
+
</button>
|
|
1140
|
+
</div>
|
|
743
1141
|
<div
|
|
744
|
-
v-for="col in visibleColumns"
|
|
1142
|
+
v-for="(col, ci) in visibleColumns"
|
|
745
1143
|
:key="col.key"
|
|
746
1144
|
role="cell"
|
|
747
1145
|
class="min-w-0"
|
|
748
|
-
:class="col.alignRight ? '
|
|
1146
|
+
:class="[col.alignRight ? RIGHT_ALIGNED : '', pinnedClass(ci + (reorderable ? 1 : 0)), rightPinClass(col)]"
|
|
1147
|
+
:style="rightPinStyle(col) ?? pinnedStyle(ci + (reorderable ? 1 : 0))"
|
|
749
1148
|
>
|
|
750
1149
|
<slot :name="`cell-${col.key}`" :row="entry.row">
|
|
751
1150
|
<!-- Primary column: bold record anchor + optional tinted icon tile. -->
|
|
@@ -772,7 +1171,7 @@ function defaultCell(col, row) {
|
|
|
772
1171
|
information to read out, and announcing them as six empty rows would
|
|
773
1172
|
be worse than silence; the table says it is `aria-busy` instead,
|
|
774
1173
|
which is the same news in one word. -->
|
|
775
|
-
<template v-if="showTable && loading && !displayedRows.length">
|
|
1174
|
+
<template v-if="showTable && !cardMode && loading && !displayedRows.length">
|
|
776
1175
|
<div
|
|
777
1176
|
v-for="n in 6"
|
|
778
1177
|
:key="`sk-${n}`"
|
|
@@ -781,7 +1180,7 @@ function defaultCell(col, row) {
|
|
|
781
1180
|
:style="SUBGRID_ROW"
|
|
782
1181
|
>
|
|
783
1182
|
<div
|
|
784
|
-
v-for="col in
|
|
1183
|
+
v-for="col in renderColumns"
|
|
785
1184
|
:key="col.key"
|
|
786
1185
|
:class="col.alignRight ? 'flex justify-end' : ''"
|
|
787
1186
|
>
|
|
@@ -799,8 +1198,8 @@ function defaultCell(col, row) {
|
|
|
799
1198
|
role="row"
|
|
800
1199
|
class="col-[1/-1] px-3 py-8 text-center text-sm text-muted-foreground"
|
|
801
1200
|
>
|
|
802
|
-
<div role="cell" :aria-colspan="
|
|
803
|
-
<slot name="empty">
|
|
1201
|
+
<div role="cell" :aria-colspan="renderColumns.length">
|
|
1202
|
+
<slot name="empty" :query="query" :filters="activeNarrowing" :clear="clearNarrowing">
|
|
804
1203
|
{{ emptyText ?? t("shared.datatable.empty.default") }}
|
|
805
1204
|
</slot>
|
|
806
1205
|
</div>
|
|
@@ -809,6 +1208,24 @@ function defaultCell(col, row) {
|
|
|
809
1208
|
</div>
|
|
810
1209
|
</div>
|
|
811
1210
|
|
|
1211
|
+
<!-- More columns to the right (D5, Charge 2): a soft edge over the rows
|
|
1212
|
+
and a button that scrolls on, so a wide table says that it is wide
|
|
1213
|
+
instead of ending in a clipped "Stat…". -->
|
|
1214
|
+
<div
|
|
1215
|
+
v-if="showTable && !cardMode && moreRight"
|
|
1216
|
+
class="pointer-events-none absolute inset-y-0 right-0 z-[15] w-10 bg-gradient-to-l from-[rgb(11_5_34_/_0.07)] to-transparent"
|
|
1217
|
+
/>
|
|
1218
|
+
<!-- Never over the rows (UI-F02, EC-F30): a table without a footer gets
|
|
1219
|
+
a slim line under it instead of a pill covering the last cells. -->
|
|
1220
|
+
<div
|
|
1221
|
+
v-if="showTable && !cardMode && moreRight && !showFooter"
|
|
1222
|
+
class="relative z-20 flex justify-end border-t border-black/[0.06] bg-white/70 px-2 py-1"
|
|
1223
|
+
>
|
|
1224
|
+
<Button variant="ghost" size="sm" class="h-7 gap-1 text-xs" @click="scrollRight">
|
|
1225
|
+
{{ t("shared.datatable.scroll.more") }}
|
|
1226
|
+
<AltArrowRight :size="12" weight="Bold" />
|
|
1227
|
+
</Button>
|
|
1228
|
+
</div>
|
|
812
1229
|
<!-- The rows' scrollbar ---------------------------------------- -->
|
|
813
1230
|
<!-- Drawn, not borrowed. A browser's own bar belongs to the scrolling
|
|
814
1231
|
box, and the column head is inside that box — it has to be, because
|
|
@@ -829,11 +1246,18 @@ function defaultCell(col, row) {
|
|
|
829
1246
|
</div>
|
|
830
1247
|
</div>
|
|
831
1248
|
|
|
1249
|
+
<!-- Result count, spoken. Outside the table role: a live region is not
|
|
1250
|
+
a row, and the table may own rows only. -->
|
|
1251
|
+
<span role="status" class="sr-only">{{ liveStatus }}</span>
|
|
1252
|
+
<!-- A move, said once: a reader who stepped a row with the arrow keys
|
|
1253
|
+
hears where it landed. -->
|
|
1254
|
+
<span v-if="reorderable" role="status" class="sr-only">{{ moveStatus }}</span>
|
|
1255
|
+
|
|
832
1256
|
<!-- Footer ------------------------------------------------------- -->
|
|
833
1257
|
<div
|
|
834
1258
|
v-if="showFooter"
|
|
835
1259
|
ref="footerEl"
|
|
836
|
-
class="flex items-center justify-between gap-2 border-t border-gray-200 bg-white/55 backdrop-blur-md px-4 py-3 text-sm text-muted-foreground
|
|
1260
|
+
class="flex items-center justify-between gap-2 border-t border-gray-200 bg-white/55 backdrop-blur-md px-4 py-3 text-sm text-muted-foreground"
|
|
837
1261
|
>
|
|
838
1262
|
<div class="flex items-center gap-2.5">
|
|
839
1263
|
<span class="tabular-nums">
|
|
@@ -851,11 +1275,23 @@ function defaultCell(col, row) {
|
|
|
851
1275
|
</select>
|
|
852
1276
|
</label>
|
|
853
1277
|
</div>
|
|
1278
|
+
<div class="ml-auto flex items-center gap-2">
|
|
1279
|
+
<Button
|
|
1280
|
+
v-if="showTable && !cardMode && moreRight"
|
|
1281
|
+
variant="ghost"
|
|
1282
|
+
size="sm"
|
|
1283
|
+
class="gap-1"
|
|
1284
|
+
@click="scrollRight"
|
|
1285
|
+
>
|
|
1286
|
+
{{ t("shared.datatable.scroll.more") }}
|
|
1287
|
+
<AltArrowRight :size="12" weight="Bold" />
|
|
1288
|
+
</Button>
|
|
1289
|
+
</div>
|
|
854
1290
|
<div v-if="lastPage > 0" class="flex items-center gap-2">
|
|
855
1291
|
<Button
|
|
856
1292
|
variant="outline"
|
|
857
1293
|
size="sm"
|
|
858
|
-
class="
|
|
1294
|
+
class="text-sm"
|
|
859
1295
|
:disabled="page === 0 || loading"
|
|
860
1296
|
@click="prevPage"
|
|
861
1297
|
>
|
|
@@ -867,7 +1303,7 @@ function defaultCell(col, row) {
|
|
|
867
1303
|
<Button
|
|
868
1304
|
variant="outline"
|
|
869
1305
|
size="sm"
|
|
870
|
-
class="
|
|
1306
|
+
class="text-sm"
|
|
871
1307
|
:disabled="page >= lastPage || loading"
|
|
872
1308
|
@click="nextPage"
|
|
873
1309
|
>
|
|
@@ -881,3 +1317,7 @@ function defaultCell(col, row) {
|
|
|
881
1317
|
<style scoped>
|
|
882
1318
|
.rx-rows::-webkit-scrollbar{height:10px;width:0}.rx-rows::-webkit-scrollbar-track{background:transparent}.rx-rows::-webkit-scrollbar-thumb{background:rgba(11,5,34,.18);background-clip:padding-box;border:3px solid transparent;border-radius:9999px}.rx-thumb{min-height:32px}
|
|
883
1319
|
</style>
|
|
1320
|
+
|
|
1321
|
+
<style>
|
|
1322
|
+
@media (max-width:767.98px){[data-reka-popper-content-wrapper]:has(>[data-slot=popover-content].w-\[34rem\]){inset:auto 0 0 0!important;min-width:0!important;position:fixed!important;transform:none!important}[data-reka-popper-content-wrapper]>[data-slot=popover-content].w-\[34rem\]{border-radius:.75rem .75rem 0 0!important;max-height:80svh;max-width:100vw!important;overflow:auto;padding-bottom:env(safe-area-inset-bottom);width:100vw!important}}
|
|
1323
|
+
</style>
|