Skip to content

Commit 2d9760e

Browse files
authored
refactor: enhance tables and update table layout (#234)
* refactor: update user table layout * refactor: extract tanstack table definitions to tanstack-table.d.ts - extract tanstack table definitions to tanstack-table.d.ts - update table selector padding styles - update meta type in users-table * refactor: improve tasks layout and table styling - update layout of the Tasks component for better responsiveness - adjust td, th padding styles
1 parent 630a05e commit 2d9760e

File tree

10 files changed

+65
-32
lines changed

10 files changed

+65
-32
lines changed

src/components/data-table/column-header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function DataTableColumnHeader<TData, TValue>({
3737
<Button
3838
variant='ghost'
3939
size='sm'
40-
className='data-[state=open]:bg-accent -ms-3 h-8'
40+
className='data-[state=open]:bg-accent h-8'
4141
>
4242
<span>{title}</span>
4343
{column.getIsSorted() === 'desc' ? (

src/components/data-table/pagination.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import {
1717

1818
type DataTablePaginationProps<TData> = {
1919
table: Table<TData>
20+
className?: string
2021
}
2122

2223
export function DataTablePagination<TData>({
2324
table,
25+
className,
2426
}: DataTablePaginationProps<TData>) {
2527
const currentPage = table.getState().pagination.pageIndex + 1
2628
const totalPages = table.getPageCount()
@@ -30,7 +32,8 @@ export function DataTablePagination<TData>({
3032
<div
3133
className={cn(
3234
'flex items-center justify-between overflow-clip px-2',
33-
'@max-2xl/content:flex-col-reverse @max-2xl/content:gap-4'
35+
'@max-2xl/content:flex-col-reverse @max-2xl/content:gap-4',
36+
className
3437
)}
3538
style={{ overflowClipMargin: 1 }}
3639
>

src/components/ui/table.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
6767
<th
6868
data-slot='table-head'
6969
className={cn(
70-
'text-foreground h-10 px-2 text-start align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-[2px]',
70+
'text-foreground h-10 px-2 text-start align-middle font-medium whitespace-nowrap [&>[role=checkbox]]:translate-y-[2px]',
7171
className
7272
)}
7373
{...props}
@@ -80,7 +80,7 @@ function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
8080
<td
8181
data-slot='table-cell'
8282
className={cn(
83-
'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-[2px]',
83+
'p-2 align-middle whitespace-nowrap [&>[role=checkbox]]:translate-y-[2px]',
8484
className
8585
)}
8686
{...props}

src/features/tasks/components/tasks-columns.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const tasksColumns: ColumnDef<Task>[] = [
4545
header: ({ column }) => (
4646
<DataTableColumnHeader column={column} title='Title' />
4747
),
48+
meta: { className: 'ps-1', tdClassName: 'ps-4' },
4849
cell: ({ row }) => {
4950
const label = labels.find((label) => label.value === row.original.label)
5051

@@ -63,6 +64,7 @@ export const tasksColumns: ColumnDef<Task>[] = [
6364
header: ({ column }) => (
6465
<DataTableColumnHeader column={column} title='Status' />
6566
),
67+
meta: { className: 'ps-1', tdClassName: 'ps-4' },
6668
cell: ({ row }) => {
6769
const status = statuses.find(
6870
(status) => status.value === row.getValue('status')
@@ -90,6 +92,7 @@ export const tasksColumns: ColumnDef<Task>[] = [
9092
header: ({ column }) => (
9193
<DataTableColumnHeader column={column} title='Priority' />
9294
),
95+
meta: { className: 'ps-1', tdClassName: 'ps-3' },
9396
cell: ({ row }) => {
9497
const priority = priorities.find(
9598
(priority) => priority.value === row.getValue('priority')

src/features/tasks/components/tasks-table.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getSortedRowModel,
1313
useReactTable,
1414
} from '@tanstack/react-table'
15+
import { cn } from '@/lib/utils'
1516
import { useTableUrlState } from '@/hooks/use-table-url-state'
1617
import {
1718
Table,
@@ -64,6 +65,7 @@ export function TasksTable({ data }: DataTableProps) {
6465
],
6566
})
6667

68+
// eslint-disable-next-line react-hooks/incompatible-library
6769
const table = useReactTable({
6870
data,
6971
columns,
@@ -103,7 +105,12 @@ export function TasksTable({ data }: DataTableProps) {
103105
}, [pageCount, ensurePageInRange])
104106

105107
return (
106-
<div className='space-y-4 max-sm:has-[div[role="toolbar"]]:mb-16'>
108+
<div
109+
className={cn(
110+
'max-sm:has-[div[role="toolbar"]]:mb-16', // Add margin bottom to the table on mobile when the toolbar is visible
111+
'flex flex-1 flex-col gap-4'
112+
)}
113+
>
107114
<DataTableToolbar
108115
table={table}
109116
searchPlaceholder='Filter by title or ID...'
@@ -127,7 +134,14 @@ export function TasksTable({ data }: DataTableProps) {
127134
<TableRow key={headerGroup.id}>
128135
{headerGroup.headers.map((header) => {
129136
return (
130-
<TableHead key={header.id} colSpan={header.colSpan}>
137+
<TableHead
138+
key={header.id}
139+
colSpan={header.colSpan}
140+
className={cn(
141+
header.column.columnDef.meta?.className,
142+
header.column.columnDef.meta?.thClassName
143+
)}
144+
>
131145
{header.isPlaceholder
132146
? null
133147
: flexRender(
@@ -148,7 +162,13 @@ export function TasksTable({ data }: DataTableProps) {
148162
data-state={row.getIsSelected() && 'selected'}
149163
>
150164
{row.getVisibleCells().map((cell) => (
151-
<TableCell key={cell.id}>
165+
<TableCell
166+
key={cell.id}
167+
className={cn(
168+
cell.column.columnDef.meta?.className,
169+
cell.column.columnDef.meta?.tdClassName
170+
)}
171+
>
152172
{flexRender(
153173
cell.column.columnDef.cell,
154174
cell.getContext()
@@ -170,7 +190,7 @@ export function TasksTable({ data }: DataTableProps) {
170190
</TableBody>
171191
</Table>
172192
</div>
173-
<DataTablePagination table={table} />
193+
<DataTablePagination table={table} className='mt-auto' />
174194
<DataTableBulkActions table={table} />
175195
</div>
176196
)

src/features/tasks/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export function Tasks() {
2222
</div>
2323
</Header>
2424

25-
<Main>
26-
<div className='mb-2 flex flex-wrap items-center justify-between space-y-2 gap-x-4'>
25+
<Main className='flex flex-1 flex-col gap-4 sm:gap-6'>
26+
<div className='flex flex-wrap items-end justify-between gap-2'>
2727
<div>
2828
<h2 className='text-2xl font-bold tracking-tight'>Tasks</h2>
2929
<p className='text-muted-foreground'>
@@ -32,9 +32,7 @@ export function Tasks() {
3232
</div>
3333
<TasksPrimaryButtons />
3434
</div>
35-
<div className='-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-y-0 lg:space-x-12'>
36-
<TasksTable data={tasks} />
37-
</div>
35+
<TasksTable data={tasks} />
3836
</Main>
3937

4038
<TasksDialogs />

src/features/users/components/users-columns.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const usersColumns: ColumnDef<User>[] = [
2323
/>
2424
),
2525
meta: {
26-
className: cn('sticky md:table-cell start-0 z-10 rounded-tl-[inherit]'),
26+
className: cn('max-md:sticky start-0 z-10 rounded-tl-[inherit]'),
2727
},
2828
cell: ({ row }) => (
2929
<Checkbox
@@ -47,7 +47,7 @@ export const usersColumns: ColumnDef<User>[] = [
4747
meta: {
4848
className: cn(
4949
'drop-shadow-[0_1px_2px_rgb(0_0_0_/_0.1)] dark:drop-shadow-[0_1px_2px_rgb(255_255_255_/_0.1)]',
50-
'sticky start-6 @4xl/content:table-cell @4xl/content:drop-shadow-none'
50+
'ps-0.5 max-md:sticky start-6 @4xl/content:table-cell @4xl/content:drop-shadow-none'
5151
),
5252
},
5353
enableHiding: false,
@@ -70,7 +70,7 @@ export const usersColumns: ColumnDef<User>[] = [
7070
<DataTableColumnHeader column={column} title='Email' />
7171
),
7272
cell: ({ row }) => (
73-
<div className='w-fit text-nowrap'>{row.getValue('email')}</div>
73+
<div className='w-fit ps-2 text-nowrap'>{row.getValue('email')}</div>
7474
),
7575
},
7676
{

src/features/users/components/users-table.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ import { type User } from '../data/schema'
2727
import { DataTableBulkActions } from './data-table-bulk-actions'
2828
import { usersColumns as columns } from './users-columns'
2929

30-
declare module '@tanstack/react-table' {
31-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
32-
interface ColumnMeta<TData, TValue> {
33-
className: string
34-
}
35-
}
36-
3730
type DataTableProps = {
3831
data: User[]
3932
search: Record<string, unknown>
@@ -70,6 +63,7 @@ export function UsersTable({ data, search, navigate }: DataTableProps) {
7063
],
7164
})
7265

66+
// eslint-disable-next-line react-hooks/incompatible-library
7367
const table = useReactTable({
7468
data,
7569
columns,
@@ -99,7 +93,12 @@ export function UsersTable({ data, search, navigate }: DataTableProps) {
9993
}, [table, ensurePageInRange])
10094

10195
return (
102-
<div className='space-y-4 max-sm:has-[div[role="toolbar"]]:mb-16'>
96+
<div
97+
className={cn(
98+
'max-sm:has-[div[role="toolbar"]]:mb-16', // Add margin bottom to the table on mobile when the toolbar is visible
99+
'flex flex-1 flex-col gap-4'
100+
)}
101+
>
103102
<DataTableToolbar
104103
table={table}
105104
searchPlaceholder='Filter users...'
@@ -134,7 +133,8 @@ export function UsersTable({ data, search, navigate }: DataTableProps) {
134133
colSpan={header.colSpan}
135134
className={cn(
136135
'bg-background group-hover/row:bg-muted group-data-[state=selected]/row:bg-muted',
137-
header.column.columnDef.meta?.className ?? ''
136+
header.column.columnDef.meta?.className,
137+
header.column.columnDef.meta?.thClassName
138138
)}
139139
>
140140
{header.isPlaceholder
@@ -162,7 +162,8 @@ export function UsersTable({ data, search, navigate }: DataTableProps) {
162162
key={cell.id}
163163
className={cn(
164164
'bg-background group-hover/row:bg-muted group-data-[state=selected]/row:bg-muted',
165-
cell.column.columnDef.meta?.className ?? ''
165+
cell.column.columnDef.meta?.className,
166+
cell.column.columnDef.meta?.tdClassName
166167
)}
167168
>
168169
{flexRender(
@@ -186,7 +187,7 @@ export function UsersTable({ data, search, navigate }: DataTableProps) {
186187
</TableBody>
187188
</Table>
188189
</div>
189-
<DataTablePagination table={table} />
190+
<DataTablePagination table={table} className='mt-auto' />
190191
<DataTableBulkActions table={table} />
191192
</div>
192193
)

src/features/users/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export function Users() {
2828
</div>
2929
</Header>
3030

31-
<Main>
32-
<div className='mb-2 flex flex-wrap items-center justify-between space-y-2'>
31+
<Main className='flex flex-1 flex-col gap-4 sm:gap-6'>
32+
<div className='flex flex-wrap items-end justify-between gap-2'>
3333
<div>
3434
<h2 className='text-2xl font-bold tracking-tight'>User List</h2>
3535
<p className='text-muted-foreground'>
@@ -38,9 +38,7 @@ export function Users() {
3838
</div>
3939
<UsersPrimaryButtons />
4040
</div>
41-
<div className='-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-y-0 lg:space-x-12'>
42-
<UsersTable data={users} search={search} navigate={navigate} />
43-
</div>
41+
<UsersTable data={users} search={search} navigate={navigate} />
4442
</Main>
4543

4644
<UsersDialogs />

src/tanstack-table.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import '@tanstack/react-table'
2+
3+
declare module '@tanstack/react-table' {
4+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
5+
interface ColumnMeta<TData, TValue> {
6+
className?: string // apply to both th and td
7+
tdClassName?: string
8+
thClassName?: string
9+
}
10+
}

0 commit comments

Comments
 (0)