pin columns

This commit is contained in:
2025-11-25 13:39:19 -03:00
parent de340a6d46
commit 0278fca9f2
7 changed files with 65 additions and 32 deletions

View File

@@ -47,12 +47,14 @@ export const columns: ColumnDef<Enrollment>[] = [
{ {
id: 'select', id: 'select',
header: DataTableColumnHeaderSelect, header: DataTableColumnHeaderSelect,
cell: DataTableColumnSelect cell: DataTableColumnSelect,
meta: { className: 'w-9' }
}, },
...columns_, ...columns_,
{ {
id: 'actions', id: 'action',
cell: ActionMenu cell: ActionMenu,
meta: { className: 'w-12' }
} }
] ]

View File

@@ -89,6 +89,7 @@ export default function Route({ loaderData: { data } }: Route.ComponentProps) {
sort={[{ id: 'created_at', desc: true }]} sort={[{ id: 'created_at', desc: true }]}
columns={columns} columns={columns}
data={hits as Enrollment[]} data={hits as Enrollment[]}
columnPinning={{ left: ['select'], right: ['action'] }}
pageIndex={page - 1} pageIndex={page - 1}
pageSize={hitsPerPage} pageSize={hitsPerPage}
setSelectedRows={setSelectedRows} setSelectedRows={setSelectedRows}

View File

@@ -14,7 +14,8 @@ export const columns: ColumnDef<Order>[] = [
{ {
id: 'select', id: 'select',
header: DataTableColumnHeaderSelect, header: DataTableColumnHeaderSelect,
cell: DataTableColumnSelect cell: DataTableColumnSelect,
meta: { className: 'w-9' }
}, },
...columns_ ...columns_
] ]

View File

@@ -42,12 +42,14 @@ export const columns: ColumnDef<User>[] = [
{ {
id: 'select', id: 'select',
header: DataTableColumnHeaderSelect, header: DataTableColumnHeaderSelect,
cell: DataTableColumnSelect cell: DataTableColumnSelect,
meta: { className: 'w-9' }
}, },
...columns_, ...columns_,
{ {
id: 'actions', id: 'actions',
cell: ActionMenu cell: ActionMenu,
meta: { className: 'w-12' }
} }
] ]

View File

@@ -5,6 +5,7 @@ import {
getCoreRowModel, getCoreRowModel,
useReactTable, useReactTable,
type ColumnDef, type ColumnDef,
type ColumnPinningState,
type ColumnSort, type ColumnSort,
type RowSelectionState, type RowSelectionState,
type SortingState, type SortingState,
@@ -38,6 +39,7 @@ import { DataTablePagination } from './pagination'
interface DataTableProps<TData, TValue> { interface DataTableProps<TData, TValue> {
children?: ReactNode children?: ReactNode
columns: ColumnDef<TData, TValue>[] columns: ColumnDef<TData, TValue>[]
columnPinning?: ColumnPinningState
data: TData[] data: TData[]
setSelectedRows?: (selectedRows: TData[]) => void setSelectedRows?: (selectedRows: TData[]) => void
pageIndex: number pageIndex: number
@@ -67,6 +69,7 @@ export function DataTable<TData, TValue>({
data, data,
children, children,
columns, columns,
columnPinning = { left: [], right: [] },
sort, sort,
pageIndex, pageIndex,
pageSize, pageSize,
@@ -192,10 +195,12 @@ export function DataTable<TData, TValue>({
sorting, sorting,
rowSelection, rowSelection,
columnVisibility, columnVisibility,
columnPinning,
pagination: { pageIndex, pageSize } pagination: { pageIndex, pageSize }
}, },
manualSorting: true, manualSorting: true,
manualPagination: true, manualPagination: true,
enableColumnPinning: true,
enableRowSelection: true, enableRowSelection: true,
getRowId, getRowId,
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
@@ -220,7 +225,7 @@ export function DataTable<TData, TValue>({
<CardContent> <CardContent>
{children} {children}
<Table_ className="table-auto"> <Table_ className="table-auto w-full">
<TableHeader> <TableHeader>
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map((headerGroup) => (
<TableRow <TableRow
@@ -228,11 +233,18 @@ export function DataTable<TData, TValue>({
className="hover:bg-transparent" className="hover:bg-transparent"
> >
{headerGroup.headers.map((header) => { {headerGroup.headers.map((header) => {
const isPinned = header.column.getIsPinned()
return ( return (
<TableHead <TableHead
key={header.id} key={header.id}
className={cn( className={cn(
isPinned && 'z-1 lg:sticky bg-card',
isPinned === 'left' && 'left-0',
isPinned === 'right' && 'right-0',
'p-2.5', 'p-2.5',
// Override the shadcn class
'[&:has([role=checkbox])]:pr-2.5',
// @ts-ignore // @ts-ignore
header.column.columnDef.meta?.className header.column.columnDef.meta?.className
)} )}
@@ -252,29 +264,42 @@ export function DataTable<TData, TValue>({
<TableBody> <TableBody>
{table.getRowModel().rows?.length ? ( {table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => ( table.getRowModel().rows.map((row) => {
<TableRow const isSelected = row.getIsSelected()
key={row.id}
data-state={row.getIsSelected() && 'selected'} return (
className="has-data-[state=open]:bg-muted/50" <TableRow
> key={row.id}
{row.getVisibleCells().map((cell) => ( data-state={isSelected && 'selected'}
<TableCell className="group has-data-[state=open]:bg-muted transition-none hover:bg-muted relative z-5"
key={cell.id} >
className={cn( {row.getVisibleCells().map((cell) => {
'p-2.5', const isPinned = cell.column.getIsPinned()
// @ts-ignore
cell.column.columnDef.meta?.className return (
)} <TableCell
> key={cell.id}
{flexRender( className={cn(
cell.column.columnDef.cell, isPinned &&
cell.getContext() 'lg:sticky z-1 bg-card group-hover:bg-muted group-has-data-[state=open]:bg-muted',
)} isPinned && isSelected && 'bg-muted',
</TableCell> isPinned === 'left' && 'left-0',
))} isPinned === 'right' && 'right-0',
</TableRow> 'p-2.5',
)) // @ts-ignore
cell.column.columnDef.meta?.className
)}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
)
})}
</TableRow>
)
})
) : ( ) : (
<TableRow> <TableRow>
<TableCell <TableCell

View File

@@ -28,7 +28,9 @@ export const columns: ColumnDef<Enrollment>[] = [
return ( return (
<div className="flex gap-2.5 items-center"> <div className="flex gap-2.5 items-center">
<Avatar className="size-10 hidden lg:block"> <Avatar className="size-10 hidden lg:block">
<AvatarFallback>{initials(user.name)}</AvatarFallback> <AvatarFallback className="border">
{initials(user.name)}
</AvatarFallback>
</Avatar> </Avatar>
<ul> <ul>

View File

@@ -23,7 +23,7 @@ export const columns: ColumnDef<User>[] = [
return ( return (
<div className="flex gap-2.5 items-center"> <div className="flex gap-2.5 items-center">
<Avatar className="size-10 hidden lg:block"> <Avatar className="size-10 hidden lg:block">
<AvatarFallback>{initials(name)}</AvatarFallback> <AvatarFallback className="border">{initials(name)}</AvatarFallback>
</Avatar> </Avatar>
<ul> <ul>