pagination.tsx 4.4 KB

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