138 lines
4.6 KiB
TypeScript
138 lines
4.6 KiB
TypeScript
|
|
import { Header, Table, flexRender } from "@tanstack/react-table";
|
||
|
|
|
||
|
|
import {
|
||
|
|
Button,
|
||
|
|
DropdownMenu,
|
||
|
|
DropdownMenuContent,
|
||
|
|
DropdownMenuItem,
|
||
|
|
DropdownMenuSeparator,
|
||
|
|
DropdownMenuTrigger,
|
||
|
|
Separator,
|
||
|
|
} from "@repo/shadcn-ui/components";
|
||
|
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
||
|
|
import { t } from "i18next";
|
||
|
|
import { ArrowDownIcon, ArrowDownUpIcon, ArrowUpIcon, EyeOffIcon } from "lucide-react";
|
||
|
|
|
||
|
|
interface DataTableColumnHeaderProps<TData, TValue> extends React.HTMLAttributes<HTMLDivElement> {
|
||
|
|
table: Table<TData>;
|
||
|
|
header: Header<TData, TValue>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function DataTableColumnHeader<TData, TValue>({
|
||
|
|
table,
|
||
|
|
header,
|
||
|
|
className,
|
||
|
|
}: DataTableColumnHeaderProps<TData, TValue>) {
|
||
|
|
if (!header.column.getCanSort()) {
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<div className={cn("data-[state=open]:bg-accent tracking-wide text-ellipsis", className)}>
|
||
|
|
{header.isPlaceholder
|
||
|
|
? null
|
||
|
|
: flexRender(header.column.columnDef.header, header.getContext())}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{false && header.column.getCanResize() && (
|
||
|
|
<Separator
|
||
|
|
orientation='vertical'
|
||
|
|
className={cn(
|
||
|
|
"absolute top-0 h-full w-[5px] bg-black/10 cursor-col-resize",
|
||
|
|
table.options.columnResizeDirection,
|
||
|
|
header.column.getIsResizing() ? "bg-primary opacity-100" : ""
|
||
|
|
)}
|
||
|
|
{...{
|
||
|
|
onDoubleClick: () => header.column.resetSize(),
|
||
|
|
onMouseDown: header.getResizeHandler(),
|
||
|
|
onTouchStart: header.getResizeHandler(),
|
||
|
|
style: {
|
||
|
|
transform:
|
||
|
|
table.options.columnResizeMode === "onEnd" && header.column.getIsResizing()
|
||
|
|
? `translateX(${
|
||
|
|
(table.options.columnResizeDirection === "rtl" ? -1 : 1) *
|
||
|
|
(table.getState().columnSizingInfo.deltaOffset ?? 0)
|
||
|
|
}px)`
|
||
|
|
: "",
|
||
|
|
},
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className={cn("flex items-center space-x-2", className)}>
|
||
|
|
<DropdownMenu>
|
||
|
|
<DropdownMenuTrigger asChild>
|
||
|
|
<Button
|
||
|
|
aria-label={
|
||
|
|
header.column.getIsSorted() === "desc"
|
||
|
|
? t("common.sort_desc_description")
|
||
|
|
: header.column.getIsSorted() === "asc"
|
||
|
|
? t("common.sort_asc_description")
|
||
|
|
: t("sort_none_description")
|
||
|
|
}
|
||
|
|
size='sm'
|
||
|
|
variant='ghost'
|
||
|
|
className='-ml-3 h-8 data-[state=open]:bg-accent font-bold text-muted-foreground'
|
||
|
|
>
|
||
|
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||
|
|
|
||
|
|
{header.column.getIsSorted() === "desc" ? (
|
||
|
|
<ArrowDownIcon className='w-4 h-4 ml-2' aria-hidden='true' />
|
||
|
|
) : header.column.getIsSorted() === "asc" ? (
|
||
|
|
<ArrowUpIcon className='w-4 h-4 ml-2' aria-hidden='true' />
|
||
|
|
) : (
|
||
|
|
<ArrowDownUpIcon
|
||
|
|
className='w-4 h-4 ml-2 text-muted-foreground/30'
|
||
|
|
aria-hidden='true'
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
</Button>
|
||
|
|
</DropdownMenuTrigger>
|
||
|
|
<DropdownMenuContent align='start'>
|
||
|
|
{header.column.getCanSort() && (
|
||
|
|
<>
|
||
|
|
<DropdownMenuItem
|
||
|
|
onClick={() => header.column.toggleSorting(false)}
|
||
|
|
aria-label={t("common.sort_asc")}
|
||
|
|
>
|
||
|
|
<ArrowUpIcon
|
||
|
|
className='mr-2 h-3.5 w-3.5 text-muted-foreground/70'
|
||
|
|
aria-hidden='true'
|
||
|
|
/>
|
||
|
|
{t("common.sort_asc")}
|
||
|
|
</DropdownMenuItem>
|
||
|
|
<DropdownMenuItem
|
||
|
|
onClick={() => header.column.toggleSorting(true)}
|
||
|
|
aria-label={t("common.sort_desc")}
|
||
|
|
>
|
||
|
|
<ArrowDownIcon
|
||
|
|
className='mr-2 h-3.5 w-3.5 text-muted-foreground/70'
|
||
|
|
aria-hidden='true'
|
||
|
|
/>
|
||
|
|
{t("common.sort_desc")}
|
||
|
|
</DropdownMenuItem>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{header.column.getCanSort() && header.column.getCanHide() && <DropdownMenuSeparator />}
|
||
|
|
|
||
|
|
{header.column.getCanHide() && (
|
||
|
|
<DropdownMenuItem
|
||
|
|
onClick={() => header.column.toggleVisibility(false)}
|
||
|
|
aria-label={t("Hide")}
|
||
|
|
>
|
||
|
|
<EyeOffIcon
|
||
|
|
className='mr-2 h-3.5 w-3.5 text-muted-foreground/70'
|
||
|
|
aria-hidden='true'
|
||
|
|
/>
|
||
|
|
{t("Hide")}
|
||
|
|
</DropdownMenuItem>
|
||
|
|
)}
|
||
|
|
</DropdownMenuContent>
|
||
|
|
</DropdownMenu>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|