diff --git a/src/renderer/components/item-list/item-table-list/item-table-list.module.css b/src/renderer/components/item-list/item-table-list/item-table-list.module.css index 8986b94ce..6341f49a6 100644 --- a/src/renderer/components/item-list/item-table-list/item-table-list.module.css +++ b/src/renderer/components/item-list/item-table-list/item-table-list.module.css @@ -27,6 +27,7 @@ } .item-table-pinned-rows-container { + position: relative; display: flex; flex: 1 1 auto; flex-direction: column; @@ -41,10 +42,21 @@ } .item-table-pinned-rows-grid-container.with-header { - border-bottom: 1px solid var(--theme-colors-border); + position: relative; +} + +.item-table-pinned-rows-grid-container.with-header::after { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 1px; + content: ''; + background-color: var(--theme-colors-border); } .item-table-pinned-columns-grid-container { + position: relative; display: flex; flex: 0 1 auto; flex-direction: column; @@ -58,7 +70,17 @@ } .item-table-pinned-intersection-grid-container.with-header { - border-bottom: 1px solid var(--theme-colors-border); + position: relative; +} + +.item-table-pinned-intersection-grid-container.with-header::after { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 1px; + content: ''; + background-color: var(--theme-colors-border); } .item-table-pinned-columns-container { @@ -130,3 +152,19 @@ transparent 100% ); } + +.item-table-top-scroll-shadow { + position: absolute; + top: var(--header-height, 40px); + right: 0; + left: 0; + z-index: 1; + height: 8px; + pointer-events: none; + background: linear-gradient( + to bottom, + rgb(0 0 0 / 50%) 0%, + rgb(0 0 0 / 5%) 50%, + transparent 100% + ); +} diff --git a/src/renderer/components/item-list/item-table-list/item-table-list.tsx b/src/renderer/components/item-list/item-table-list/item-table-list.tsx index dbf9d009b..75f8edc3c 100644 --- a/src/renderer/components/item-list/item-table-list/item-table-list.tsx +++ b/src/renderer/components/item-list/item-table-list/item-table-list.tsx @@ -115,6 +115,7 @@ interface VirtualizedTableGridProps { playerContext: PlayerContext; showLeftShadow: boolean; showRightShadow: boolean; + showTopShadow: boolean; size: 'compact' | 'default' | 'large'; tableId: string; totalColumnCount: number; @@ -154,6 +155,7 @@ const VirtualizedTableGrid = React.memo( playerContext, showLeftShadow, showRightShadow, + showTopShadow, size, tableId, totalColumnCount, @@ -293,12 +295,15 @@ const VirtualizedTableGrid = React.memo(
0).reduce( - (a, _, i) => a + columnWidth(i), - 0, - )}px`, - }} + style={ + { + '--header-height': `${headerHeight}px`, + minWidth: `${Array.from( + { length: pinnedLeftColumnCount }, + () => 0, + ).reduce((a, _, i) => a + columnWidth(i), 0)}px`, + } as React.CSSProperties + } > {!!(pinnedLeftColumnCount || pinnedRowCount) && (
- {enableHeader &&
}
)} + {enableHeader && showTopShadow && ( +
+ )} {!!pinnedLeftColumnCount && (
)}
-
+
{!!pinnedRowCount && (
0).length} rowHeight={getRowHeight} /> - {enableHeader &&
}
)} + {enableHeader && showTopShadow && ( +
+ )}
0, - ).reduce( - (a, _, i) => - a + columnWidth(i + pinnedLeftColumnCount + totalColumnCount), - 0, - )}px`, - }} + style={ + { + '--header-height': `${headerHeight}px`, + minWidth: `${Array.from( + { length: pinnedRightColumnCount }, + () => 0, + ).reduce( + (a, _, i) => + a + + columnWidth(i + pinnedLeftColumnCount + totalColumnCount), + 0, + )}px`, + } as React.CSSProperties + } > {!!(pinnedRightColumnCount || pinnedRowCount) && (
- {enableHeader && ( -
- )}
)} + {enableHeader && showTopShadow && ( +
+ )}
void; onColumnResized?: (columnId: TableColumn, width: number) => void; onRangeChanged?: (range: { startIndex: number; stopIndex: number }) => void; @@ -659,6 +679,7 @@ export const ItemTableList = ({ const mergedRowRef = useMergedRef(rowRef, scrollContainerRef); const [showLeftShadow, setShowLeftShadow] = useState(false); const [showRightShadow, setShowRightShadow] = useState(false); + const [showTopShadow, setShowTopShadow] = useState(false); const handleRef = useRef(null); const containerFocusRef = useRef(null); @@ -1181,6 +1202,29 @@ export const ItemTableList = ({ }; }, [pinnedLeftColumnCount, pinnedRightColumnCount]); + // Handle top shadow visibility based on vertical scroll + useEffect(() => { + const row = rowRef.current?.childNodes[0] as HTMLDivElement; + + if (!row || !enableHeader) { + setShowTopShadow(false); + return; + } + + const checkScrollPosition = () => { + const scrollTop = row.scrollTop; + setShowTopShadow(scrollTop > 0); + }; + + checkScrollPosition(); + + row.addEventListener('scroll', checkScrollPosition); + + return () => { + row.removeEventListener('scroll', checkScrollPosition); + }; + }, [enableHeader]); + const getRowHeight = useCallback( (index: number, cellProps: TableItemProps) => { const height = size === 'compact' ? 40 : size === 'large' ? 88 : 64; @@ -1427,6 +1471,7 @@ export const ItemTableList = ({ playerContext={playerContext} showLeftShadow={showLeftShadow} showRightShadow={showRightShadow} + showTopShadow={showTopShadow} size={size} tableId={tableId} totalColumnCount={totalColumnCount}