summaryrefslogtreecommitdiff
path: root/components/data-table/data-table-column-header.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-03-26 00:37:41 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-03-26 00:37:41 +0000
commite0dfb55c5457aec489fc084c4567e791b4c65eb1 (patch)
tree68543a65d88f5afb3a0202925804103daa91bc6f /components/data-table/data-table-column-header.tsx
3/25 까지의 대표님 작업사항
Diffstat (limited to 'components/data-table/data-table-column-header.tsx')
-rw-r--r--components/data-table/data-table-column-header.tsx109
1 files changed, 109 insertions, 0 deletions
diff --git a/components/data-table/data-table-column-header.tsx b/components/data-table/data-table-column-header.tsx
new file mode 100644
index 00000000..aa0c754b
--- /dev/null
+++ b/components/data-table/data-table-column-header.tsx
@@ -0,0 +1,109 @@
+"use client"
+
+import { SelectIcon } from "@radix-ui/react-select"
+import { type Column } from "@tanstack/react-table"
+import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+} from "@/components/ui/select"
+
+interface DataTableColumnHeaderProps<TData, TValue>
+ extends React.HTMLAttributes<HTMLDivElement> {
+ column: Column<TData, TValue>
+ title: string
+}
+
+export function DataTableColumnHeader<TData, TValue>({
+ column,
+ title,
+ className,
+}: DataTableColumnHeaderProps<TData, TValue>) {
+ if (!column.getCanSort() && !column.getCanHide()) {
+ return <div className={cn(className)}>{title}</div>
+ }
+
+ const ascValue = `${column.id}-asc`
+ const descValue = `${column.id}-desc`
+ const hideValue = `${column.id}-hide`
+
+ return (
+ <div className={cn("flex items-center gap-2", className)}>
+ <Select
+ value={
+ column.getIsSorted() === "desc"
+ ? descValue
+ : column.getIsSorted() === "asc"
+ ? ascValue
+ : undefined
+ }
+ onValueChange={(value) => {
+ if (value === ascValue) column.toggleSorting(false)
+ else if (value === descValue) column.toggleSorting(true)
+ else if (value === hideValue) column.toggleVisibility(false)
+ }}
+ >
+ <SelectTrigger
+ aria-label={
+ column.getIsSorted() === "desc"
+ ? "Sorted descending. Click to sort ascending."
+ : column.getIsSorted() === "asc"
+ ? "Sorted ascending. Click to sort descending."
+ : "Not sorted. Click to sort ascending."
+ }
+ className="-ml-3 h-8 w-fit border-none text-xs hover:bg-accent hover:text-accent-foreground data-[state=open]:bg-accent [&>svg:last-child]:hidden"
+ >
+ {title}
+ <SelectIcon asChild>
+ {column.getCanSort() && column.getIsSorted() === "desc" ? (
+ <ArrowDown className="ml-2.5 size-4" aria-hidden="true" />
+ ) : column.getIsSorted() === "asc" ? (
+ <ArrowUp className="ml-2.5 size-4" aria-hidden="true" />
+ ) : (
+ <ChevronsUpDown className="ml-2.5 size-4" aria-hidden="true" />
+ )}
+ </SelectIcon>
+ </SelectTrigger>
+ <SelectContent align="start">
+ {column.getCanSort() && (
+ <>
+ <SelectItem value={ascValue}>
+ <span className="flex items-center">
+ <ArrowUp
+ className="mr-2 size-3.5 text-muted-foreground/70"
+ aria-hidden="true"
+ />
+ Asc
+ </span>
+ </SelectItem>
+ <SelectItem value={descValue}>
+ <span className="flex items-center">
+ <ArrowDown
+ className="mr-2 size-3.5 text-muted-foreground/70"
+ aria-hidden="true"
+ />
+ Desc
+ </span>
+ </SelectItem>
+ </>
+ )}
+ {column.getCanHide() && (
+ <SelectItem value={hideValue}>
+ <span className="flex items-center">
+ <EyeOff
+ className="mr-2 size-3.5 text-muted-foreground/70"
+ aria-hidden="true"
+ />
+ Hide
+ </span>
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
+ </div>
+ )
+}