refactor(DataTable): enhance table styling and functionality with fixed action column, improved striped rows, and new props for UX customization
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
This commit is contained in:
@@ -34,6 +34,8 @@ import Tooltip from './Tooltip.jsx';
|
||||
* - [{ icon: Component, label: string, onClick: (item) => void, variant?: string }]
|
||||
* @param {boolean} props.selectable - Включить чекбоксы выбора (default: true)
|
||||
* @param {number} props.skeletonRows - Количество строк скелетона (default: 10)
|
||||
* @param {boolean} props.striped - Чередование фона строк (Tabler UX, default: true)
|
||||
* @param {boolean} props.compact - Уменьшенные отступы ячеек (default: false)
|
||||
*/
|
||||
function DataTable({
|
||||
columns = [],
|
||||
@@ -56,11 +58,13 @@ function DataTable({
|
||||
actions = [],
|
||||
selectable = true,
|
||||
skeletonRows = 10,
|
||||
striped = true,
|
||||
compact = false,
|
||||
}) {
|
||||
const hasActions = onEdit || onDelete || onCopy || actions.length > 0;
|
||||
const isEditing = (item) => inlineEdit && item[itemKey] === inlineEdit.editingKey;
|
||||
|
||||
// Рендер заголовка колонки
|
||||
// Рендер заголовка колонки (col.title — подпись, col.tooltip — подсказка для UX)
|
||||
const renderColumnHeader = (col) => {
|
||||
const isSortable = col.sortable !== false && onSort;
|
||||
const isActive = sortField === col.key;
|
||||
@@ -77,22 +81,27 @@ function DataTable({
|
||||
</div>
|
||||
);
|
||||
|
||||
const thProps = {
|
||||
key: col.key,
|
||||
scope: 'col',
|
||||
style: col.width ? { width: col.width } : undefined,
|
||||
};
|
||||
|
||||
if (isSortable) {
|
||||
return (
|
||||
<th
|
||||
key={col.key}
|
||||
<th
|
||||
{...thProps}
|
||||
className="cursor-pointer user-select-none"
|
||||
onClick={() => onSort(col.key)}
|
||||
style={col.width ? { width: col.width } : undefined}
|
||||
>
|
||||
{content}
|
||||
{col.tooltip ? <Tooltip content={col.tooltip} position="top">{content}</Tooltip> : content}
|
||||
</th>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<th key={col.key} style={col.width ? { width: col.width } : undefined}>
|
||||
{content}
|
||||
<th {...thProps}>
|
||||
{col.tooltip ? <Tooltip content={col.tooltip} position="top">{content}</Tooltip> : content}
|
||||
</th>
|
||||
);
|
||||
};
|
||||
@@ -210,15 +219,20 @@ function DataTable({
|
||||
}
|
||||
|
||||
const allSelected = items.length > 0 && items.every(i => selectedItems.has(i[itemKey]));
|
||||
|
||||
const tableClass = [
|
||||
'table card-table table-vcenter table-nowrap mb-0',
|
||||
striped && 'table-striped',
|
||||
compact && 'table-sm',
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="table-responsive">
|
||||
<table className="table card-table table-vcenter table-nowrap mb-0">
|
||||
<table className={tableClass} role="grid">
|
||||
<thead>
|
||||
<tr>
|
||||
{selectable && (
|
||||
<th style={{ width: '40px' }}>
|
||||
<th scope="col" style={{ width: '40px' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
@@ -229,7 +243,7 @@ function DataTable({
|
||||
</th>
|
||||
)}
|
||||
{columns.map(renderColumnHeader)}
|
||||
{hasActions && <th className="text-end">Действия</th>}
|
||||
{hasActions && <th scope="col" className="text-end td-actions">Действия</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -261,7 +275,7 @@ function DataTable({
|
||||
</td>
|
||||
))}
|
||||
{hasActions && (
|
||||
<td className="text-end">
|
||||
<td className="text-end td-actions">
|
||||
{renderActions(item)}
|
||||
</td>
|
||||
)}
|
||||
|
||||
+15
-1
@@ -296,7 +296,7 @@ button:focus-visible,
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ===== Table Improvements ===== */
|
||||
/* ===== Table Improvements (Tabler + UX) ===== */
|
||||
.table thead th {
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
@@ -318,6 +318,20 @@ button:focus-visible,
|
||||
background-color: rgba(32, 107, 196, 0.1);
|
||||
}
|
||||
|
||||
/* Колонка «Действия» — фиксированная ширина, не сжимается (лаконичный UX) */
|
||||
.table .td-actions {
|
||||
min-width: 140px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Выбранная строка поверх zebra (table-striped) */
|
||||
.table-striped tbody tr.table-selected > * {
|
||||
--tblr-table-bg-type: rgba(32, 107, 196, 0.08);
|
||||
}
|
||||
.table-striped tbody tr.table-selected:hover > * {
|
||||
--tblr-table-bg-type: rgba(32, 107, 196, 0.12);
|
||||
}
|
||||
|
||||
.user-select-none {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
Reference in New Issue
Block a user