From bac0228d21b7195065e9cddcc327ae33659c7bcc Mon Sep 17 00:00:00 2001 From: dujinkim Date: Sun, 1 Jun 2025 13:52:21 +0000 Subject: (대표님) 20250601까지 작업사항 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/data-table/infinite-data-table.tsx | 69 +++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 9 deletions(-) (limited to 'components/data-table/infinite-data-table.tsx') diff --git a/components/data-table/infinite-data-table.tsx b/components/data-table/infinite-data-table.tsx index fcac56ee..b8764d62 100644 --- a/components/data-table/infinite-data-table.tsx +++ b/components/data-table/infinite-data-table.tsx @@ -6,7 +6,7 @@ import { ChevronRight, ChevronUp, Loader2 } from "lucide-react" import { useIntersection } from "@mantine/hooks" import { cn } from "@/lib/utils" -import { getCommonPinningStyles } from "@/lib/data-table" +import { getCommonPinningStylesWithBorder } from "@/lib/data-table" import { Table, TableBody, @@ -53,6 +53,9 @@ export function InfiniteDataTable({ useAutoSizeColumns(table, autoSizeColumns) + // 🎯 스크롤 상태 감지 추가 + const [isScrolled, setIsScrolled] = React.useState(false) + // Intersection Observer for infinite scroll const { ref: loadMoreRef, entry } = useIntersection({ threshold: 0.1, @@ -65,21 +68,62 @@ export function InfiniteDataTable({ } }, [entry?.isIntersecting, hasNextPage, isLoadingMore, onLoadMore]) + // 🎯 스크롤 핸들러 추가 + const handleScroll = (e: React.UIEvent) => { + const scrollLeft = e.currentTarget.scrollLeft + setIsScrolled(scrollLeft > 0) + } + + // 🎯 동적 핀 스타일 함수 (width 중복 제거) + const getPinnedStyle = (column: any, isHeader: boolean = false) => { + const baseStyle = getCommonPinningStylesWithBorder({ column }) + const pinnedSide = column.getIsPinned() + + // width를 제외한 나머지 스타일만 반환 + const { width, ...restBaseStyle } = baseStyle + + return { + ...restBaseStyle, + // 헤더는 핀 여부와 관계없이 항상 배경 유지 (sticky로 고정되어 있기 때문) + ...(isHeader && { + background: "hsl(var(--background))", + transition: "none", + }), + // 바디 셀은 핀된 경우에만 스크롤 상태에 따라 동적 변경 + ...(!isHeader && pinnedSide && { + background: isScrolled + ? "hsl(var(--background))" + : "transparent", + transition: "background-color 0.15s ease-out", + }), + } + } + + // 🎯 테이블 총 너비 계산 + const getTableWidth = React.useCallback(() => { + const totalSize = table.getCenterTotalSize() + table.getLeftTotalSize() + table.getRightTotalSize() + return Math.max(totalSize, 800) // 최소 800px 보장 + }, [table]) + // 컴팩트 모드를 위한 클래스 정의 const compactStyles = compact ? { row: "h-7", cell: "py-1 px-2 text-sm", + header: "py-1 px-2 text-sm", // 헤더 스타일 추가 + headerRow: "h-8", // 헤더 행 높이 추가 groupRow: "py-1 bg-muted/20 text-sm", emptyRow: "h-16", } : { row: "", cell: "", + header: "", // 헤더 스타일 추가 + headerRow: "", // 헤더 행 높이 추가 groupRow: "bg-muted/20", emptyRow: "h-24", } return ( -
+
{children} {/* 총 개수 표시 */} @@ -97,12 +141,19 @@ export function InfiniteDataTable({
- +
{/* 테이블 헤더 */} {table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => { if (header.column.getIsGrouped()) { return null @@ -113,10 +164,10 @@ export function InfiniteDataTable({ key={header.id} colSpan={header.colSpan} data-column-id={header.column.id} - className={compact ? "py-1 px-2 text-sm" : ""} + className={compactStyles.header} style={{ - ...getCommonPinningStyles({ column: header.column }), - width: header.getSize(), + ...getPinnedStyle(header.column, true), // 🎯 헤더임을 명시 + width: header.getSize(), // 🎯 width 별도 설정 }} >
@@ -211,8 +262,8 @@ export function InfiniteDataTable({ data-column-id={cell.column.id} className={compactStyles.cell} style={{ - ...getCommonPinningStyles({ column: cell.column }), - width: cell.column.getSize(), + ...getPinnedStyle(cell.column, false), // 🎯 바디 셀임을 명시 + width: cell.column.getSize(), // 🎯 width 별도 설정 }} > {flexRender( -- cgit v1.2.3