From 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 25 Mar 2025 15:55:45 +0900
Subject: initial commit

---
 components/data-table/data-table-column-header.tsx | 109 +++++++++++++++++++++
 1 file changed, 109 insertions(+)
 create mode 100644 components/data-table/data-table-column-header.tsx

(limited to 'components/data-table/data-table-column-header.tsx')

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>
+  )
+}
-- 
cgit v1.2.3

