- 
                Notifications
    You must be signed in to change notification settings 
- Fork 166
Repository table CSS tweaks #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6818406
              103e4f5
              e284d3e
              51104b5
              ba23077
              2d4e359
              97c5a0f
              0979b07
              1193bda
              6d8ba19
              5156fa6
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| "use client" | ||
| "use client"; | ||
|  | ||
| import React from "react"; | ||
| import { | ||
| ColumnDef, | ||
| ColumnFiltersState, | ||
|  | @@ -10,25 +11,24 @@ import { | |
| getPaginationRowModel, | ||
| getSortedRowModel, | ||
| useReactTable, | ||
| } from "@tanstack/react-table" | ||
| } from "@tanstack/react-table"; | ||
| import { Button } from "@/components/ui/button"; | ||
| import { Input } from "@/components/ui/input"; | ||
| import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; | ||
| import { | ||
| Table, | ||
| TableBody, | ||
| TableCell, | ||
| TableHead, | ||
| TableHeader, | ||
| TableRow, | ||
| } from "@/components/ui/table" | ||
| import { Button } from "@/components/ui/button" | ||
| import { Input } from "@/components/ui/input" | ||
| import * as React from "react" | ||
|  | ||
| DropdownMenu, | ||
| DropdownMenuTrigger, | ||
| DropdownMenuContent, | ||
| DropdownMenuRadioGroup, | ||
| DropdownMenuRadioItem, | ||
| } from "@/components/ui/dropdown-menu"; | ||
| import { ChevronDown } from "lucide-react"; | ||
|  | ||
| interface DataTableProps<TData, TValue> { | ||
| columns: ColumnDef<TData, TValue>[] | ||
| data: TData[] | ||
| searchKey: string | ||
| searchPlaceholder?: string | ||
| columns: ColumnDef<TData, TValue>[]; | ||
| data: TData[]; | ||
| searchKey: string; | ||
| searchPlaceholder?: string; | ||
| } | ||
|  | ||
| export function DataTable<TData, TValue>({ | ||
|  | @@ -37,100 +37,136 @@ export function DataTable<TData, TValue>({ | |
| searchKey, | ||
| searchPlaceholder, | ||
| }: DataTableProps<TData, TValue>) { | ||
| const [sorting, setSorting] = React.useState<SortingState>([]) | ||
| const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( | ||
| [] | ||
| ) | ||
| const [sorting, setSorting] = React.useState<SortingState>([]); | ||
| const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]); | ||
| const [pagination, setPagination] = React.useState({ | ||
| pageIndex: 0, | ||
| pageSize: 10, // Default page size | ||
| }); | ||
|  | ||
| const table = useReactTable({ | ||
| data, | ||
| columns, | ||
| getCoreRowModel: getCoreRowModel(), | ||
| getPaginationRowModel: getPaginationRowModel(), | ||
| onSortingChange: setSorting, | ||
| getSortedRowModel: getSortedRowModel(), | ||
| onColumnFiltersChange: setColumnFilters, | ||
| getFilteredRowModel: getFilteredRowModel(), | ||
| state: { | ||
| sorting, | ||
| columnFilters, | ||
| pagination, | ||
| }, | ||
| }) | ||
| onSortingChange: setSorting, | ||
| onColumnFiltersChange: setColumnFilters, | ||
| onPaginationChange: setPagination, | ||
| getCoreRowModel: getCoreRowModel(), | ||
| getPaginationRowModel: getPaginationRowModel(), | ||
| getSortedRowModel: getSortedRowModel(), | ||
| getFilteredRowModel: getFilteredRowModel(), | ||
| }); | ||
|  | ||
| return ( | ||
| <div> | ||
| <div className="flex items-center py-4"> | ||
| <div className="pb-12"> | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: could we add a optional  | ||
| <div className="flex items-center justify-between py-4"> | ||
| <Input | ||
| placeholder={searchPlaceholder} | ||
| value={(table.getColumn(searchKey)?.getFilterValue() as string) ?? ""} | ||
| onChange={(event) => | ||
| table.getColumn(searchKey)?.setFilterValue(event.target.value) | ||
| } | ||
| onChange={(event) => table.getColumn(searchKey)?.setFilterValue(event.target.value)} | ||
| className="max-w-sm" | ||
| /> | ||
|  | ||
| {/* Pagination Controls */} | ||
| <div className="flex items-center space-x-4"> | ||
| <span className="text-sm font-medium min-w-20"> | ||
| Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} | ||
| </span> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.previousPage()} | ||
| disabled={!table.getCanPreviousPage()} | ||
| > | ||
| Previous | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.nextPage()} | ||
| disabled={!table.getCanNextPage()} | ||
| > | ||
| Next | ||
| </Button> | ||
|  | ||
| {/* Radix Dropdown for items per page */} | ||
| <DropdownMenu> | ||
| <DropdownMenuTrigger asChild> | ||
| {/* Fixed width here to prevent layout shift */} | ||
| <Button variant="outline" size="sm" className="w-28 justify-between"> | ||
| Show {pagination.pageSize} | ||
| <ChevronDown className="ml-2 h-4 w-4" /> | ||
| </Button> | ||
| </DropdownMenuTrigger> | ||
| <DropdownMenuContent className="w-28"> | ||
| <DropdownMenuRadioGroup | ||
| value={String(pagination.pageSize)} | ||
| onValueChange={(value) => | ||
| setPagination((prev) => ({ | ||
| ...prev, | ||
| pageSize: Number(value), | ||
| })) | ||
| } | ||
| > | ||
| <DropdownMenuRadioItem value="10">10</DropdownMenuRadioItem> | ||
| <DropdownMenuRadioItem value="20">20</DropdownMenuRadioItem> | ||
| <DropdownMenuRadioItem value="50">50</DropdownMenuRadioItem> | ||
| <DropdownMenuRadioItem value="100">100</DropdownMenuRadioItem> | ||
| </DropdownMenuRadioGroup> | ||
| </DropdownMenuContent> | ||
| </DropdownMenu> | ||
| </div> | ||
| </div> | ||
|  | ||
| <div className="rounded-md border"> | ||
| <Table> | ||
| <Table className="table-fixed"> | ||
| <TableHeader> | ||
| {table.getHeaderGroups().map((headerGroup) => ( | ||
| <TableRow key={headerGroup.id}> | ||
| {headerGroup.headers.map((header) => { | ||
| return ( | ||
| <TableHead key={header.id}> | ||
| {header.isPlaceholder | ||
| ? null | ||
| : flexRender( | ||
| header.column.columnDef.header, | ||
| header.getContext() | ||
| )} | ||
| </TableHead> | ||
| ) | ||
| })} | ||
| {headerGroup.headers.map((header) => ( | ||
| <TableHead | ||
| key={header.id} | ||
| style={{ width: header.column.getSize() }} | ||
| > | ||
| {header.isPlaceholder | ||
| ? null | ||
| : flexRender( | ||
| header.column.columnDef.header, | ||
| header.getContext() | ||
| )} | ||
| </TableHead> | ||
| ))} | ||
| </TableRow> | ||
| ))} | ||
| </TableHeader> | ||
| <TableBody> | ||
| {table.getRowModel().rows?.length ? ( | ||
| table.getRowModel().rows.map((row) => ( | ||
| <TableRow | ||
| key={row.id} | ||
| data-state={row.getIsSelected() && "selected"} | ||
| > | ||
| <TableRow key={row.id} data-state={row.getIsSelected() && "selected"}> | ||
| {row.getVisibleCells().map((cell) => ( | ||
| <TableCell key={cell.id}> | ||
| <TableCell key={cell.id} style={{ width: cell.column.getSize() }}> | ||
| {flexRender(cell.column.columnDef.cell, cell.getContext())} | ||
| </TableCell> | ||
| ))} | ||
| </TableRow> | ||
| )) | ||
| ) : ( | ||
| <TableRow> | ||
| <TableCell colSpan={columns.length} className="h-24 text-center"> | ||
| <TableCell | ||
| colSpan={columns.length} | ||
| className="h-24 text-center" | ||
| > | ||
| No results. | ||
| </TableCell> | ||
| </TableRow> | ||
| )} | ||
| </TableBody> | ||
| </Table> | ||
| </div> | ||
| <div className="flex items-center justify-end space-x-2 py-4"> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.previousPage()} | ||
| disabled={!table.getCanPreviousPage()} | ||
| > | ||
| Previous | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.nextPage()} | ||
| disabled={!table.getCanNextPage()} | ||
| > | ||
| Next | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| ) | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -47,7 +47,7 @@ const DropdownMenuSubContent = React.forwardRef< | |
| <DropdownMenuPrimitive.SubContent | ||
| ref={ref} | ||
| className={cn( | ||
| "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
| "z-50 min-w-[6rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of modifying the component directly here, could we pass the  | ||
| className | ||
| )} | ||
| {...props} | ||
|  | @@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef< | |
| ref={ref} | ||
| sideOffset={sideOffset} | ||
| className={cn( | ||
| "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
| "z-50 min-w-[6rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
| className | ||
| )} | ||
| {...props} | ||
|  | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
micro nit: usually when adding conditional CSS, we use
clsx