summaryrefslogtreecommitdiff
path: root/components/data-table/data-table-pin.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-pin.tsx
3/25 까지의 대표님 작업사항
Diffstat (limited to 'components/data-table/data-table-pin.tsx')
-rw-r--r--components/data-table/data-table-pin.tsx146
1 files changed, 146 insertions, 0 deletions
diff --git a/components/data-table/data-table-pin.tsx b/components/data-table/data-table-pin.tsx
new file mode 100644
index 00000000..991152f6
--- /dev/null
+++ b/components/data-table/data-table-pin.tsx
@@ -0,0 +1,146 @@
+"use client"
+
+import * as React from "react"
+import { type Table } from "@tanstack/react-table"
+import {
+ MoveLeft,
+ MoveRight,
+ Slash,
+ ChevronsUpDown,
+} from "lucide-react"
+
+import { cn, toSentenceCase } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from "@/components/ui/command"
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover"
+
+/**
+ * Button that opens a popover with a list of columns.
+ * Each column can be pinned left, pinned right, or unpinned.
+ */
+export function DataTablePinList<TData>({ table }: { table: Table<TData> }) {
+ const [open, setOpen] = React.useState(false)
+
+ return (
+ <Popover open={open} onOpenChange={setOpen}>
+ <PopoverTrigger asChild>
+ <Button
+ variant="outline"
+ size="sm"
+ className="h-8 gap-2"
+ >
+ Pin
+ <ChevronsUpDown className="size-4 opacity-50" aria-hidden="true" />
+ </Button>
+ </PopoverTrigger>
+ <PopoverContent align="end" className="w-48 p-0">
+ <Command>
+ <CommandInput placeholder="Search columns..." />
+ <CommandList>
+ <CommandEmpty>No columns found.</CommandEmpty>
+ <CommandGroup>
+ {table
+ .getAllLeafColumns()
+ .filter((col) => col.getCanPin?.()) // Only show columns that can be pinned
+ .map((column) => {
+ const pinned = column.getIsPinned?.() // 'left' | 'right' | false
+ return (
+ <PinColumnItem
+ key={column.id}
+ column={column}
+ pinned={pinned}
+ onPinnedChange={(newPin) => {
+ column.pin?.(newPin === "none" ? false : newPin)
+ }}
+ />
+ )
+ })}
+ </CommandGroup>
+ </CommandList>
+ </Command>
+ </PopoverContent>
+ </Popover>
+ )
+}
+
+/**
+ * Renders a single column row (CommandItem) with sub-options:
+ * Left, Right, or Unpin
+ */
+function PinColumnItem({
+ column,
+ pinned,
+ onPinnedChange,
+}: {
+ column: any
+ pinned: "left" | "right" | false
+ onPinnedChange: (newPin: "left" | "right" | "none") => void
+}) {
+ const [subOpen, setSubOpen] = React.useState(false)
+ const colId = column.id
+
+ const handleMainSelect = () => {
+ // Toggle subOpen to show sub-options
+ setSubOpen((prev) => !prev)
+ }
+
+ return (
+ <>
+ <CommandItem onSelect={handleMainSelect}>
+ <span className="truncate">{toSentenceCase(colId)}</span>
+ {pinned === "left" && (
+ <MoveLeft className="ml-auto size-4 text-primary" />
+ )}
+ {pinned === "right" && (
+ <MoveRight className="ml-auto size-4 text-primary" />
+ )}
+ {pinned === false && (
+ <Slash className="ml-auto size-4 opacity-50" />
+ )}
+ </CommandItem>
+
+ {subOpen && (
+ <div className="ml-4 flex flex-col gap-1 border-l pl-2 pt-1">
+ <CommandItem
+ onSelect={() => {
+ onPinnedChange("left")
+ setSubOpen(false)
+ }}
+ >
+ <MoveLeft className="mr-2 size-4" />
+ Pin Left
+ </CommandItem>
+ <CommandItem
+ onSelect={() => {
+ onPinnedChange("right")
+ setSubOpen(false)
+ }}
+ >
+ <MoveRight className="mr-2 size-4" />
+ Pin Right
+ </CommandItem>
+ <CommandItem
+ onSelect={() => {
+ onPinnedChange("none")
+ setSubOpen(false)
+ }}
+ >
+ <Slash className="mr-2 size-4" />
+ No Pin
+ </CommandItem>
+ </div>
+ )}
+ </>
+ )
+} \ No newline at end of file