fix: remove extra bottom padding from filter and pagination bars

CardContent defaults to px-5 pb-4. Tailwind's CSS cascade means pb-4
always wins over the py-0 override, leaving 16px of phantom bottom
padding on all thin toolbar cards. Replaced CardContent with plain divs
carrying the intended py-2 px-3 directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 03:10:37 -04:00
parent 7819e438df
commit 47a0ccc88c
+125 -133
View File
@@ -29,7 +29,7 @@ import {
import * as React from "react"; import * as React from "react";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import { Card, CardContent } from "~/components/ui/card"; import { Card } from "~/components/ui/card";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuCheckboxItem, DropdownMenuCheckboxItem,
@@ -231,115 +231,113 @@ export function DataTable<TData, TValue>({
{/* Filter Bar Card */} {/* Filter Bar Card */}
{(showSearch || filterableColumns.length > 0 || showColumnVisibility) && ( {(showSearch || filterableColumns.length > 0 || showColumnVisibility) && (
<Card className="bg-card border-border border py-2"> <Card className="bg-card border-border border">
<CardContent className="px-3 py-0"> <div className="flex items-center gap-2 px-3 py-2">
<div className="flex items-center gap-2"> {showSearch && (
{showSearch && ( <div className="relative min-w-0 flex-1">
<div className="relative min-w-0 flex-1"> <Search className="text-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
<Search className="text-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" /> <Input
<Input placeholder={searchPlaceholder}
placeholder={searchPlaceholder} value={searchInput ?? ""}
value={searchInput ?? ""} onChange={(event) => setSearchInput(event.target.value)}
onChange={(event) => setSearchInput(event.target.value)} className="h-9 w-full pr-3 pl-9"
className="h-9 w-full pr-3 pl-9" />
/> </div>
</div> )}
)} {filterableColumns.map((column) => (
{filterableColumns.map((column) => ( <Select
<Select key={column.id}
key={column.id} value={
value={ (table.getColumn(column.id)?.getFilterValue() as string) ??
(table.getColumn(column.id)?.getFilterValue() as string) ?? "all"
"all" }
} onValueChange={(value) =>
onValueChange={(value) => table
table .getColumn(column.id)
.getColumn(column.id) ?.setFilterValue(value === "all" ? "" : value)
?.setFilterValue(value === "all" ? "" : value) }
} >
> <SelectTrigger className="h-9 w-9 p-0 sm:w-[180px] sm:px-3 [&>svg]:hidden sm:[&>svg]:inline-flex">
<SelectTrigger className="h-9 w-9 p-0 sm:w-[180px] sm:px-3 [&>svg]:hidden sm:[&>svg]:inline-flex"> <div className="flex w-full items-center justify-center">
<div className="flex w-full items-center justify-center"> <Filter className="text-foreground h-4 w-4 sm:hidden" />
<Filter className="text-foreground h-4 w-4 sm:hidden" /> <span className="hidden sm:inline">
<span className="hidden sm:inline"> <SelectValue placeholder={column.title} />
<SelectValue placeholder={column.title} /> </span>
</span> </div>
</div> </SelectTrigger>
</SelectTrigger> <SelectContent>
<SelectContent> <SelectItem value="all" className="gap-0">
<SelectItem value="all" className="gap-0"> All {column.title}
All {column.title} </SelectItem>
</SelectItem> {column.options.map((option) => (
{column.options.map((option) => ( <SelectItem
<SelectItem key={option.value}
key={option.value} value={option.value}
value={option.value} className="gap-0"
className="gap-0"
>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
))}
{filterableColumns.length > 0 && (
<Button
variant="outline"
size="sm"
className="h-9 w-9 p-0 sm:w-auto sm:px-4"
onClick={() => {
table.resetColumnFilters();
setGlobalFilter("");
}}
>
<X className="h-4 w-4 sm:hidden" />
<span className="hidden sm:flex sm:items-center">
<Filter className="text-foreground mr-2 h-3.5 w-3.5" />
Clear filters
</span>
</Button>
)}
{showColumnVisibility && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="hidden h-9 sm:flex"
> >
Columns <ChevronDown className="ml-2 h-3.5 w-3.5" /> {option.label}
</Button> </SelectItem>
</DropdownMenuTrigger> ))}
<DropdownMenuContent align="end" className="w-[150px]"> </SelectContent>
{table </Select>
.getAllColumns() ))}
.filter((column) => column.getCanHide()) {filterableColumns.length > 0 && (
.map((column) => { <Button
return ( variant="outline"
<DropdownMenuCheckboxItem size="sm"
key={column.id} className="h-9 w-9 p-0 sm:w-auto sm:px-4"
className="capitalize" onClick={() => {
checked={column.getIsVisible()} table.resetColumnFilters();
onCheckedChange={(value) => setGlobalFilter("");
column.toggleVisibility(!!value) }}
} >
> <X className="h-4 w-4 sm:hidden" />
{column.id} <span className="hidden sm:flex sm:items-center">
</DropdownMenuCheckboxItem> <Filter className="text-foreground mr-2 h-3.5 w-3.5" />
); Clear filters
})} </span>
</DropdownMenuContent> </Button>
</DropdownMenu> )}
)} {showColumnVisibility && (
</div> <DropdownMenu>
</CardContent> <DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="hidden h-9 sm:flex"
>
Columns <ChevronDown className="ml-2 h-3.5 w-3.5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[150px]">
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
</Card> </Card>
)} )}
{/* Selection Toolbar */} {/* Selection Toolbar */}
{selectionActions && table.getSelectedRowModel().rows.length > 0 && ( {selectionActions && table.getSelectedRowModel().rows.length > 0 && (
<Card className="bg-primary/5 border-primary/20 border py-2"> <Card className="bg-primary/5 border-primary/20 border">
<CardContent className="flex items-center justify-between gap-3 px-3 py-0"> <div className="flex items-center justify-between gap-3 px-3 py-2">
<span className="text-foreground text-sm font-medium"> <span className="text-foreground text-sm font-medium">
{table.getSelectedRowModel().rows.length} selected {table.getSelectedRowModel().rows.length} selected
</span> </span>
@@ -349,7 +347,7 @@ export function DataTable<TData, TValue>({
() => table.resetRowSelection(), () => table.resetRowSelection(),
)} )}
</div> </div>
</CardContent> </div>
</Card> </Card>
)} )}
@@ -435,9 +433,8 @@ export function DataTable<TData, TValue>({
{/* Pagination Bar Card */} {/* Pagination Bar Card */}
{showPagination && ( {showPagination && (
<Card className="bg-card border-border border py-2"> <Card className="bg-card border-border border">
<CardContent className="px-3 py-0"> <div className="flex items-center justify-between gap-2 px-3 py-2">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<p className="text-muted-foreground hidden text-xs sm:inline sm:text-sm"> <p className="text-muted-foreground hidden text-xs sm:inline sm:text-sm">
{table.getFilteredRowModel().rows.length === 0 {table.getFilteredRowModel().rows.length === 0
@@ -537,8 +534,7 @@ export function DataTable<TData, TValue>({
<span className="sr-only">Last page</span> <span className="sr-only">Last page</span>
</Button> </Button>
</div> </div>
</div> </div>
</CardContent>
</Card> </Card>
)} )}
</div> </div>
@@ -596,13 +592,11 @@ export function DataTableSkeleton({
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{/* Filter bar skeleton */} {/* Filter bar skeleton */}
<Card className="bg-card border-border border py-2"> <Card className="bg-card border-border border">
<CardContent className="px-3 py-0"> <div className="flex items-center gap-2 px-3 py-2">
<div className="flex items-center gap-2"> <div className="bg-muted/30 h-9 w-full flex-1 animate-pulse sm:max-w-sm"></div>
<div className="bg-muted/30 h-9 w-full flex-1 animate-pulse sm:max-w-sm"></div> <div className="bg-muted/30 h-9 w-24 animate-pulse"></div>
<div className="bg-muted/30 h-9 w-24 animate-pulse"></div> </div>
</div>
</CardContent>
</Card> </Card>
{/* Table skeleton */} {/* Table skeleton */}
@@ -667,23 +661,21 @@ export function DataTableSkeleton({
</Card> </Card>
{/* Pagination skeleton */} {/* Pagination skeleton */}
<Card className="bg-card border-border border py-2"> <Card className="bg-card border-border border">
<CardContent className="px-3 py-0"> <div className="flex items-center justify-between gap-2 px-3 py-2">
<div className="flex items-center justify-between gap-2"> <div className="flex items-center gap-2">
<div className="flex items-center gap-2"> <div className="bg-muted/30 h-4 w-20 animate-pulse rounded text-xs sm:w-32 sm:text-sm"></div>
<div className="bg-muted/30 h-4 w-20 animate-pulse rounded text-xs sm:w-32 sm:text-sm"></div> <div className="bg-muted/30 h-8 w-[70px] animate-pulse rounded"></div>
<div className="bg-muted/30 h-8 w-[70px] animate-pulse rounded"></div>
</div>
<div className="flex items-center gap-1">
{Array.from({ length: 5 }).map((_, i) => (
<div
key={i}
className="bg-muted/30 h-8 w-8 animate-pulse rounded"
></div>
))}
</div>
</div> </div>
</CardContent> <div className="flex items-center gap-1">
{Array.from({ length: 5 }).map((_, i) => (
<div
key={i}
className="bg-muted/30 h-8 w-8 animate-pulse rounded"
></div>
))}
</div>
</div>
</Card> </Card>
</div> </div>
); );