691 lines
29 KiB
PHP
691 lines
29 KiB
PHP
@props(['id', 'columns', 'ajax', 'bulkDeleteUrl' => null])
|
|
|
|
@php
|
|
$dtColumns = collect($columns)
|
|
->map(function ($c, $index) {
|
|
return [
|
|
'data' => $c['key'],
|
|
'name' => $c['key'],
|
|
'orderable' => $c['orderable'] ?? true,
|
|
'searchable' => $c['searchable'] ?? true,
|
|
'className' => $c['className'] ?? '',
|
|
'visible' => $c['visible'] ?? true,
|
|
];
|
|
})
|
|
->values();
|
|
@endphp
|
|
|
|
@if ($bulkDeleteUrl)
|
|
<div class="d-flex justify-content-start align-items-center mb-3" id="{{ $id }}-bulk-actions"
|
|
style="display: none !important;">
|
|
<div class="bg-danger-subtle text-danger rounded-3 d-flex align-items-center gap-3 px-4 py-2">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<i data-lucide="alert-circle" width="16" height="16"></i>
|
|
<span class="fw-medium"><span id="{{ $id }}-selected-count">0</span> items selected</span>
|
|
</div>
|
|
<div class="vr bg-danger opacity-25"></div>
|
|
<x-button-c-r-m type="button" variant="danger" size="sm" icon="trash-2" id="{{ $id }}-bulk-delete-opener-btn"
|
|
class="shadow-sm">
|
|
Delete Selected
|
|
</x-button-c-r-m>
|
|
</div>
|
|
</div>
|
|
<div class="modal fade" id="{{ $id }}-bulk-delete-modal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title h5" id="{{ $id }}-bulk-delete-modal-title">
|
|
Confirm Bulk Delete
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>Are you sure you want to delete <span id="{{ $id }}-bulk-delete-count-display"
|
|
class="fw-bold"></span>
|
|
selected items?</p>
|
|
<p class="text-danger mb-0 mt-2">This action cannot be undone.</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<x-button-c-r-m type="button" variant="danger" id="{{ $id }}-confirm-bulk-delete-btn">
|
|
Delete
|
|
</x-button-c-r-m>
|
|
|
|
<x-button-c-r-m type="button" variant="secondary" data-bs-dismiss="modal">
|
|
Cancel
|
|
</x-button-c-r-m>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="data-table-wrapper position-relative shadow-none">
|
|
<div class="loading-process" id="{{ $id }}-loading" style="display: none;">
|
|
<div class="loading-bar"></div>
|
|
<div class="loading-overlay"></div>
|
|
</div>
|
|
|
|
<table id="{{ $id }}" class="table-hover mb-0 table bg-white shadow-none align-middle"
|
|
style="width:100%; border-collapse: separate; border-spacing: 0;">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
@foreach ($columns as $col)
|
|
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7 border-bottom position-relative py-3 ps-3"
|
|
style="font-size: 0.75rem; letter-spacing: 0.5px;">
|
|
<div
|
|
class="d-flex align-items-center {{ $col['key'] === 'checkbox' ? 'justify-content-center' : 'justify-content-between' }}">
|
|
<span>
|
|
@if ($col['key'] === 'checkbox')
|
|
{!! $col['label'] !!}
|
|
@else
|
|
{{ $col['label'] }}
|
|
@endif
|
|
</span>
|
|
@if ($col['key'] !== 'checkbox' && ($col['orderable'] ?? true))
|
|
<div class="sort-icons d-flex flex-column ms-2">
|
|
<i data-lucide="arrow-up" class="sort-icon-asc" width="10" height="10"></i>
|
|
<i data-lucide="arrow-down" class="sort-icon-desc" width="10" height="10"
|
|
style="margin-top: -2px;"></i>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</th>
|
|
@endforeach
|
|
</tr>
|
|
<tr class="filter-row bg-light" id="{{ $id }}-filter-row" style="display: none;">
|
|
@foreach ($columns as $col)
|
|
<th class="border-bottom p-2">
|
|
@if ($col['searchable'] ?? true)
|
|
<div class="input-group input-group-sm">
|
|
<span class="input-group-text border-end-0 text-muted border-light bg-white pe-2 ps-2">
|
|
<i data-lucide="search" style="font-size: 0.75rem;"></i>
|
|
</span>
|
|
<input type="text"
|
|
class="form-control form-control-sm border-start-0 column-search border-light bg-white ps-0 shadow-none"
|
|
placeholder="Filter..." data-column="{{ $loop->index }}" style="font-size: 0.8125rem;">
|
|
</div>
|
|
@endif
|
|
</th>
|
|
@endforeach
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="{{ $id }}-column-offcanvas">
|
|
<div class="offcanvas-header border-bottom">
|
|
<h5 class="offcanvas-title">Column Visibility</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
|
|
</div>
|
|
<div class="offcanvas-body p-3">
|
|
<div id="{{ $id }}-column-list">
|
|
@foreach($columns as $index => $col)
|
|
@if((!isset($col['visibility']) || $col['visibility'] !== false) && $col['key'] !== 'checkbox')
|
|
<div class="d-flex align-items-center gap-2 mb-2 p-2 rounded column-item bg-white border" data-column-key="{{ $col['key'] }}" data-column-index="{{ $index }}" style="cursor: grab; transition: all 0.15s ease;">
|
|
<i data-lucide="grip-vertical" class="text-muted" style="width: 16px; height: 16px; flex-shrink: 0;"></i>
|
|
<div class="form-check form-switch mb-0 flex-grow-1">
|
|
<input type="checkbox" class="form-check-input column-toggle"
|
|
data-column-key="{{ $col['key'] }}"
|
|
data-column-index="{{ $index }}"
|
|
id="{{ $id }}-col-{{ $index }}"
|
|
{{ !isset($col['visible']) || $col['visible'] !== false ? 'checked' : '' }}>
|
|
<label class="form-check-label user-select-none" for="{{ $id }}-col-{{ $index }}">{{ $col['label'] }}</label>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@push('custom-scripts')
|
|
<script src="{{ asset('build/plugins/sortablejs/Sortable.min.js') }}"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
$.fn.DataTable.ext.pager.numbers_length = 7;
|
|
|
|
var table = $('#{{ $id }}').DataTable({
|
|
processing: true,
|
|
serverSide: true,
|
|
ajax: '{{ $ajax }}',
|
|
columns: @json($dtColumns),
|
|
orderCellsTop: true,
|
|
fixedHeader: false,
|
|
stateSave: true,
|
|
pagingType: 'full_numbers',
|
|
language: {
|
|
loadingRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="spinner-border text-primary mb-3" role="status"></div><h6 class="text-secondary fw-medium">Loading...</h6></div>',
|
|
searchPlaceholder: "Search...",
|
|
search: "",
|
|
lengthMenu: "_MENU_",
|
|
info: "Showing <span class='fw-bold'>_START_</span> to <span class='fw-bold'>_END_</span> of <span class='fw-bold'>_TOTAL_</span> entries",
|
|
paginate: {
|
|
first: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-left" width="16" height="16"></i></span>',
|
|
last: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-right" width="16" height="16"></i></span>',
|
|
next: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-right" width="16" height="16"></i></span>',
|
|
previous: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-left" width="16" height="16"></i></span>'
|
|
},
|
|
zeroRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No matching records found</h6></div>',
|
|
emptyTable: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No data available</h6></div>'
|
|
},
|
|
dom: "<'row px-3 py-2 align-items-center'<'col-sm-12 col-md-6 d-inline-flex align-items-center gap-2'<'dt-filter-toggle'><'dt-column-toggle'>f><'col-sm-12 col-md-6 d-inline-flex align-items-center justify-content-end gap-2'l>>" +
|
|
"<'row p-0'<'col-sm-12'tr>>" +
|
|
"<'row px-3 pb-3 pt-3 align-items-center'<'col-sm-12 col-md-5 text-muted small d-inline-flex align-items-center'i><'col-sm-12 col-md-7 d-inline-flex align-items-center justify-content-end gap-2'p>>",
|
|
initComplete: function () {
|
|
var wrapper = $('#{{ $id }}_wrapper');
|
|
|
|
wrapper.find('.dt-filter-toggle').html(
|
|
'<button type="button" class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-1" id="{{ $id }}-filter-toggle-btn">' +
|
|
'<i data-lucide="filter" width="14" height="14"></i>' +
|
|
'<span>Filters</span>' +
|
|
'</button>'
|
|
);
|
|
|
|
wrapper.find('.dt-column-toggle').html(
|
|
'<button type="button" class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-1" data-bs-toggle="offcanvas" data-bs-target="#{{ $id }}-column-offcanvas">' +
|
|
'<i data-lucide="columns" width="14" height="14"></i>' +
|
|
'<span>Columns</span>' +
|
|
'</button>'
|
|
);
|
|
|
|
$('#{{ $id }}-filter-toggle-btn').on('click', function () {
|
|
var filterRow = $('#{{ $id }}-filter-row');
|
|
var btn = $(this);
|
|
filterRow.toggle();
|
|
btn.toggleClass('btn-outline-secondary btn-primary');
|
|
if (!filterRow.is(':visible')) {
|
|
filterRow.find('input').val('');
|
|
table.columns().search('').draw();
|
|
}
|
|
});
|
|
|
|
wrapper.find('.dataTables_filter input')
|
|
.addClass('form-control form-control-sm')
|
|
.attr('placeholder', 'Search...');
|
|
|
|
$('.dataTables_length select').select2({
|
|
minimumResultsForSearch: Infinity,
|
|
width: '80px',
|
|
dropdownCssClass: 'small-select-dropdown',
|
|
selectionCssClass: 'small-select-selection'
|
|
});
|
|
|
|
let searchTimeouts = {};
|
|
this.api().columns().every(function () {
|
|
var that = this;
|
|
$('input', this.header()).on('keyup change clear', function () {
|
|
const colIdx = that.index();
|
|
const value = this.value;
|
|
|
|
clearTimeout(searchTimeouts[colIdx]);
|
|
searchTimeouts[colIdx] = setTimeout(function () {
|
|
if (that.search() !== value) {
|
|
that.search(value).draw();
|
|
}
|
|
}, 400);
|
|
});
|
|
});
|
|
},
|
|
drawCallback: function () {
|
|
if ($('.dataTables_length select').data('select2')) {
|
|
$('.dataTables_length select').select2('destroy');
|
|
}
|
|
$('.dataTables_length select').select2({
|
|
minimumResultsForSearch: Infinity,
|
|
width: '80px'
|
|
});
|
|
|
|
setTimeout(function () {
|
|
if (window.lucide) {
|
|
lucide.createIcons();
|
|
}
|
|
}, 50);
|
|
|
|
var storedOrder = getStoredOrder();
|
|
if (storedOrder && storedOrder.length > 0) {
|
|
var $table = $('#{{ $id }}');
|
|
var $tbody = $table.find('tbody');
|
|
var $rows = $tbody.find('tr');
|
|
if ($rows.length > 0) {
|
|
$rows.each(function() {
|
|
var cells = $(this).find('td').toArray();
|
|
var newCells = storedOrder.map(function(idx) { return cells[idx]; });
|
|
$(this).find('td').remove();
|
|
newCells.forEach(function(td) { $(this).append(td); }, $(this));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var sortableInstance = null;
|
|
var tableId = '{{ $id }}';
|
|
var storageKey = 'dt_column_order_' + tableId;
|
|
|
|
function getStoredOrder() {
|
|
var stored = localStorage.getItem(storageKey);
|
|
return stored ? JSON.parse(stored) : null;
|
|
}
|
|
|
|
function saveOrderToStorage(newOrder) {
|
|
localStorage.setItem(storageKey, JSON.stringify(newOrder));
|
|
}
|
|
|
|
function reorderTableColumns(newOrder) {
|
|
saveOrderToStorage(newOrder);
|
|
|
|
var $table = $('#{{ $id }}');
|
|
var $theadRows = $table.find('thead tr');
|
|
|
|
$theadRows.each(function() {
|
|
var headers = $(this).find('th').toArray();
|
|
var newHeaders = newOrder.map(function(idx) { return headers[idx]; });
|
|
$(this).find('th').remove();
|
|
newHeaders.forEach(function(th) { $(this).append(th); }, $(this));
|
|
});
|
|
|
|
var $tbody = $table.find('tbody');
|
|
var $rows = $tbody.find('tr');
|
|
if ($rows.length > 0) {
|
|
$rows.each(function() {
|
|
var cells = $(this).find('td').toArray();
|
|
var newCells = newOrder.map(function(idx) { return cells[idx]; });
|
|
$(this).find('td').remove();
|
|
newCells.forEach(function(td) { $(this).append(td); }, $(this));
|
|
});
|
|
}
|
|
|
|
reorderOffcanvasList(newOrder);
|
|
}
|
|
|
|
function reorderOffcanvasList(newOrder) {
|
|
var $list = $('#{{ $id }}-column-list');
|
|
var items = $list.find('.column-item').toArray();
|
|
var newItems = newOrder.map(function(idx) { return items[idx]; });
|
|
$list.find('.column-item').remove();
|
|
newItems.forEach(function(item) { $list.append(item); });
|
|
}
|
|
|
|
function applyStoredOrder() {
|
|
var storedOrder = getStoredOrder();
|
|
if (storedOrder && storedOrder.length > 0) {
|
|
reorderTableColumns(storedOrder);
|
|
}
|
|
}
|
|
|
|
applyStoredOrder();
|
|
|
|
var sortableInstance = null;
|
|
|
|
function initSortable() {
|
|
var sortableList = document.getElementById('{{ $id }}-column-list');
|
|
if (!sortableList) return;
|
|
|
|
sortableInstance = new Sortable(sortableList, {
|
|
animation: 150,
|
|
ghostClass: 'bg-light',
|
|
delay: 100,
|
|
onEnd: function (evt) {
|
|
var items = sortableList.querySelectorAll('.column-item');
|
|
var newOrder = [];
|
|
items.forEach(function(item) {
|
|
newOrder.push(parseInt(item.dataset.columnIndex));
|
|
});
|
|
|
|
reorderTableColumns(newOrder);
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#{{ $id }}-column-offcanvas').on('change', '.column-toggle', function () {
|
|
var columnKey = $(this).data('column-key');
|
|
var columnIdx = $(this).data('column-index');
|
|
var column = table.column(columnIdx);
|
|
column.visible($(this).is(':checked'));
|
|
});
|
|
|
|
var offcanvasEl = document.getElementById('{{ $id }}-column-offcanvas');
|
|
if (offcanvasEl) {
|
|
offcanvasEl.addEventListener('shown.bs.offcanvas', function() {
|
|
initSortable();
|
|
if (window.lucide) lucide.createIcons();
|
|
});
|
|
}
|
|
|
|
$('#{{ $id }} tbody').on('dblclick', 'tr', function () {
|
|
const editLink = $(this).find('a.btn-outline-primary, a[href*="edit"]').first();
|
|
if (editLink.length && editLink.attr('href')) {
|
|
window.location.href = editLink.attr('href');
|
|
}
|
|
});
|
|
|
|
table.on('processing.dt', function (e, settings, processing) {
|
|
const loadingEl = $('#{{ $id }}-loading');
|
|
if (processing) {
|
|
loadingEl.fadeIn(100);
|
|
} else {
|
|
loadingEl.fadeOut(200);
|
|
}
|
|
});
|
|
|
|
$('#{{ $id }} thead').on('click', '#{{ $id }}-filter-row th', function (e) {
|
|
e.stopPropagation();
|
|
});
|
|
|
|
@if ($bulkDeleteUrl)
|
|
(function () {
|
|
const bulkActions = $('#{{ $id }}-bulk-actions');
|
|
const selectedCount = $('#{{ $id }}-selected-count');
|
|
const masterCheckbox = $('#dt-master-checkbox');
|
|
let selectedIds = [];
|
|
|
|
$(document).on('change', '#{{ $id }} #dt-master-checkbox', function () {
|
|
const isChecked = $(this).is(':checked');
|
|
$('#{{ $id }} .dt-checkbox').prop('checked', isChecked).trigger('change');
|
|
});
|
|
|
|
$(document).on('change', '#{{ $id }} .dt-checkbox', function () {
|
|
const id = $(this).val();
|
|
if ($(this).is(':checked')) {
|
|
if (!selectedIds.includes(id)) selectedIds.push(id);
|
|
} else {
|
|
selectedIds = selectedIds.filter(item => item !== id);
|
|
}
|
|
|
|
selectedCount.text(selectedIds.length);
|
|
if (selectedIds.length > 0) {
|
|
bulkActions.show();
|
|
bulkActions.removeClass('d-none').addClass('d-flex');
|
|
bulkActions.attr('style', '');
|
|
} else {
|
|
bulkActions.hide();
|
|
}
|
|
|
|
const allCheckboxes = $('#{{ $id }} .dt-checkbox').length;
|
|
const checkedCheckboxes = $('#{{ $id }} .dt-checkbox:checked').length;
|
|
|
|
if (allCheckboxes > 0 && allCheckboxes === checkedCheckboxes) {
|
|
masterCheckbox.prop('checked', true);
|
|
masterCheckbox.prop('indeterminate', false);
|
|
} else if (checkedCheckboxes > 0) {
|
|
masterCheckbox.prop('checked', false);
|
|
masterCheckbox.prop('indeterminate', true);
|
|
} else {
|
|
masterCheckbox.prop('checked', false);
|
|
masterCheckbox.prop('indeterminate', false);
|
|
}
|
|
});
|
|
|
|
$('#{{ $id }}').on('draw.dt', function () {
|
|
selectedIds = [];
|
|
bulkActions.hide();
|
|
masterCheckbox.prop('checked', false);
|
|
masterCheckbox.prop('indeterminate', false);
|
|
});
|
|
|
|
const modalEl = document.getElementById('{{ $id }}-bulk-delete-modal');
|
|
const openerBtn = $('#{{ $id }}-bulk-delete-opener-btn');
|
|
const confirmBtn = $('#{{ $id }}-confirm-bulk-delete-btn');
|
|
const countDisplay = $('#{{ $id }}-bulk-delete-count-display');
|
|
let bsModal = null;
|
|
|
|
openerBtn.on('click', function () {
|
|
if (selectedIds.length === 0) return;
|
|
countDisplay.text(selectedIds.length);
|
|
if (!bsModal) {
|
|
bsModal = new bootstrap.Modal(modalEl);
|
|
}
|
|
bsModal.show();
|
|
});
|
|
|
|
confirmBtn.on('click', function () {
|
|
$.ajax({
|
|
url: '{{ $bulkDeleteUrl }}',
|
|
type: 'DELETE',
|
|
data: {
|
|
ids: selectedIds,
|
|
_token: '{{ csrf_token() }}'
|
|
},
|
|
beforeSend: function () {
|
|
confirmBtn.prop('disabled', true).text('Deleting...');
|
|
},
|
|
success: function (response) {
|
|
if (bsModal) bsModal.hide();
|
|
$('#{{ $id }}').DataTable().ajax.reload();
|
|
selectedIds = [];
|
|
bulkActions.hide();
|
|
|
|
if (typeof FuiToast !== 'undefined') {
|
|
FuiToast.success(response.message || 'Selected items have been deleted successfully.');
|
|
}
|
|
if (window.lucide) lucide.createIcons();
|
|
},
|
|
error: function (xhr) {
|
|
const message = xhr.responseJSON?.message || 'Something went wrong.';
|
|
if (typeof FuiToast !== 'undefined') {
|
|
FuiToast.error(message);
|
|
} else {
|
|
alert(message);
|
|
}
|
|
if (bsModal) bsModal.hide();
|
|
},
|
|
complete: function () {
|
|
confirmBtn.prop('disabled', false).text('Delete');
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
@endif
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.data-table-wrapper {
|
|
background: #fff;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
overflow: visible;
|
|
position: relative;
|
|
}
|
|
|
|
.pagination button.page-link {
|
|
height: 100%;
|
|
}
|
|
|
|
.data-table-wrapper .input-group-text {
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.data-table-wrapper .form-control::placeholder {
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.dataTables_wrapper .pagination .page-item .page-link {
|
|
border: 1px solid transparent;
|
|
border-radius: 6px;
|
|
margin: 0 2px;
|
|
color: #64748b;
|
|
padding: 0;
|
|
font-size: 0.875rem;
|
|
transition: all 0.2s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 38px;
|
|
min-width: 38px;
|
|
}
|
|
|
|
.dataTables_wrapper .pagination .page-item.active .page-link {
|
|
background-color: #0f172a;
|
|
color: white;
|
|
font-weight: 500;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
border-color: #0f172a;
|
|
}
|
|
|
|
.dataTables_wrapper .pagination .page-item.disabled .page-link {
|
|
color: #cbd5e1;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.dataTables_wrapper .pagination .page-item:not(.active) .page-link:hover {
|
|
background-color: #f8fafc;
|
|
color: #0f172a;
|
|
border-color: #e2e8f0;
|
|
}
|
|
|
|
.dataTables_length {
|
|
margin-right: 1rem;
|
|
}
|
|
|
|
.select2-container--default .select2-selection--single {
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 6px;
|
|
height: 32px;
|
|
display: flex;
|
|
align-items: center;
|
|
outline: none;
|
|
}
|
|
|
|
.select2-container--default .select2-selection--single:focus {
|
|
border-color: #94a3b8;
|
|
}
|
|
|
|
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
|
height: 30px;
|
|
}
|
|
|
|
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
|
color: #475569;
|
|
font-size: 0.8125rem;
|
|
padding-left: 10px;
|
|
line-height: normal;
|
|
}
|
|
|
|
.loading-process {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 5;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.loading-bar {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
height: 3px;
|
|
width: 100%;
|
|
background: #f1f5f9;
|
|
overflow: hidden;
|
|
z-index: 6;
|
|
}
|
|
|
|
.loading-bar::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
width: 50%;
|
|
background: linear-gradient(90deg, transparent, #0f172a, transparent);
|
|
animation: loading-process-info 1.5s infinite linear;
|
|
}
|
|
|
|
.loading-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(255, 255, 255, 0.5);
|
|
backdrop-filter: blur(1px);
|
|
}
|
|
|
|
@keyframes loading-process-info {
|
|
0% {
|
|
transform: translateX(-100%);
|
|
}
|
|
|
|
100% {
|
|
transform: translateX(200%);
|
|
}
|
|
}
|
|
|
|
.sort-icons {
|
|
opacity: 0.15;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
th:hover .sort-icons {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
th.sorting_asc .sort-icons {
|
|
opacity: 1;
|
|
}
|
|
|
|
th.sorting_asc .sort-icon-desc {
|
|
display: none !important;
|
|
}
|
|
|
|
th.sorting_desc .sort-icons {
|
|
opacity: 1;
|
|
}
|
|
|
|
th.sorting_desc .sort-icon-asc {
|
|
display: none !important;
|
|
}
|
|
|
|
table.dataTable thead .sorting:before,
|
|
table.dataTable thead .sorting:after,
|
|
table.dataTable thead .sorting_asc:before,
|
|
table.dataTable thead .sorting_asc:after,
|
|
table.dataTable thead .sorting_desc:before,
|
|
table.dataTable thead .sorting_desc:after {
|
|
display: none !important;
|
|
}
|
|
|
|
div.dataTables_processing {
|
|
display: none !important;
|
|
}
|
|
|
|
.dataTables_filter {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.dataTables_filter label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
margin: 0;
|
|
}
|
|
|
|
.column-item {
|
|
cursor: grab !important;
|
|
}
|
|
|
|
.column-item:hover {
|
|
background-color: #f8f9fa !important;
|
|
border-color: #dee2e6 !important;
|
|
}
|
|
|
|
.column-item:active {
|
|
background-color: #e9ecef !important;
|
|
cursor: grabbing !important;
|
|
}
|
|
|
|
.column-item.sortable-ghost {
|
|
background-color: #e3f2fd !important;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.column-item.sortable-chosen {
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
}
|
|
</style>
|
|
@endpush |