pagination.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import {
  2. ChevronLeftIcon,
  3. ChevronRightIcon,
  4. DoubleArrowLeftIcon,
  5. DoubleArrowRightIcon,
  6. } from '@radix-ui/react-icons'
  7. import { type Table } from '@tanstack/react-table'
  8. import { cn, getPageNumbers } from '@/lib/utils'
  9. import { Button } from '@/components/ui/button'
  10. import {
  11. Select,
  12. SelectContent,
  13. SelectItem,
  14. SelectTrigger,
  15. SelectValue,
  16. } from '@/components/ui/select'
  17. type DataTablePaginationProps<TData> = {
  18. table: Table<TData>
  19. className?: string
  20. }
  21. export function DataTablePagination<TData>({
  22. table,
  23. className,
  24. }: DataTablePaginationProps<TData>) {
  25. const currentPage = table.getState().pagination.pageIndex + 1
  26. const totalPages = table.getPageCount()
  27. const pageNumbers = getPageNumbers(currentPage, totalPages)
  28. return (
  29. <div
  30. className={cn(
  31. 'flex items-center justify-between overflow-clip px-2',
  32. '@max-2xl/content:flex-col-reverse @max-2xl/content:gap-4',
  33. className
  34. )}
  35. style={{ overflowClipMargin: 1 }}
  36. >
  37. <div className='flex w-full items-center justify-between'>
  38. <div className='flex w-[100px] items-center justify-center text-sm font-medium @2xl/content:hidden'>
  39. Page {currentPage} of {totalPages}
  40. </div>
  41. <div className='flex items-center gap-2 @max-2xl/content:flex-row-reverse'>
  42. <Select
  43. value={`${table.getState().pagination.pageSize}`}
  44. onValueChange={(value) => {
  45. table.setPageSize(Number(value))
  46. }}
  47. >
  48. <SelectTrigger className='h-8 w-[70px]'>
  49. <SelectValue placeholder={table.getState().pagination.pageSize} />
  50. </SelectTrigger>
  51. <SelectContent side='top'>
  52. {[10, 20, 30, 40, 50].map((pageSize) => (
  53. <SelectItem key={pageSize} value={`${pageSize}`}>
  54. {pageSize}
  55. </SelectItem>
  56. ))}
  57. </SelectContent>
  58. </Select>
  59. <p className='hidden text-sm font-medium sm:block'>Rows per page</p>
  60. </div>
  61. </div>
  62. <div className='flex items-center sm:space-x-6 lg:space-x-8'>
  63. <div className='flex w-[100px] items-center justify-center text-sm font-medium @max-3xl/content:hidden'>
  64. Page {currentPage} of {totalPages}
  65. </div>
  66. <div className='flex items-center space-x-2'>
  67. <Button
  68. variant='outline'
  69. className='size-8 p-0 @max-md/content:hidden'
  70. onClick={() => table.setPageIndex(0)}
  71. disabled={!table.getCanPreviousPage()}
  72. >
  73. <span className='sr-only'>Go to first page</span>
  74. <DoubleArrowLeftIcon className='h-4 w-4' />
  75. </Button>
  76. <Button
  77. variant='outline'
  78. className='size-8 p-0'
  79. onClick={() => table.previousPage()}
  80. disabled={!table.getCanPreviousPage()}
  81. >
  82. <span className='sr-only'>Go to previous page</span>
  83. <ChevronLeftIcon className='h-4 w-4' />
  84. </Button>
  85. {/* Page number buttons */}
  86. {pageNumbers.map((pageNumber, index) => (
  87. <div key={`${pageNumber}-${index}`} className='flex items-center'>
  88. {pageNumber === '...' ? (
  89. <span className='px-1 text-sm text-muted-foreground'>...</span>
  90. ) : (
  91. <Button
  92. variant={currentPage === pageNumber ? 'default' : 'outline'}
  93. className='h-8 min-w-8 px-2'
  94. onClick={() => table.setPageIndex((pageNumber as number) - 1)}
  95. >
  96. <span className='sr-only'>Go to page {pageNumber}</span>
  97. {pageNumber}
  98. </Button>
  99. )}
  100. </div>
  101. ))}
  102. <Button
  103. variant='outline'
  104. className='size-8 p-0'
  105. onClick={() => table.nextPage()}
  106. disabled={!table.getCanNextPage()}
  107. >
  108. <span className='sr-only'>Go to next page</span>
  109. <ChevronRightIcon className='h-4 w-4' />
  110. </Button>
  111. <Button
  112. variant='outline'
  113. className='size-8 p-0 @max-md/content:hidden'
  114. onClick={() => table.setPageIndex(table.getPageCount() - 1)}
  115. disabled={!table.getCanNextPage()}
  116. >
  117. <span className='sr-only'>Go to last page</span>
  118. <DoubleArrowRightIcon className='h-4 w-4' />
  119. </Button>
  120. </div>
  121. </div>
  122. </div>
  123. )
  124. }