From a8e00d234b9f5db9daca3efe75cf6a40e6c90361 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Thu, 27 Jun 2024 10:49:33 -0400 Subject: [PATCH] Refactor buttonbar into its own component Refactor the buttonbar and its associated window resize logic into its own component. Closes #465 --- .../src/components/ListViewButtonBar.jsx | 200 ++++++++++++++++++ web/gui-v2/src/components/ListViewTable.jsx | 183 ++-------------- 2 files changed, 212 insertions(+), 171 deletions(-) create mode 100644 web/gui-v2/src/components/ListViewButtonBar.jsx diff --git a/web/gui-v2/src/components/ListViewButtonBar.jsx b/web/gui-v2/src/components/ListViewButtonBar.jsx new file mode 100644 index 0000000..5c1edd0 --- /dev/null +++ b/web/gui-v2/src/components/ListViewButtonBar.jsx @@ -0,0 +1,200 @@ +import React, { useLayoutEffect, useRef, useState } from 'react'; +import { css } from '@emotion/react'; +import { CSVLink } from 'react-csv'; +import { + AddCircleOutline as AddCircleOutlineIcon, + Close as CloseIcon, + Download as DownloadIcon, + Help as HelpIcon, +} from "@mui/icons-material"; +import { Button } from '@mui/material'; + +import { + HelpTooltip, + classes, +} from '@eto/eto-ui-components'; + +import { useWindowSize } from '../util'; + +const styles = { + standardText: css` + font-family: GTZirkonLight; + letter-spacing: 0.00938em; + line-height: 1.5; + text-transform: uppercase; + `, + buttonBar: css` + background-color: var(--bright-blue-lighter); + display: flex; + flex-wrap: wrap; + padding: 0.5rem; + + button { + font-family: GTZirkonLight; + + svg { + margin-right: 5px; + } + } + `, + buttonBarLeft: css` + align-items: center; + color: var(--dark-blue); + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + margin: 6px 8px; + + & > span { + align-items: center; + } + `, + activeFilterTooltip: css` + .MuiTooltip-tooltip { + max-width: 400px; + + li > span { + font-family: GTZirkonLight; + } + } + `, + activeFiltersText: css` + align-items: center; + display: flex; + + svg { + fill: var(--bright-blue); + height: 16px; + } + `, + buttonBarRight: css` + display: flex; + margin-left: auto; + `, + buttonBarButton: css` + min-width: 40px; + `, + +}; + +const BUTTONBAR_PADDING = 16; +const BUTTONBAR_LEFT_MARGIN = 16; +const BUTTON_WIDTH_RESET = 145; +const BUTTON_WIDTH_DOWNLOAD = 182; +const BUTTON_WIDTH_COLUMNS = 202; +const BUTTON_WIDTH_NO_LABEL = 45; +const BUTTONBAR_RIGHT_MIN_WIDTH = 3 * BUTTON_WIDTH_NO_LABEL; + + +const ButtonBar = ({ + activeFilters, + activeFiltersTooltip, + currentFilters, + exportData, + exportHeaders, + numCompanies, + resetFilters, + setDialogOpen, + totalRows, +}) => { + const windowSize = useWindowSize(); + + // Adjust the visibility of the buttonbar labels based on how much space we have + // available based on the viewport width. + // TODO: Refactor the buttonbar into a separate component. + const buttonBarRef = useRef(); + const buttonBarLeftRef = useRef(); + const [buttonBarWidth, setButtonBarWidth] = useState(500); + const [buttonBarLeftWidth, setButtonBarLeftWidth] = useState(200); + const [showLabelReset, setShowLabelReset] = useState(false); + const [showLabelDownload, setShowLabelDownload] = useState(false); + const [showLabelColumns, setShowLabelColumns] = useState(false); + + useLayoutEffect(() => { + const barBounds = buttonBarRef.current.getBoundingClientRect(); + setButtonBarWidth(barBounds.width - BUTTONBAR_PADDING); + const leftBounds = buttonBarLeftRef.current.getBoundingClientRect(); + setButtonBarLeftWidth(leftBounds.width + BUTTONBAR_LEFT_MARGIN); + }, [currentFilters, windowSize]); + + // The label for Download is hidden first, then Columns, and finally Reset is hidden last. + useLayoutEffect(() => { + let spaceForButtons = buttonBarWidth - buttonBarLeftWidth; + // If we don't have enough space on the first row for the the buttons without *any* labels, + // flexbox will wrap us onto the next line, so we have the full buttonbar width to use. + if ( spaceForButtons < BUTTONBAR_RIGHT_MIN_WIDTH ) { + spaceForButtons = buttonBarWidth; + } + + if ( spaceForButtons >= BUTTON_WIDTH_RESET + BUTTON_WIDTH_COLUMNS + BUTTON_WIDTH_DOWNLOAD ) { + setShowLabelReset(true); + setShowLabelDownload(true); + setShowLabelColumns(true); + } else if ( spaceForButtons >= BUTTON_WIDTH_RESET + BUTTON_WIDTH_COLUMNS + BUTTON_WIDTH_NO_LABEL) { + setShowLabelReset(true); + setShowLabelDownload(false); + setShowLabelColumns(true); + } else if ( spaceForButtons >= BUTTON_WIDTH_RESET + 2*BUTTON_WIDTH_NO_LABEL ) { + setShowLabelReset(true); + setShowLabelDownload(false); + setShowLabelColumns(false); + } else { + setShowLabelReset(false); + setShowLabelDownload(false); + setShowLabelColumns(false); + } + }, [buttonBarWidth, buttonBarLeftWidth]); + + + return ( +
+
+ Viewing {numCompanies !== totalRows ? `${numCompanies} of ${totalRows}` : totalRows} companies + {activeFilters.length > 0 && + + + ({activeFilters.length} filters active) + + + + } +
+
+ 0 && activeFiltersTooltip} + > + + + + + + +
+
+ ); +}; + +export default ButtonBar; diff --git a/web/gui-v2/src/components/ListViewTable.jsx b/web/gui-v2/src/components/ListViewTable.jsx index 449c04d..2fb558f 100644 --- a/web/gui-v2/src/components/ListViewTable.jsx +++ b/web/gui-v2/src/components/ListViewTable.jsx @@ -1,28 +1,19 @@ import React, { useEffect, - useLayoutEffect, useMemo, useRef, useState, } from 'react'; -import { CSVLink } from 'react-csv'; import { getQueryParams, useQueryParamString } from 'react-use-query-param-string'; import { css } from '@emotion/react'; -import { - AddCircleOutline as AddCircleOutlineIcon, - Close as CloseIcon, - Download as DownloadIcon, - Help as HelpIcon, -} from "@mui/icons-material"; -import { Button } from '@mui/material'; import { HelpTooltip, Table, - classes, } from '@eto/eto-ui-components'; import AddRemoveColumnDialog from './AddRemoveColumnDialog'; +import ButtonBar from './ListViewButtonBar'; import HeaderDropdown from './HeaderDropdown'; import HeaderSlider from './HeaderSlider'; import overallData from '../static_data/overall_data.json'; @@ -33,73 +24,15 @@ import { commas, debounce, useMultiState, - useWindowSize, } from '../util'; import { plausibleEvent } from '../util/analytics'; import { formatActiveSliderFilter } from '../util/format'; const styles = { - standardText: css` - font-family: GTZirkonLight; - letter-spacing: 0.00938em; - line-height: 1.5; - text-transform: uppercase; - `, - buttonBar: css` - background-color: var(--bright-blue-lighter); - display: flex; - flex-wrap: wrap; - padding: 0.5rem; - - button { - font-family: GTZirkonLight; - - svg { - margin-right: 5px; - } - } - `, - buttonBarLeft: css` - align-items: center; - color: var(--dark-blue); - display: flex; - flex-wrap: wrap; - gap: 0.25rem; - margin: 6px 8px; - - & > span { - align-items: center; - } - `, - activeFilterTooltip: css` - .MuiTooltip-tooltip { - max-width: 400px; - - li > span { - font-family: GTZirkonLight; - } - } - `, activeFiltersList: css` margin: 0; padding-left: 1rem; `, - activeFiltersText: css` - align-items: center; - display: flex; - - svg { - fill: var(--bright-blue); - height: 16px; - } - `, - buttonBarRight: css` - display: flex; - margin-left: auto; - `, - buttonBarButton: css` - min-width: 40px; - `, table: css` td.MuiTableCell-root { padding: 0.5rem; @@ -438,20 +371,11 @@ const AggregateCell = ({ ); } -const BUTTONBAR_PADDING = 16; -const BUTTONBAR_LEFT_MARGIN = 16; -const BUTTON_WIDTH_RESET = 145; -const BUTTON_WIDTH_DOWNLOAD = 182; -const BUTTON_WIDTH_COLUMNS = 202; -const BUTTON_WIDTH_NO_LABEL = 45; -const BUTTONBAR_RIGHT_MIN_WIDTH = 3 * BUTTON_WIDTH_NO_LABEL; - const ListViewTable = ({ data, }) => { const [dialogOpen, setDialogOpen] = useState(false); - const windowSize = useWindowSize(); const isFirstRender = useRef(true); const tableRef = useRef(); @@ -616,53 +540,6 @@ const ListViewTable = ({ ); - // Adjust the visibility of the buttonbar labels based on how much space we have - // available based on the viewport width. - // TODO: Refactor the buttonbar into a separate component. - const buttonBarRef = useRef(); - const buttonBarLeftRef = useRef(); - const [buttonBarWidth, setButtonBarWidth] = useState(500); - const [buttonBarLeftWidth, setButtonBarLeftWidth] = useState(200); - const [showLabelReset, setShowLabelReset] = useState(false); - const [showLabelDownload, setShowLabelDownload] = useState(false); - const [showLabelColumns, setShowLabelColumns] = useState(false); - - useLayoutEffect(() => { - const barBounds = buttonBarRef.current.getBoundingClientRect(); - setButtonBarWidth(barBounds.width - BUTTONBAR_PADDING); - const leftBounds = buttonBarLeftRef.current.getBoundingClientRect(); - setButtonBarLeftWidth(leftBounds.width + BUTTONBAR_LEFT_MARGIN); - }, [currentFilters, windowSize]); - - // The label for Download is hidden first, then Columns, and finally Reset is hidden last. - useLayoutEffect(() => { - let spaceForButtons = buttonBarWidth - buttonBarLeftWidth; - // If we don't have enough space on the first row for the the buttons without *any* labels, - // flexbox will wrap us onto the next line, so we have the full buttonbar width to use. - if ( spaceForButtons < BUTTONBAR_RIGHT_MIN_WIDTH ) { - spaceForButtons = buttonBarWidth; - } - - if ( spaceForButtons >= BUTTON_WIDTH_RESET + BUTTON_WIDTH_COLUMNS + BUTTON_WIDTH_DOWNLOAD ) { - setShowLabelReset(true); - setShowLabelDownload(true); - setShowLabelColumns(true); - } else if ( spaceForButtons >= BUTTON_WIDTH_RESET + BUTTON_WIDTH_COLUMNS + BUTTON_WIDTH_NO_LABEL) { - setShowLabelReset(true); - setShowLabelDownload(false); - setShowLabelColumns(true); - } else if ( spaceForButtons >= BUTTON_WIDTH_RESET + 2*BUTTON_WIDTH_NO_LABEL ) { - setShowLabelReset(true); - setShowLabelDownload(false); - setShowLabelColumns(false); - } else { - setShowLabelReset(false); - setShowLabelDownload(false); - setShowLabelColumns(false); - } - }, [buttonBarWidth, buttonBarLeftWidth]); - - // Prepare the columns that we will display in the ``, including // adding the appropriate filter mechanisms to the header cells. const columnsParamSplit = columnsParam.split(','); @@ -883,53 +760,17 @@ const ListViewTable = ({ return (
-
-
- Viewing {numCompanies !== totalRows ? `${numCompanies} of ${totalRows}` : totalRows} companies - {activeFilters.length > 0 && - - - ({activeFilters.length} filters active) - - - - } -
-
- 0 && activeFiltersTooltip} - > - - - - - - -
-
+