diff --git a/client/src/Components/design-elements/StatBox.tsx b/client/src/Components/design-elements/StatBox.tsx index 9cdb9c024..b5e9c7834 100644 --- a/client/src/Components/design-elements/StatBox.tsx +++ b/client/src/Components/design-elements/StatBox.tsx @@ -23,9 +23,11 @@ export const GradientBox = ({ children, palette, sx, interactive }: GradientBox) // gradient collapses flat. Darken slightly towards the page ground instead. const paperStart = isLight ? darken(paper, 0.02) : lighten(paper, 0.08); const paperEnd = paper; - // The gradient carries white `contrastText`, so it runs between two shades - // dark enough to keep that legible. `light` is a mid-tone used for status - // dots and chart marks - too pale here - so lift from `main` instead. + // Both ends stay close to `main` so MUI's derived `contrastText` still + // applies - that is white on the dark light-mode fills and near-black on + // the lighter dark-mode ones, so a bigger lift would break one or other. + // `light` is a mid-tone used for status dots and chart marks, too pale to + // use here, so the lift comes off `main` instead. const bg = palette ? `linear-gradient(135deg, ${lighten(theme.palette[palette].main, 0.12)} 0%, ${theme.palette[palette].main} 100%)` : `linear-gradient(135deg, ${paperStart} 0%, ${paperEnd} 100%)`; diff --git a/client/src/Components/design-elements/Table.tsx b/client/src/Components/design-elements/Table.tsx index 9ef7dcee8..44eab9424 100644 --- a/client/src/Components/design-elements/Table.tsx +++ b/client/src/Components/design-elements/Table.tsx @@ -52,6 +52,8 @@ type DataTableProps = emptyViewText?: string; emptyViewPositive?: boolean; getRowSx?: (row: T) => SxProps; + /** Marks a row selected so it gets the shared selected + hover treatment. */ + isRowSelected?: (row: T) => boolean; }; export function DataTable< @@ -70,6 +72,7 @@ export function DataTable< emptyViewText, emptyViewPositive, getRowSx, + isRowSelected, }: DataTableProps) { const theme = useTheme(); const [expanded, setExpanded] = useState<(string | number) | null>(null); @@ -213,10 +216,21 @@ export function DataTable< "& .MuiTableBody-root .MuiTableRow-root:last-child .MuiTableCell-root": { borderBottom: "none", }, + // Cells paint `background.paper`, so a background set on the row + // never shows. Selection and hover both have to be applied at + // cell level, and selection has to come first so hover layers + // on top of it rather than replacing it. + "& .MuiTableBody-root .MuiTableRow-root.is-selected .MuiTableCell-root": { + backgroundColor: theme.palette.action.selected, + }, "& .MuiTableBody-root .MuiTableRow-root.is-clickable:hover .MuiTableCell-root": { backgroundColor: theme.palette.action.rowHover, }, + "& .MuiTableBody-root .MuiTableRow-root.is-selected.is-clickable:hover .MuiTableCell-root": + { + backgroundColor: theme.palette.action.selectedHover, + }, }} > @@ -241,7 +255,12 @@ export function DataTable< return ( { alignItems: "flex-start", color: theme.palette.text.secondary, "&.Mui-selected": { + // Weight stays put, as on ToggleButton: bolding the active tab + // widens it, shifting every tab to its right and dragging the + // indicator to a moving target. Colour and the indicator are + // already carrying the state. color: theme.palette.primary.main, - fontWeight: 600, }, "&:hover": { color: theme.palette.text.secondary, diff --git a/client/src/Components/inputs/TextInput.tsx b/client/src/Components/inputs/TextInput.tsx index 230e7650b..a246aaf04 100644 --- a/client/src/Components/inputs/TextInput.tsx +++ b/client/src/Components/inputs/TextInput.tsx @@ -39,7 +39,7 @@ export const TextInput = forwardRef(function T }, "& input:-webkit-autofill, & input:-webkit-autofill:hover, & input:-webkit-autofill:focus, & input:-webkit-autofill:active": { - WebkitBoxShadow: `0 0 0 100px ${theme.palette.background.default} inset !important`, + WebkitBoxShadow: `0 0 0 100px ${theme.palette.background.paper} inset !important`, WebkitTextFillColor: `${theme.palette.text.primary} !important`, caretColor: theme.palette.text.primary, transition: "background-color 5000s ease-in-out 0s", diff --git a/client/src/Components/sidebar/index.tsx b/client/src/Components/sidebar/index.tsx index 658054dbd..e9a999ebd 100644 --- a/client/src/Components/sidebar/index.tsx +++ b/client/src/Components/sidebar/index.tsx @@ -73,15 +73,14 @@ export const Sidebar = () => { gap={theme.spacing(LAYOUT.SM)} borderRight={`1px solid ${theme.palette.divider}`} width={width} + // On `paper` rather than inheriting the page ground, so the nav + // reads as a surface and the content area stays the darker + // `default`. Opaque, so the blur it used to carry is gone. + bgcolor={theme.palette.background.paper} sx={{ touchAction: "none", transition: transition, zIndex: 1000, - backdropFilter: "blur(8px)", - // Sits on `paper` rather than inheriting the page ground, so - // the nav reads as a surface and the content area behind it - // stays the slightly darker `default`. - backgroundColor: theme.palette.background.paper, }} > { navigate(`/docker/host/${row.id}`); }} - getRowSx={(row) => ({ - backgroundColor: isRowSelected(row.id) - ? theme.palette.action.selected - : "inherit", - })} + isRowSelected={(row) => isRowSelected(row.id)} /> { navigate(`/infrastructure/${row.id}`); }} - getRowSx={(row) => ({ - backgroundColor: isRowSelected(row.id) - ? theme.palette.action.selected - : "inherit", - })} + isRowSelected={(row) => isRowSelected(row.id)} /> { navigate(`/uptime/${row.id}`); }} - getRowSx={(row) => ({ - backgroundColor: isRowSelected(row.id) - ? theme.palette.action.selected - : "inherit", - })} + isRowSelected={(row) => isRowSelected(row.id)} />