diff --git a/src/components/repositories/LanguageWeightsTable.tsx b/src/components/repositories/LanguageWeightsTable.tsx index 927d7fcf..e953cd5a 100644 --- a/src/components/repositories/LanguageWeightsTable.tsx +++ b/src/components/repositories/LanguageWeightsTable.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo, useRef, useEffect } from 'react'; +import React, { useState, useMemo, useRef } from 'react'; import { Box, TablePagination, @@ -48,7 +48,15 @@ const LanguageWeightsTable: React.FC = () => { const [showChart, setShowChart] = useState(false); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(10); - const containerRef = useRef(null); + const tableWrapperRef = useRef(null); + + // Scroll the table body back to the top when the rows-per-page selection + // changes, so the new page starts at row 0. The scrollable element is the + // tbody (see the sx selectors below) — not the wrapper itself. + const scrollTableToTop = () => { + const body = tableWrapperRef.current?.querySelector('.MuiTableBody-root'); + body?.scrollTo({ top: 0, behavior: 'smooth' }); + }; const handleSort = (field: SortField) => { if (sortField === field) { @@ -69,6 +77,7 @@ const LanguageWeightsTable: React.FC = () => { ) => { setRowsPerPage(parseInt(event.target.value, 10)); setPage(0); + scrollTableToTop(); }; const handleSearchChange = (event: React.ChangeEvent) => { @@ -188,16 +197,6 @@ const LanguageWeightsTable: React.FC = () => { }; }, [paginatedLanguages, theme]); - // Scroll to top when rows per page changes - useEffect(() => { - if (containerRef.current) { - containerRef.current.scrollIntoView({ - behavior: 'smooth', - block: 'start', - }); - } - }, [rowsPerPage]); - const sortLabelHeaderSx = { '& .MuiTableSortLabel-root:hover': { color: 'secondary.main' }, '& .MuiTableSortLabel-root.Mui-active': { color: 'secondary.main' }, @@ -264,7 +263,7 @@ const LanguageWeightsTable: React.FC = () => { ); return ( - + { onChange={(e) => { setRowsPerPage(e.target.value as number); setPage(0); + scrollTableToTop(); }} sx={{ color: theme.palette.text.primary, @@ -407,12 +407,35 @@ const LanguageWeightsTable: React.FC = () => { ({ + // Scroll the tbody (not an outer wrapper) so the thead stays put. + // Same pattern as RepositoryPRsTable. + '& .MuiTable-root': { display: 'block' }, + '& .MuiTableHead-root': { + display: 'block', + // Reserve space matching the body's scrollbar gutter so columns line up. + paddingRight: '8px', + backgroundColor: t.palette.surface.tooltip, + }, + '& .MuiTableHead-root .MuiTableRow-root': { + display: 'table', + tableLayout: 'fixed', + width: '100%', + }, + '& .MuiTableBody-root': { + display: 'block', + maxHeight: '800px', + overflowY: 'auto', + scrollbarGutter: 'stable', + ...scrollbarSx, + }, + '& .MuiTableBody-root .MuiTableRow-root': { + display: 'table', + tableLayout: 'fixed', + width: '100%', + }, + })} > columns={columns} diff --git a/src/pages/OnboardPage.tsx b/src/pages/OnboardPage.tsx index 4a615ec4..0dff0440 100644 --- a/src/pages/OnboardPage.tsx +++ b/src/pages/OnboardPage.tsx @@ -62,7 +62,7 @@ const OnboardPage: React.FC = () => { sx={(theme) => ({ position: 'sticky', top: 0, - zIndex: 2, + zIndex: 10, maxWidth: 1200, width: '100%', mx: 'auto', diff --git a/src/pages/WatchlistPage.tsx b/src/pages/WatchlistPage.tsx index f4540aaf..ac901ef7 100644 --- a/src/pages/WatchlistPage.tsx +++ b/src/pages/WatchlistPage.tsx @@ -175,7 +175,6 @@ const WatchlistPage: React.FC = () => { const discovery = TAB_DISCOVERY[activeTab]; const isLargeScreen = useMediaQuery(theme.breakpoints.up('xl')); - const showSidebarRight = !isEmpty && isLargeScreen; const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md')); const sidebarWidth = @@ -223,9 +222,9 @@ const WatchlistPage: React.FC = () => { { flexDirection: 'column', gap: { xs: 2, sm: 1.5 }, minHeight: 0, - overflow: showSidebarRight ? 'auto' : 'visible', + overflow: isLargeScreen ? 'auto' : 'visible', minWidth: 0, - pr: showSidebarRight ? 1 : 0, + pr: isLargeScreen ? 1 : 0, ...scrollbarSx, }} > + {/* minHeight reserves the Clear button's row height so switching to + an empty tab (where the button is hidden) doesn't shift the Tabs + below upward. */} { fontSize: '0.75rem', textTransform: 'none', color: 'text.secondary', + flexShrink: 0, }} > Clear {noun.plural} @@ -386,9 +390,9 @@ const WatchlistPage: React.FC = () => { {!isEmpty && (