This commit is contained in:
82
frontend/src/components/ui/AnimatedDataTable.jsx
Normal file
82
frontend/src/components/ui/AnimatedDataTable.jsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { animated, useTransition } from '@react-spring/web';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
|
||||
export default function AnimatedDataTable({
|
||||
columns = [],
|
||||
rows = [],
|
||||
rowKey = (row) => row?.id,
|
||||
renderRow,
|
||||
loading = false,
|
||||
loadingMessage = 'Učitavanje...',
|
||||
emptyMessage = 'Nema podataka.',
|
||||
tableClassName = 'min-w-full text-sm',
|
||||
headClassName = 'bg-canvas-deep text-left text-xs uppercase tracking-wide text-text-muted',
|
||||
bodyClassName = 'divide-y divide-border-hairline',
|
||||
rowClassName = 'hover:bg-canvas-deep',
|
||||
wrapperClassName = 'overflow-x-auto',
|
||||
trail = 35,
|
||||
}) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const transitions = useTransition(rows, {
|
||||
keys: (row) => rowKey(row),
|
||||
from: { opacity: 0, transform: 'translate3d(0,8px,0)' },
|
||||
enter: { opacity: 1, transform: 'translate3d(0,0,0)' },
|
||||
leave: { opacity: 0, transform: 'translate3d(0,-8px,0)' },
|
||||
trail,
|
||||
config: { tension: 230, friction: 26 },
|
||||
});
|
||||
|
||||
const colSpan = Math.max(1, columns.length);
|
||||
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<table className={tableClassName}>
|
||||
<thead className={headClassName}>
|
||||
<tr>
|
||||
{columns.map((column) => (
|
||||
<th key={column.key} className={column.className}>
|
||||
{column.label}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className={bodyClassName}>
|
||||
{!mounted && (
|
||||
<tr>
|
||||
<td colSpan={colSpan} className="px-4 py-6 text-center text-sm text-text-muted">
|
||||
{loadingMessage}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{mounted && loading && (
|
||||
<tr>
|
||||
<td colSpan={colSpan} className="px-4 py-6 text-center text-sm text-text-muted">
|
||||
{loadingMessage}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{mounted && !loading && rows.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={colSpan} className="px-4 py-6 text-center text-sm text-text-muted">
|
||||
{emptyMessage}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{mounted && !loading && transitions((style, row) => (
|
||||
<animated.tr
|
||||
key={rowKey(row)}
|
||||
style={style}
|
||||
className={typeof rowClassName === 'function' ? rowClassName(row) : rowClassName}
|
||||
>
|
||||
{renderRow(row)}
|
||||
</animated.tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user