From e732cab837e3b7cbec501cf5858e291cfe6f1de2 Mon Sep 17 00:00:00 2001 From: Carter Date: Fri, 13 Mar 2026 14:57:42 -0600 Subject: [PATCH 1/4] fixed table formatting and added a scroll bar --- src/common/ResponsiveTable.tsx | 93 +++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index ef99665..b229475 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -15,11 +15,10 @@ const useStyles = makeStyles((theme: Theme) => { border: "none" }, tableContainer: { - // margin: theme.spacing(1), - // [theme.breakpoints.up("sm")]: { - // margin: theme.spacing(2) - // }, - // width: "auto" + width: "100%", + maxWidth: "100%", + overflow: "hidden", + minWidth: 0, }, title: { padding: theme.spacing(1), @@ -75,6 +74,53 @@ export interface Column { disableSort?: boolean; } +function ResizableHeaderTitle(props: { + column: Column; + index: number; + columnsLength: number; + resizeable: boolean; + onColumnClick: (column: Column) => void; + showOrderIcon: (column: Column) => React.ReactNode; +}) { + const { column, index, columnsLength, resizeable, onColumnClick, showOrderIcon } = props; + const titleRef = useRef(null); + const [isOverflowing, setIsOverflowing] = useState(false); + + useEffect(() => { + const el = titleRef.current; + if (!el) return; + const checkOverflow = () => setIsOverflowing(el.scrollWidth > el.clientWidth); + checkOverflow(); + const ro = new ResizeObserver(checkOverflow); + ro.observe(el); + return () => ro.disconnect(); + }, []); + + return ( + !column.disableSort && onColumnClick(column)} + sx={{ + cursor: column.disableSort ? "default" : "pointer", + minWidth: 0, + overflow: "hidden", + ...(isOverflowing && resizeable && index < columnsLength - 1 + ? { + maskImage: "linear-gradient(to right, black 75%, transparent 100%)", + WebkitMaskImage: "linear-gradient(to right, black 75%, transparent 100%)", + } + : {}), + }} + > + + {column.title} {showOrderIcon(column)} + + + ); +} + interface Props { rows: T[], columns?: Column[] | (() => Column[]), @@ -483,11 +529,15 @@ export default function ResponsiveTable(props: Props) { if (!dragStart) return let newWidths: number[] = [...rowWidths] - newWidths[index] = newWidths[index] - (dragStart - e.clientX) + const delta = dragStart - e.clientX + const newWidthForIndex = newWidths[index] - delta + const clampedWidth = Math.max(MIN_COLUMN_WIDTH, newWidthForIndex) + const actualDelta = newWidths[index] - clampedWidth + newWidths[index] = clampedWidth newWidths.every((width, j) => { if (j <= index || width === 0) return true else if (newWidths[j] !== undefined) { - newWidths[j] = newWidths[j] + (dragStart - e.clientX) + newWidths[j] = newWidths[j] + actualDelta return false } }) @@ -495,8 +545,11 @@ export default function ResponsiveTable(props: Props) { } + const MIN_COLUMN_WIDTH = 24; + return ( + @@ -552,18 +605,23 @@ export default function ResponsiveTable(props: Props) { ) return ( - - !column.disableSort && columnClick(column)} - sx={{ cursor: column.disableSort ? "default" : "pointer" }} - > - {column.title} {showOrderIcon(column)} - + + {index < columns.length-1 && resizeable && resizeClick(event, index)} > | @@ -672,6 +730,7 @@ export default function ResponsiveTable(props: Props) { }
+
{!hidePagination && Date: Fri, 13 Mar 2026 15:23:07 -0600 Subject: [PATCH 2/4] fixed miscoloring of the data section of the table --- src/common/ResponsiveTable.tsx | 81 ++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index b229475..c5d2c82 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -1,11 +1,11 @@ import { Box, Button, Card, Checkbox, CircularProgress, Collapse, darken, Divider, Grid2, IconButton, InputAdornment, ListItemButton, ListItemIcon, ListItemText, Menu, MenuItem, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material"; +import { alpha } from "@mui/system/colorManipulator"; import { makeStyles } from "@mui/styles"; import { ArrowDownward, ArrowUpward, ChevronRight, Close, Search, ViewColumn } from "@mui/icons-material" import { useEffect, useRef, useState } from "react"; import React from "react"; import { useMobile } from "hooks"; import classNames from "classnames"; -import { getThemeType } from "theme"; const useStyles = makeStyles((theme: Theme) => { //const isMobile = useMobile() @@ -58,10 +58,14 @@ const useStyles = makeStyles((theme: Theme) => { }, stickyHeader: { position: "sticky", - backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(40, 40, 40)", + backgroundColor: theme.palette.background.paper, + // Match Paper's elevation overlay so header matches search bar area + backgroundImage: theme.palette.mode === "dark" + ? `linear-gradient(${alpha("#fff", 0.05)}, ${alpha("#fff", 0.05)})` + : undefined, top: 0, zIndex: 300 //giving a really high z-index to make sure nothing is in front of it - } + }, })}, ); @@ -549,44 +553,45 @@ export default function ResponsiveTable(props: Props) { return ( + {(title || setSearchText) && ( + + + + + {renderTitle()} + {renderSubtitle()} + + + + + + {actions && actions} + + + {endTitleElement} + + + {setSearchText && ( + + {searchBar()} + + )} + + + { columns && !hideKeys && + + + + } + + + + + + )} - - - - - - {renderTitle()} - {renderSubtitle()} - - - - - - {actions && actions} - - - {endTitleElement} - - - {setSearchText && - {searchBar()} - } - - - { columns && !hideKeys && - - - - } - - - - - - - {customElement && From 06d7ff4d4a3c80ebfb014bf639c646e039a460d5 Mon Sep 17 00:00:00 2001 From: Carter Date: Fri, 13 Mar 2026 15:34:43 -0600 Subject: [PATCH 3/4] fixed column resizer being broken --- src/common/ResponsiveTable.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index c5d2c82..4772aff 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -500,14 +500,12 @@ export default function ResponsiveTable(props: Props) { } const resizeClick = (event: React.MouseEvent, index: number) => { - - let newWidths: number[] = [] - event.currentTarget.parentElement?.parentElement?.parentElement?.childNodes.forEach(node => { - if (node instanceof HTMLElement) { - newWidths.push(node.clientWidth) - } - }) - + const row = event.currentTarget.closest("tr") + if (!row) return + const cells = Array.from(row.querySelectorAll("th, td")) + const offset = (rowSelect ? 1 : 0) + (renderGutter ? 1 : 0) + const newWidths = cells.slice(offset).map((cell) => cell.clientWidth) + rowWidthsRef.current = newWidths dragIndexRef.current = index; dragStartRef.current = event.clientX; From 50103d5a0c4f16d54894e6a2958a3de15fc5640f Mon Sep 17 00:00:00 2001 From: Carter Date: Fri, 13 Mar 2026 15:37:36 -0600 Subject: [PATCH 4/4] rendering scroll bar below the table instead of on top of the last row --- src/common/ResponsiveTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index 4772aff..2a4cf1a 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -587,7 +587,7 @@ export default function ResponsiveTable(props: Props) { )} - +
{customElement &&