690 lines
18 KiB
Vue
690 lines
18 KiB
Vue
<template>
|
||
<div class="admin-data-table">
|
||
<div v-if="exportable" class="clearfix admin-data-table__toolbar">
|
||
<div class="btn-group pull-right">
|
||
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"
|
||
aria-haspopup="true" aria-expanded="false">
|
||
<i class="fa fa-download"></i> Eksport <span class="caret"></span>
|
||
</button>
|
||
<ul class="dropdown-menu dropdown-menu-right">
|
||
<li><a href="#" @click.prevent="exportToCSV">Eksport CSV</a></li>
|
||
<li><a href="#" @click.prevent="exportToExcel">Eksport Excel</a></li>
|
||
<li><a href="#" @click.prevent="exportToPDF">Eksport PDF</a></li>
|
||
<li><a href="#" @click.prevent="exportToJSON">Eksport JSON</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="admin-data-table__shell">
|
||
<div class="admin-data-table__scroll">
|
||
<table class="admin-data-table__table table table-hover">
|
||
<thead>
|
||
<tr>
|
||
<th v-for="h in tableHeaders" :key="h.key" :class="{
|
||
'is-sortable': h.sortable,
|
||
'admin-data-table__col-index': h.key === '__adt_index'
|
||
}" @click="h.sortable && toggleSort(h.key)">
|
||
<div class="admin-data-table__th-inner">
|
||
<span class="admin-data-table__th-title">{{ h.title }}</span>
|
||
<span v-if="h.sortable" class="admin-data-table__sort" aria-hidden="true">
|
||
<template v-if="sortKey === h.key">
|
||
<svg v-if="sortDir === 'asc'" class="admin-data-table__sort-icon"
|
||
xmlns="http://www.w3.org/2000/svg" width="14" height="14"
|
||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
||
stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M18 15l-6-6-6 6" />
|
||
</svg>
|
||
<svg v-else class="admin-data-table__sort-icon"
|
||
xmlns="http://www.w3.org/2000/svg" width="14" height="14"
|
||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
||
stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M6 9l6 6 6-6" />
|
||
</svg>
|
||
</template>
|
||
<span v-else class="admin-data-table__sort-hint">
|
||
<svg class="admin-data-table__sort-icon admin-data-table__sort-icon--faint"
|
||
xmlns="http://www.w3.org/2000/svg" width="10" height="10"
|
||
viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="2.5">
|
||
<path d="M18 15l-6-6-6 6" />
|
||
</svg>
|
||
<svg class="admin-data-table__sort-icon admin-data-table__sort-icon--faint"
|
||
xmlns="http://www.w3.org/2000/svg" width="10" height="10"
|
||
viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="2.5">
|
||
<path d="M6 9l6 6 6-6" />
|
||
</svg>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-if="loading" class="admin-data-table__state-row">
|
||
<td :colspan="tableHeaders.length">
|
||
<div class="admin-data-table__state">
|
||
<i class="fa fa-refresh fa-spin admin-data-table__state-icon"></i>
|
||
<div class="admin-data-table__state-title">Memuatkan…</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr v-else-if="!displayRows.length" class="admin-data-table__state-row">
|
||
<td :colspan="tableHeaders.length">
|
||
<div class="admin-data-table__state">
|
||
<i class="fa fa-inbox admin-data-table__state-icon"></i>
|
||
<div class="admin-data-table__state-title">{{ emptyText }}</div>
|
||
<div class="admin-data-table__state-hint">Tiada rekod untuk dipaparkan</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr v-else v-for="(item, rowIdx) in displayRows" :key="String(item[itemKey])">
|
||
<td v-for="h in tableHeaders" :key="h.key" :class="cellTdClass(h)">
|
||
<template v-if="h.key === '__adt_index'">
|
||
{{ rowGlobalIndex(rowIdx) }}
|
||
</template>
|
||
<template v-else>
|
||
<slot :name="'item-' + h.key" :item="item" :value="cellValue(item, h.key)">
|
||
{{ formatCell(item, h.key) }}
|
||
</slot>
|
||
</template>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div v-if="showPagination && !loading && totalItems > 0" class="admin-data-table__footer">
|
||
<div class="admin-data-table__footer-left">
|
||
<label class="admin-data-table__footer-label">Baris setiap halaman</label>
|
||
<select v-model.number="localPerPage" class="form-control input-sm admin-data-table__page-size"
|
||
@change="onPerPageChange">
|
||
<option v-for="n in perPageOptions" :key="n" :value="n">{{ n }}</option>
|
||
</select>
|
||
</div>
|
||
<div class="admin-data-table__footer-mid">
|
||
{{ rangeFrom }}–{{ rangeTo }} daripada {{ totalItems }}
|
||
</div>
|
||
<nav class="admin-data-table__footer-right" aria-label="Pagination">
|
||
<ul class="pagination pagination-sm admin-data-table__pagination">
|
||
<li :class="{ disabled: page <= 1 }">
|
||
<a href="#" @click.prevent="goPage(page - 1)">Sebelum</a>
|
||
</li>
|
||
<li :class="{ disabled: page >= totalPages }">
|
||
<a href="#" @click.prevent="goPage(page + 1)">Seterusnya</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { jsPDF } from 'jspdf';
|
||
import autoTable from 'jspdf-autotable';
|
||
import * as XLSX from 'xlsx';
|
||
import { saveAs } from 'file-saver';
|
||
|
||
export default {
|
||
name: 'AdminDataTable',
|
||
|
||
props: {
|
||
headers: {
|
||
type: Array,
|
||
default: function () {
|
||
return [];
|
||
}
|
||
},
|
||
items: {
|
||
type: Array,
|
||
default: function () {
|
||
return [];
|
||
}
|
||
},
|
||
itemsPerPage: {
|
||
type: Number,
|
||
default: 10
|
||
},
|
||
showPagination: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
loading: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
itemKey: {
|
||
type: String,
|
||
default: 'id'
|
||
},
|
||
emptyText: {
|
||
type: String,
|
||
default: 'Tiada data'
|
||
},
|
||
exportable: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
exportFileName: {
|
||
type: String,
|
||
default: 'table-data'
|
||
},
|
||
showIndex: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
indexTitle: {
|
||
type: String,
|
||
default: 'Bil'
|
||
}
|
||
},
|
||
|
||
data: function () {
|
||
return {
|
||
page: 1,
|
||
localPerPage: this.itemsPerPage,
|
||
sortKey: null,
|
||
sortDir: 'asc',
|
||
perPageOptions: [10, 25, 50, 100, 500, 1000]
|
||
};
|
||
},
|
||
|
||
computed: {
|
||
totalItems: function () {
|
||
return this.sortedItems.length;
|
||
},
|
||
totalPages: function () {
|
||
var n = Math.ceil(this.totalItems / this.localPerPage) || 1;
|
||
return n;
|
||
},
|
||
sortedItems: function () {
|
||
var list = this.items.slice();
|
||
if (!this.sortKey) {
|
||
return list;
|
||
}
|
||
var key = this.sortKey;
|
||
var dir = this.sortDir === 'desc' ? -1 : 1;
|
||
list.sort(function (a, b) {
|
||
var va = a[key];
|
||
var vb = b[key];
|
||
if (va == null && vb == null) return 0;
|
||
if (va == null) return 1;
|
||
if (vb == null) return -1;
|
||
if (typeof va === 'number' && typeof vb === 'number') {
|
||
return (va - vb) * dir;
|
||
}
|
||
return String(va).localeCompare(String(vb), undefined, { numeric: true }) * dir;
|
||
});
|
||
return list;
|
||
},
|
||
displayRows: function () {
|
||
if (!this.showPagination) {
|
||
return this.sortedItems;
|
||
}
|
||
var start = (this.page - 1) * this.localPerPage;
|
||
return this.sortedItems.slice(start, start + this.localPerPage);
|
||
},
|
||
rangeFrom: function () {
|
||
if (!this.totalItems) return 0;
|
||
return (this.page - 1) * this.localPerPage + 1;
|
||
},
|
||
rangeTo: function () {
|
||
return Math.min(this.page * this.localPerPage, this.totalItems);
|
||
},
|
||
tableHeaders: function () {
|
||
if (!this.showIndex) {
|
||
return this.headers;
|
||
}
|
||
return [
|
||
{ title: this.indexTitle, key: '__adt_index', sortable: false }
|
||
].concat(this.headers);
|
||
}
|
||
},
|
||
|
||
watch: {
|
||
items: function () {
|
||
if (this.page > this.totalPages) {
|
||
this.page = Math.max(1, this.totalPages);
|
||
}
|
||
},
|
||
itemsPerPage: function (v) {
|
||
this.localPerPage = v;
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
rowGlobalIndex: function (rowIdx) {
|
||
if (!this.showPagination) {
|
||
return rowIdx + 1;
|
||
}
|
||
return (this.page - 1) * this.localPerPage + rowIdx + 1;
|
||
},
|
||
cellTdClass: function (h) {
|
||
var o = {};
|
||
if (h.key === '__adt_index') o['admin-data-table__col-index'] = true;
|
||
return o;
|
||
},
|
||
cellValue: function (item, key) {
|
||
return item[key];
|
||
},
|
||
formatCell: function (item, key) {
|
||
var v = item[key];
|
||
return v == null ? '' : v;
|
||
},
|
||
toggleSort: function (key) {
|
||
if (this.sortKey === key) {
|
||
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
|
||
} else {
|
||
this.sortKey = key;
|
||
this.sortDir = 'asc';
|
||
}
|
||
},
|
||
goPage: function (p) {
|
||
if (p < 1 || p > this.totalPages) return;
|
||
this.page = p;
|
||
},
|
||
onPerPageChange: function () {
|
||
this.page = 1;
|
||
},
|
||
|
||
isActionColumnKey: function (key) {
|
||
if (!key) return false;
|
||
var k = String(key).toLowerCase();
|
||
return k === 'actions' || k === 'action' || k === 'opsi' || k === 'tindakan';
|
||
},
|
||
|
||
resolveFieldValue: function (item, headerKey) {
|
||
if (headerKey === '#') return '';
|
||
var keys = String(headerKey).split('.');
|
||
var value = item;
|
||
for (var i = 0; i < keys.length; i++) {
|
||
if (value && typeof value === 'object' && keys[i] in value) {
|
||
value = value[keys[i]];
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
if (Array.isArray(value)) {
|
||
return value
|
||
.map(function (v) {
|
||
return v && typeof v === 'object' && v.name != null ? v.name : String(v);
|
||
})
|
||
.join(', ');
|
||
}
|
||
if (value && typeof value === 'object' && 'name' in value) {
|
||
return value.name;
|
||
}
|
||
return value;
|
||
},
|
||
|
||
cellStringForExport: function (header, item, rowIndex) {
|
||
if (typeof header.exportValue === 'function') {
|
||
return header.exportValue(item, rowIndex) || '';
|
||
}
|
||
if (header.key === '__adt_index' || header.key === '#') {
|
||
return String(rowIndex + 1);
|
||
}
|
||
if (this.isActionColumnKey(header.key)) {
|
||
return '';
|
||
}
|
||
var raw = this.resolveFieldValue(item, header.key);
|
||
if (raw == null) return '';
|
||
return String(raw);
|
||
},
|
||
|
||
prepareExportMatrix: function () {
|
||
var rows = [];
|
||
var headerTitles = this.tableHeaders.map(function (h) {
|
||
return h.title || h.key;
|
||
});
|
||
var vm = this;
|
||
this.sortedItems.forEach(function (item, index) {
|
||
var line = vm.tableHeaders.map(function (h) {
|
||
return vm.cellStringForExport(h, item, index);
|
||
});
|
||
rows.push(line);
|
||
});
|
||
return { headerTitles: headerTitles, rows: rows };
|
||
},
|
||
|
||
exportEmitError: function (err) {
|
||
this.$emit('export-error', err instanceof Error ? err : new Error(String(err)));
|
||
},
|
||
|
||
exportToCSV: function () {
|
||
try {
|
||
var m = this.prepareExportMatrix();
|
||
var csvContent = [m.headerTitles]
|
||
.concat(m.rows)
|
||
.map(function (row) {
|
||
return row
|
||
.map(function (cell) {
|
||
return '"' + String(cell).replace(/"/g, '""') + '"';
|
||
})
|
||
.join(',');
|
||
})
|
||
.join('\n');
|
||
var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||
saveAs(blob, this.exportFileName + '.csv');
|
||
} catch (e) {
|
||
this.exportEmitError(e);
|
||
}
|
||
},
|
||
|
||
exportToExcel: function () {
|
||
try {
|
||
var m = this.prepareExportMatrix();
|
||
var aoa = [m.headerTitles].concat(m.rows);
|
||
var worksheet = XLSX.utils.aoa_to_sheet(aoa);
|
||
var workbook = XLSX.utils.book_new();
|
||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
||
var buf = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
||
var blob = new Blob([buf], {
|
||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
});
|
||
saveAs(blob, this.exportFileName + '.xlsx');
|
||
} catch (e) {
|
||
this.exportEmitError(e);
|
||
}
|
||
},
|
||
|
||
exportToPDF: function () {
|
||
try {
|
||
var m = this.prepareExportMatrix();
|
||
var colCount = m.headerTitles.length;
|
||
var useLandscape = colCount > 6;
|
||
var doc = new jsPDF(useLandscape ? 'l' : 'p', 'pt', 'a4');
|
||
var fontSize = 8;
|
||
if (colCount > 12) fontSize = 6;
|
||
else if (colCount > 8) fontSize = 7;
|
||
var cellPadding = colCount > 8 ? 4 : 8;
|
||
var tableOptions = {
|
||
head: [m.headerTitles],
|
||
body: m.rows,
|
||
styles: { fontSize: fontSize, cellPadding: cellPadding },
|
||
headStyles: { fillColor: [25, 118, 210] },
|
||
margin: { top: 20 }
|
||
};
|
||
if (colCount > 8) {
|
||
tableOptions.tableWidth = 'wrap';
|
||
tableOptions.horizontalPageBreak = true;
|
||
tableOptions.styles = Object.assign({}, tableOptions.styles, {
|
||
minCellWidth: 36,
|
||
overflow: 'linebreak'
|
||
});
|
||
}
|
||
autoTable(doc, tableOptions);
|
||
doc.save(this.exportFileName + '.pdf');
|
||
} catch (e) {
|
||
this.exportEmitError(e);
|
||
}
|
||
},
|
||
|
||
exportToJSON: function () {
|
||
try {
|
||
var vm = this;
|
||
var jsonData = this.sortedItems.map(function (item, index) {
|
||
var obj = {};
|
||
vm.tableHeaders.forEach(function (h) {
|
||
var title = h.title || h.key;
|
||
if (vm.isActionColumnKey(h.key)) return;
|
||
if (h.key === '__adt_index') {
|
||
obj[title] = index + 1;
|
||
return;
|
||
}
|
||
if (typeof h.exportValue === 'function') {
|
||
obj[title] = h.exportValue(item, index);
|
||
return;
|
||
}
|
||
var keys = String(h.key).split('.');
|
||
var value = item;
|
||
for (var i = 0; i < keys.length; i++) {
|
||
if (value && typeof value === 'object' && keys[i] in value) {
|
||
value = value[keys[i]];
|
||
} else {
|
||
value = null;
|
||
break;
|
||
}
|
||
}
|
||
obj[title] = value;
|
||
});
|
||
return obj;
|
||
});
|
||
var jsonContent = JSON.stringify(jsonData, null, 2);
|
||
var blob = new Blob([jsonContent], { type: 'application/json' });
|
||
saveAs(blob, this.exportFileName + '.json');
|
||
} catch (e) {
|
||
this.exportEmitError(e);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
|
||
.admin-data-table__toolbar {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.admin-data-table {
|
||
--adt-header-bg: var(--admin-table-header-bg);
|
||
--adt-header-color: var(--admin-table-header-color);
|
||
--adt-radius: 12px;
|
||
--adt-border: 1px solid var(--admin-table-border-color);
|
||
--adt-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||
--adt-row-hover: var(--admin-table-row-hover-bg);
|
||
--adt-footer-bg: var(--admin-table-footer-bg);
|
||
--adt-text-muted: var(--admin-table-text-muted);
|
||
--adt-font-size: 16px;
|
||
--adt-header-font-size: 16px;
|
||
}
|
||
|
||
.admin-data-table__shell {
|
||
border-radius: var(--adt-radius);
|
||
border: var(--adt-border);
|
||
box-shadow: var(--adt-shadow);
|
||
overflow: hidden;
|
||
background: var(--admin-table-shell-bg);
|
||
}
|
||
|
||
.admin-data-table__scroll {
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.admin-data-table__table {
|
||
width: 100%;
|
||
margin-bottom: 0;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
}
|
||
|
||
.admin-data-table__table thead tr:first-child th:first-child {
|
||
border-top-left-radius: var(--adt-radius);
|
||
}
|
||
|
||
.admin-data-table__table thead tr:first-child th:last-child {
|
||
border-top-right-radius: var(--adt-radius);
|
||
}
|
||
|
||
.admin-data-table__table thead th {
|
||
background-color: var(--adt-header-bg);
|
||
color: var(--adt-header-color);
|
||
font-weight: 600;
|
||
font-size: var(--adt-header-font-size);
|
||
text-transform: none;
|
||
letter-spacing: 0.02em;
|
||
border: none !important;
|
||
padding: 14px 16px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.admin-data-table__table thead th.is-sortable {
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
|
||
.admin-data-table__table thead th.is-sortable:hover {
|
||
filter: brightness(1.06);
|
||
}
|
||
|
||
.admin-data-table__table thead th.admin-data-table__col-index,
|
||
.admin-data-table__table tbody td.admin-data-table__col-index {
|
||
width: 3.25rem;
|
||
max-width: 4rem;
|
||
text-align: center;
|
||
font-variant-numeric: tabular-nums;
|
||
vertical-align: middle !important;
|
||
}
|
||
|
||
.admin-data-table__th-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 8px;
|
||
min-height: 20px;
|
||
}
|
||
|
||
.admin-data-table__th-title {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.admin-data-table__sort {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
opacity: 0.95;
|
||
}
|
||
|
||
.admin-data-table__sort-hint {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
line-height: 1;
|
||
opacity: 0.45;
|
||
margin-top: 1px;
|
||
}
|
||
|
||
.admin-data-table__sort-icon {
|
||
display: block;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.admin-data-table__sort-icon--faint {
|
||
margin-top: -3px;
|
||
}
|
||
|
||
.admin-data-table__sort-hint .admin-data-table__sort-icon--faint:first-child {
|
||
margin-top: 0;
|
||
}
|
||
|
||
.admin-data-table__table tbody td {
|
||
padding: 12px 16px;
|
||
vertical-align: middle;
|
||
border-top: 1px solid var(--admin-table-row-border-color);
|
||
font-size: var(--adt-font-size);
|
||
}
|
||
|
||
.admin-data-table__table tbody tr:first-child:not(.admin-data-table__state-row) td {
|
||
border-top: 1px solid var(--admin-table-border-color);
|
||
}
|
||
|
||
.admin-data-table__table tbody tr.admin-data-table__state-row td {
|
||
border-top: none;
|
||
padding: 0;
|
||
}
|
||
|
||
.admin-data-table__table tbody tr:not(.admin-data-table__state-row):hover td {
|
||
background-color: var(--adt-row-hover);
|
||
}
|
||
|
||
.admin-data-table__state {
|
||
text-align: center;
|
||
padding: 40px 24px;
|
||
color: var(--adt-text-muted);
|
||
}
|
||
|
||
.admin-data-table__state-icon {
|
||
font-size: 40px;
|
||
opacity: 0.45;
|
||
margin-bottom: 12px;
|
||
display: block;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.admin-data-table__state-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: var(--admin-table-text-strong);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.admin-data-table__state-hint {
|
||
font-size: 13px;
|
||
color: var(--adt-text-muted);
|
||
}
|
||
|
||
.admin-data-table__footer {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px 16px;
|
||
padding: 12px 16px;
|
||
border-top: var(--adt-border);
|
||
background: var(--adt-footer-bg);
|
||
}
|
||
|
||
.admin-data-table__footer-left {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.admin-data-table__footer-label {
|
||
margin: 0;
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
color: var(--adt-text-muted);
|
||
}
|
||
|
||
.admin-data-table__page-size {
|
||
width: auto;
|
||
min-width: 64px;
|
||
display: inline-block;
|
||
height: 30px;
|
||
padding: 4px 8px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.admin-data-table__footer-mid {
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--admin-table-footer-mid-text);
|
||
}
|
||
|
||
.admin-data-table__footer-right {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.admin-data-table__pagination {
|
||
margin: 0;
|
||
}
|
||
|
||
.admin-data-table__pagination>li>a {
|
||
padding: 5px 12px;
|
||
font-size: 12px;
|
||
color: var(--adt-header-bg);
|
||
}
|
||
|
||
.admin-data-table__pagination>li.disabled>a {
|
||
color: var(--admin-table-pagination-disabled);
|
||
pointer-events: none;
|
||
cursor: default;
|
||
}
|
||
</style>
|