From 35d9595ea26846f2db5638568813f8559f25dd7d Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 7 Apr 2025 13:11:22 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20data=20table=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20ui=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/common/components/package.json | 1 + .../components/src/ui/data-table/index.tsx | 155 ++++++++++++++---- pnpm-lock.yaml | 11 ++ 3 files changed, 136 insertions(+), 31 deletions(-) diff --git a/packages/common/components/package.json b/packages/common/components/package.json index d9ba2a55e..8b9b12eed 100644 --- a/packages/common/components/package.json +++ b/packages/common/components/package.json @@ -33,6 +33,7 @@ "@radix-ui/react-collapsible": "^1.1.3", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-popover": "^1.1.6", "@radix-ui/react-progress": "^1.1.2", diff --git a/packages/common/components/src/ui/data-table/index.tsx b/packages/common/components/src/ui/data-table/index.tsx index 7e3af5602..ac82afde9 100644 --- a/packages/common/components/src/ui/data-table/index.tsx +++ b/packages/common/components/src/ui/data-table/index.tsx @@ -1,10 +1,18 @@ import { flexRender, type RowData, - type Table as TableType, + type Table as TableInstance, } from "@tanstack/react-table"; +import { + ChevronLeftIcon, + ChevronRightIcon, + DoubleArrowLeftIcon, + DoubleArrowRightIcon, +} from "@radix-ui/react-icons"; import { cn } from "../../lib"; +import { Button } from "../button"; import { Table, TableCell, TableHead, TableHeader, TableRow } from "../table"; +import type { HTMLAttributes } from "react"; declare module "@tanstack/react-table" { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -13,7 +21,50 @@ declare module "@tanstack/react-table" { } } -function THead({ table }: { table: TableType }) { +type DataTableProps = { + table: TableInstance; + variant?: "default" | "secondary" | "line"; + className?: HTMLAttributes["className"]; + viewPagination?: boolean; + onRowClick?: (row: T) => void; +}; + +function DataTable({ + table, + variant = "default", + className, + viewPagination, + onRowClick, +}: DataTableProps) { + return ( + <> + + + + {table.getRowModel().rows.map((row) => ( + onRowClick?.(row.original)} + className={cn(onRowClick && "cursor-pointer hover:bg-accent")} + > + {row.getVisibleCells().map((cell) => { + const { meta } = cell.column.columnDef; + return ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ); + })} + + ))} + +
+ {viewPagination && } + + ); +} + +function THead({ table }: { table: TableInstance }) { return ( {table.getHeaderGroups().map((headerGroup) => ( @@ -37,39 +88,81 @@ function THead({ table }: { table: TableType }) { ); } -type TableProps = { - table: TableType; - variant?: "default" | "secondary" | "line"; - onRowClick?: (row: T) => void; -}; +function Pagination({ table }: { table: TableInstance }) { + const pageCount = table.getPageCount(); + const currentPage = table.getState().pagination.pageIndex; + const maxVisiblePages = 10; // 한 번에 보여줄 최대 페이지 수 + + let startPage = Math.max(0, currentPage - maxVisiblePages / 2); // 시작 페이지 + const endPage = Math.min(pageCount, startPage + maxVisiblePages); // 끝 페이지 + + if (endPage - startPage < maxVisiblePages) { + startPage = Math.max(0, endPage - maxVisiblePages); + } + + const pageNumbers = Array(endPage - startPage) + .fill(0) + .map((_, i) => startPage + i); -function DataTable({ - table, - variant = "default", - onRowClick, -}: TableProps) { return ( - - - - {table.getRowModel().rows.map((row) => ( - onRowClick?.(row.original)} - className={cn(onRowClick && "cursor-pointer hover:bg-accent")} +
+ + +
+ {pageNumbers.map((pageNumber) => ( + ))} -
-
+ + + + ); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a56b25dd8..beb0c1aea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -384,6 +384,9 @@ importers: '@radix-ui/react-dropdown-menu': specifier: ^2.1.6 version: 2.1.6(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-icons': + specifier: ^1.3.2 + version: 1.3.2(react@18.3.1) '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1) @@ -2102,6 +2105,14 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-icons@1.3.2(react@18.3.1): + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^18.3.1 + dependencies: + react: 18.3.1 + dev: false + /@radix-ui/react-id@1.1.0(@types/react@18.3.18)(react@18.3.1): resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: