frontend initiatewith shadcn uis
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
'use client';
|
||||
|
||||
import { useRef } from 'react';
|
||||
import { HugeiconsIcon } from '@hugeicons/react';
|
||||
import {
|
||||
Search01Icon,
|
||||
Cancel01Icon,
|
||||
ColumnsThreeCogIcon,
|
||||
Download01Icon,
|
||||
} from '@hugeicons/core-free-icons';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { type ColumnDef, type ExportFormat } from './types';
|
||||
|
||||
interface TableToolbarProps<T> {
|
||||
columns: ColumnDef<T>[];
|
||||
hiddenColumns: Set<string>;
|
||||
globalFilter: string;
|
||||
showExport?: boolean;
|
||||
exportFormats?: ExportFormat[];
|
||||
selectedCount?: number;
|
||||
onGlobalFilterChange: (value: string) => void;
|
||||
onColumnVisibilityChange: (key: string) => void;
|
||||
onExport?: (format: ExportFormat) => void;
|
||||
onClearSelection?: () => void;
|
||||
}
|
||||
|
||||
export function TableToolbar<T>({
|
||||
columns,
|
||||
hiddenColumns,
|
||||
globalFilter,
|
||||
showExport,
|
||||
exportFormats = ['csv', 'excel', 'pdf'],
|
||||
selectedCount = 0,
|
||||
onGlobalFilterChange,
|
||||
onColumnVisibilityChange,
|
||||
onExport,
|
||||
onClearSelection,
|
||||
}: TableToolbarProps<T>) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 p-3 border-b">
|
||||
{/* Global search */}
|
||||
<div className="relative flex-1 max-w-xs">
|
||||
<HugeiconsIcon
|
||||
icon={Search01Icon}
|
||||
className="absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground pointer-events-none"
|
||||
/>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={globalFilter}
|
||||
onChange={e => onGlobalFilterChange(e.target.value)}
|
||||
placeholder="Search…"
|
||||
className="pl-8 pr-8 h-8 text-sm"
|
||||
/>
|
||||
{globalFilter && (
|
||||
<button
|
||||
onClick={() => onGlobalFilterChange('')}
|
||||
className="absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<HugeiconsIcon icon={Cancel01Icon} className="size-3.5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Selection badge */}
|
||||
{selectedCount > 0 && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{selectedCount} selected
|
||||
</Badge>
|
||||
<Button variant="ghost" size="xs" onClick={onClearSelection} className="text-xs h-6">
|
||||
Clear
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Column visibility */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger render={<Button variant="outline" size="sm" className="gap-1.5" />}>
|
||||
<HugeiconsIcon icon={ColumnsThreeCogIcon} className="size-4" />
|
||||
Columns
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
{columns.map(col => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={col.key}
|
||||
checked={!hiddenColumns.has(col.key)}
|
||||
onCheckedChange={() => onColumnVisibilityChange(col.key)}
|
||||
>
|
||||
{col.title}
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
{/* Export */}
|
||||
{showExport && onExport && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger render={<Button variant="outline" size="sm" className="gap-1.5" />}>
|
||||
<HugeiconsIcon icon={Download01Icon} className="size-4" />
|
||||
Export
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
{exportFormats.map(fmt => (
|
||||
<DropdownMenuItem key={fmt} onClick={() => onExport(fmt)}>
|
||||
{fmt.toUpperCase()}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user