-
Notifications
You must be signed in to change notification settings - Fork 77
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
Repository table CSS tweaks #106
base: main
Are you sure you want to change the base?
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"> | ||
<div className="flex items-center justify-between py-4"> | ||
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 |
||
<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