diff --git a/_examples/gapminder_testing/config.jsonp b/_examples/gapminder_testing/config.jsonp index 01177977..429c168a 100644 --- a/_examples/gapminder_testing/config.jsonp +++ b/_examples/gapminder_testing/config.jsonp @@ -2,4 +2,4 @@ __loadAppConfig__5ae49320({ "name": "Trelliscope App", "datatype": "jsonp", "id": "5ae49320", -}) \ No newline at end of file +}); diff --git a/src/App.tsx b/src/App.tsx index 72ba719e..bf221891 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,8 +3,6 @@ import { useDispatch } from 'react-redux'; import { Box } from '@mui/material'; import { SnackbarProvider } from 'notistack'; import { ThemeProvider, createTheme } from '@mui/material/styles'; -import blue from '@mui/material/colors/blue'; -import lightBlue from '@mui/material/colors/lightBlue'; import { setAppID, setFullscreen, setSinglePageApp, setOptions, setPaths, setAppData } from './slices/appSlice'; import { windowResize, setAppDims } from './slices/uiSlice'; import DataProvider from './components/DataProvider'; @@ -17,6 +15,7 @@ import ErrorWrapper from './components/ErrorWrapper'; import './assets/styles/main.css'; import ErrorSnack from './components/ErrorSnack'; +import { theme } from './palette'; declare global { interface Window { @@ -73,27 +72,6 @@ const App: React.FC = ({ client, config, id, singlePageApp, options, f const dispatch = useDispatch(); const { data: configObj } = useConfig(); - const themeV1 = createTheme({ - palette: { - primary: { - light: configObj?.theme?.light || '#4dabf5', - main: configObj?.theme?.primary || blue.A200, - dark: configObj?.theme?.dark || '#2e60b1', - }, // '#4285f4', // lightBlue500, - // background: { - // default: '#151C24', - // paper: '#151C24', - // }, - secondary: { light: lightBlue[200], main: lightBlue[700] }, - }, - typography: { - fontFamily: '"Poppins", sans-serif', - fontWeightLight: 200, - fontWeightRegular: 300, - fontWeightMedium: 400, - }, - }); - useEffect(() => { dispatch(setAppID(id)); if (typeof config === 'string') { @@ -130,9 +108,17 @@ const App: React.FC = ({ client, config, id, singlePageApp, options, f return ( - + - +
diff --git a/src/assets/styles/main.css b/src/assets/styles/main.css index 8478e482..e2a8ccf7 100644 --- a/src/assets/styles/main.css +++ b/src/assets/styles/main.css @@ -9,10 +9,6 @@ body { overflow: hidden; } -.trelliscope-app-container { - background: white; -} - .trelliscope-app { font-family: 'Poppins', sans-serif; font-weight: 300; @@ -48,11 +44,9 @@ body { .trelliscope-app h5, .trelliscope-app h6 { font-weight: 500; - color: black; } .trelliscope-app strong { - color: black; font-weight: 500; } @@ -68,10 +62,6 @@ body { font-size: 20px; } -.trelliscope-app a { - color: #ff5252; -} - .trelliscope-fullscreen { position: fixed !important; top: 0 !important; diff --git a/src/assets/styles/variables.scss b/src/assets/styles/variables.scss index 58a6c523..e5cccf05 100644 --- a/src/assets/styles/variables.scss +++ b/src/assets/styles/variables.scss @@ -4,56 +4,8 @@ // consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. :root { - // color - --white: #fff; - --white-100: #fdfdfd; - --white-200: #f6f6f6; - --white-300: #eee; - --white-400: #eaedf0; - --white-500: #ebebeb; - --white-600: #e0e0e0; - --black: #000; - --black-100: #000000cc; - --black-200: #000000de; - --black-300: #00000038; - --black-400: #00000066; - --black-500: #0000001e; - --gray: #ddd; - --gray-100: #ccc; - --gray-200: #c1c1c1; - --gray-300: #c0c0c0; - --gray-400: #bbb; - --gray-500: #aaa; - --gray-600: #9ba3af; - --gray-700: #999; - --gray-800: #939393; - --gray-900: #888; - --gray-1000: #848484; - --gray-1100: #777; - --gray-1200: #f6f6f666; - --gray-1300: #666; - --gray-1400: #444; - --red: #ff8e6a; - --red-100: #ff5252; - --red-200: #ff4308; - --blue: #90caf9; - --blue-100: #458af9e6; - --blue-200: #448aff; - --blue-300: #458af966; - --orange: #ffd27f; - --orange-100: #ffc04c; - --orange-200: #ffaa0a; - --green: #81c784; - // border --border: 1px solid; - --border-1: 1px solid var(--white); - --border-2: 1px solid var(--white-400); - --border-3: 1px solid var(--white-600); - --border-4: 1px solid var(--gray); - --border-5: 1px solid var(--gray-100); - --border-6: 1px solid var(--gray-200); - --border-7: 1px solid var(--gray-300); --border-8: 10px; // size @@ -169,10 +121,6 @@ --sideButton-transition: color 0.2s, background-color 0.2s; --sideButtons-spacer-transition: height 0.2s; - // shadow - --sidebarFilter-variable-box-shadow: var(--black-500) 0px 1px 6px, var(--black-500) 0px 1px 4px; - --sidebarSort-variable-box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px; - // padding --sideButtons-container-padding-top: var(--header-container-height); --padding-px: 2px; diff --git a/src/components/AddViewModal/AddViewModal.tsx b/src/components/AddViewModal/AddViewModal.tsx index bbf12fe1..a2008074 100644 --- a/src/components/AddViewModal/AddViewModal.tsx +++ b/src/components/AddViewModal/AddViewModal.tsx @@ -14,6 +14,7 @@ import { } from '@mui/material'; import { useSnackbar } from 'notistack'; import { useSelector } from 'react-redux'; +import { useTheme } from '@mui/material/styles'; import styles from './AddViewModal.module.scss'; import { useGetAllLocalViews, useStoredInputValue } from '../../inputUtils'; import { selectFilterState } from '../../slices/filterSlice'; @@ -46,6 +47,7 @@ const AddViewModal: React.FC = ({ isOpen, handleViewToggle, s const sorts = useSelector(selectSort); const labels = useSelector(selectLabels); const layout = useSelector(selectLayout); + const theme = useTheme(); const { setStoredValue } = useStoredInputValue('trelliscope_views', viewForm?.name); @@ -107,11 +109,39 @@ const AddViewModal: React.FC = ({ isOpen, handleViewToggle, s return (
- + Add a new view - Enter a description and save this view locally. + + Enter a description and save this view locally. + = ({ isOpen, handleViewToggle, s onChange={handleFormChange} /> = ({ metaLevels, metaType, }) => { + const theme = useTheme(); const handleClick = () => { if (label === MISSING_TEXT && metaType === META_TYPE_FACTOR) { return onClick(-Infinity as unknown as string); @@ -35,29 +38,41 @@ const CatHistogramBar: React.FC = ({ return onClick(label); }; + const styleObj = { + ...style, + color: active ? theme.palette.text.primary : theme.palette.primary.contrastText, + '&:hover': { + background: lighten(theme.palette.secondary.light, 0.5), + }, + }; + return ( -
-
+ +
{label === MISSING_TEXT ? MISSING_TEXT : !metaLevels - ? label - : getLabelFromFactor(label as unknown as number, metaLevels)} + ? label + : getLabelFromFactor(label as unknown as number, metaLevels)}
+
+
+ {value}
-
{value}
- {active && ( -
- )} -
+ {active &&
} + ); }; diff --git a/src/components/Chip/Chip.module.scss b/src/components/Chip/Chip.module.scss index 259b769e..c0ef1859 100644 --- a/src/components/Chip/Chip.module.scss +++ b/src/components/Chip/Chip.module.scss @@ -50,25 +50,13 @@ font-style: italic; } - &DragIcon { - margin-right: 15px; - cursor: move; - } - &CloseIcon { display: inline-block; - color: var(--gray); - fill: var(--gray); height: var(--chip-closeIcon-size); width: var(--chip-closeIcon-size); transition: var(--chip-closeIcon-transition); cursor: pointer; margin: var(--margin-1) var(--margin-1) 0 var(--neg-margin-6); -webkit-user-select: none; - - &:hover { - color: var(--black-400); - fill: var(--white); - } } } diff --git a/src/components/Chip/Chip.tsx b/src/components/Chip/Chip.tsx index dafd9c3b..bf805f1f 100644 --- a/src/components/Chip/Chip.tsx +++ b/src/components/Chip/Chip.tsx @@ -12,7 +12,6 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { Box, useTheme } from '@mui/material'; import styles from './Chip.module.scss'; -import { useConfig } from '../../slices/configAPI'; interface ChipProps { label: string; @@ -40,7 +39,6 @@ const Chip: React.FC = ({ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: `${label}_chip` }); const transformString = CSS.Transform.toString(transform) || ''; const matchTranslate = transformString.match(/translate3d\((.*?), (.*?), (.*?)\)/); - const { data: configObj } = useConfig(); const theme = useTheme(); @@ -64,6 +62,7 @@ const Chip: React.FC = ({ {...attributes} > = ({ } }} className={styles.chipLabel} - style={{ - color: configObj?.theme?.isLightTextOnDark ? configObj?.theme?.lightText : configObj?.theme?.darkText || '#fff', - }} > - {icon.includes('alpha-asc') && ( - - )} - {icon.includes('alpha-desc') && ( - - )} - {(icon.includes('numeric-asc') || icon.includes('amount-asc')) && ( - - )} - {(icon.includes('numeric-desc') || icon.includes('amount-desc')) && ( - - )} + {icon.includes('alpha-asc') && } + {icon.includes('alpha-desc') && } + {(icon.includes('numeric-asc') || icon.includes('amount-asc')) && } + {(icon.includes('numeric-desc') || icon.includes('amount-desc')) && } {label} {text !== '' && {`(${text})`}} {isDraggable && ( - - - + + + )} { const dispatch = useDispatch(); const layout = useSelector(selectLayout); + const theme = useTheme(); const handleColumnChange = (value: string) => { let nonZeroValue = value; @@ -22,7 +24,9 @@ const ColumnSelector: React.FC = () => { return (
- Columns: + + Columns: +
{ minWidth: 30, pt: 0, '& .MuiInput-root::before': { - borderColor: 'var(--white-600)', + borderColor: theme.palette.secondary.dark, }, '& .MuiInput-root:hover::before': { - borderColor: 'var(--white-700)', + borderColor: theme.palette.primary.contrastText, }, }} data-testid="column-selector" diff --git a/src/components/ComposeEmail/ComposeEmail.tsx b/src/components/ComposeEmail/ComposeEmail.tsx index a902e068..dba48343 100644 --- a/src/components/ComposeEmail/ComposeEmail.tsx +++ b/src/components/ComposeEmail/ComposeEmail.tsx @@ -3,6 +3,7 @@ import DialogContentText from '@mui/material/DialogContentText'; import Button from '@mui/material/Button'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPaperPlane } from '@fortawesome/free-solid-svg-icons'; +import { useTheme } from '@mui/material/styles'; import styles from './ComposeEmail.module.scss'; interface ComposeEmailProps { @@ -27,10 +28,14 @@ const ComposeEmail: React.FC = ({ displayInfo, fullName, emai mail.href = `mailto:${displayInfo.inputs?.feedbackInterface.feedbackEmail}?subject=${subject}&body=${body}`; mail.click(); }; - + const theme = useTheme(); return (
- + {`By clicking the 'Compose Email' button below, an email will be drafted and opened in your email client to relay this csv file back to us, at ${displayInfo.inputs?.feedbackInterface.feedbackEmail}.`} @@ -43,6 +48,7 @@ const ComposeEmail: React.FC = ({ displayInfo, fullName, emai
- - -
-
-); +const ConfirmationModal: React.FC = ({ isOpen, handleCancel, handleConfirm, dialogText }) => { + const theme = useTheme(); + return ( +
+ + Are you sure? + + {dialogText} + + + + + + +
+ ); +}; export default ConfirmationModal; diff --git a/src/components/Content/Content.module.scss b/src/components/Content/Content.module.scss index ce188b47..fd4c6848 100644 --- a/src/components/Content/Content.module.scss +++ b/src/components/Content/Content.module.scss @@ -15,59 +15,6 @@ } } -.panel { - border: var(--border-2); - min-width: 0; - overflow: hidden; - box-sizing: border-box; - - &Graphic { - display: flex; - padding: var(--padding-2); - box-sizing: border-box; - - img { - max-width: 100%; - min-width: 1px; - width: 100%; - height: 100%; - } - } - - &Labels { - width: 100%; - background: var(--white-200); - list-style-type: none; - margin: 0; - border-collapse: collapse; - } - - &Label { - width: 100%; - font-size: var(--text-xs); - border-bottom: var(--border-2); - - &Cell { - padding: var(--padding-2); - white-space: nowrap; - - &:first-of-type { - white-space: nowrap; - font-weight: bold; - border-right: var(--border-2); - } - } - - &:first-of-type { - border-top: var(--border-2); - } - - &:last-of-type { - border-bottom: none; - } - } -} - .tableContainer { height: 100%; } diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx index 8c59e384..de026b9d 100644 --- a/src/components/Content/Content.tsx +++ b/src/components/Content/Content.tsx @@ -2,6 +2,7 @@ import React, { useContext, useEffect, useRef, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import useResizeObserver from 'use-resize-observer'; import { Box, CircularProgress } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; import { labelsSelector } from '../../selectors'; import { panelLabelSizeSelector } from '../../selectors/ui'; import { useDisplayInfo } from '../../slices/displayInfoAPI'; @@ -26,6 +27,7 @@ interface ContentProps { } const Content: React.FC = ({ table, tableWrapperRef, tableContentRef, handlePanelClick }) => { + const theme = useTheme(); const contentRef = useRef(null); const dispatch = useDispatch(); const { data, filteredData, allData } = useContext(DataContext); @@ -160,7 +162,15 @@ const Content: React.FC = ({ table, tableWrapperRef, tableContentR }; if (metaDataState === META_DATA_STATUS.LOADING || metaDataState === META_DATA_STATUS.IDLE || !allData.length) return ( - + ); @@ -180,12 +190,21 @@ const Content: React.FC = ({ table, tableWrapperRef, tableContentR return ( {!data?.length && ( - + No panels meet the current filter criteria )} {layout?.viewtype === 'grid' ? ( -
+
{metaDataState === META_DATA_STATUS.READY && displayInfoSuccess && data?.length > 0 && curPanel && ( <> @@ -219,7 +238,11 @@ const Content: React.FC = ({ table, tableWrapperRef, tableContentR
) : ( -
+
{data?.length > 0 && }
diff --git a/src/components/ContentContainer/ContentContainer.tsx b/src/components/ContentContainer/ContentContainer.tsx index f9b0118a..56556bd9 100644 --- a/src/components/ContentContainer/ContentContainer.tsx +++ b/src/components/ContentContainer/ContentContainer.tsx @@ -5,8 +5,9 @@ import { useDispatch, useSelector } from 'react-redux'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowUpRightFromSquare, faExpand } from '@fortawesome/free-solid-svg-icons'; import { useMaterialReactTable } from 'material-react-table'; -import { IconButton, Tooltip } from '@mui/material'; +import { Box, IconButton, Tooltip } from '@mui/material'; import useResizeObserver from 'use-resize-observer'; +import { useTheme } from '@mui/material/styles'; import Content from '../Content/Content'; import ContentHeader from '../ContentHeader'; import styles from './ContentContainer.module.scss'; @@ -48,6 +49,7 @@ import { DataContext } from '../DataProvider'; const ContentContainer: React.FC = () => { const layout = useSelector(selectLayout); const { data } = useContext(DataContext); + const theme = useTheme(); const dispatch = useDispatch(); const basePath = useSelector(selectBasePath); @@ -244,9 +246,11 @@ const ContentContainer: React.FC = () => { } if (meta.type === META_TYPE_HREF) { return ( - - - + + + + + ); } return ( @@ -271,12 +275,7 @@ const ContentContainer: React.FC = () => {
{ if (!meta) return; handlePanelClick(meta, cell.row.original[meta.varname] as string, row?.index); @@ -348,7 +347,26 @@ const ContentContainer: React.FC = () => { muiTablePaperProps: { elevation: 0, }, - muiTableContainerProps: { + muiTableBodyCellProps: { + sx: { + svg: { + color: theme.palette.primary.contrastText, + }, + }, + }, + muiTableHeadCellProps: { + sx: { + '.Mui-TableHeadCell-Content svg': { + color: `${theme.palette.primary.contrastText} !important`, + }, + '.MuiDivider-root': { borderColor: theme.palette.primary.contrastText, opacity: 0.3 }, + '[data-testid="PushPinIcon"]': { + fill: `${theme.palette.primary.contrastText} !important`, + }, + }, + }, + + muiTableHeadProps: { style: { overflowX: 'auto', overscrollBehaviorX: 'none', diff --git a/src/components/ContentHeader/ContentHeader.module.scss b/src/components/ContentHeader/ContentHeader.module.scss index f58cb65c..8b6871cd 100644 --- a/src/components/ContentHeader/ContentHeader.module.scss +++ b/src/components/ContentHeader/ContentHeader.module.scss @@ -2,7 +2,6 @@ width: 100%; display: flex; justify-content: space-between; - background-color: var(--white-600); overflow-x: auto; overflow-y: hidden; @@ -25,7 +24,6 @@ padding: 0px 3px 0px 10px; margin: 0 6px; border-radius: 4px; - background: var(--white-500); Button { max-height: 34px; @@ -48,12 +46,10 @@ position: absolute; cursor: pointer; z-index: 1200; - color: #000; top: 62px; width: 18px; height: 18px !important; - background: var(--white-500); - border: 1px solid #cccccc; + border: 1px solid; border-radius: 50%; padding: 4px; transition: left 0.2s ease; @@ -67,25 +63,20 @@ svg { font-size: 20px !important; + position: absolute; + top: 1px; + right: -8px; + z-index: 1001; } &Num { position: absolute; z-index: 1002; - color: var(--white); // top: 1px; // right: 1px; font-size: 12px; font-weight: 500; } - - svg { - color: var(--gray-600); - position: absolute; - top: 1px; - right: -8px; - z-index: 1001; - } } } } diff --git a/src/components/ContentHeader/ContentHeader.tsx b/src/components/ContentHeader/ContentHeader.tsx index 7dfd68eb..7790a299 100644 --- a/src/components/ContentHeader/ContentHeader.tsx +++ b/src/components/ContentHeader/ContentHeader.tsx @@ -1,10 +1,11 @@ import React from 'react'; import classNames from 'classnames'; -import { Button } from '@mui/material'; +import { Button, Box } from '@mui/material'; import { useDispatch, useSelector } from 'react-redux'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronLeft, faCircle, faChevronRight } from '@fortawesome/free-solid-svg-icons'; import { MRT_ShowHideColumnsButton } from 'material-react-table'; +import { useTheme } from '@mui/material/styles'; import { useSelectedDisplay } from '../../slices/selectedDisplaySlice'; import Pagination from '../Pagination'; import ColumnSelector from '../ColumnSelector/ColumnSelector'; @@ -29,29 +30,38 @@ const ContentHeader: React.FC = ({ table }) => { const layout = useSelector(selectLayout); const displayLoaded = selectedDisplay?.name !== ''; const activeFilters = useSelector(selectFilterState); + const theme = useTheme(); const leftPosition = layout?.sidebarActive ? '386px' : '-30px'; return ( dispatch(setLayout({ sidebarActive: !layout.sidebarActive }))} size="sm" className={styles.contentHeaderControlsItemToggleIcon} icon={faChevronLeft} /> -
+
-
+ -
-
+ + -
+ {layout?.viewtype === 'table' && ( -
- Columns + + Columns {/* eslint-disable-next-line react/jsx-pascal-case */} -
+ )} {layout?.viewtype !== 'table' && ( <> -
+ -
-
+ + -
+ )} {data && ( -
+ -
+ )} -
+ -
+
{displayLoaded && }
diff --git a/src/components/Credits/Credits.module.scss b/src/components/Credits/Credits.module.scss index 918bbe7a..cfdadc64 100644 --- a/src/components/Credits/Credits.module.scss +++ b/src/components/Credits/Credits.module.scss @@ -3,4 +3,5 @@ padding-left: var(--padding-7); padding-right: var(--padding-7); z-index: 5000; + margin-top: 15px; } diff --git a/src/components/Credits/Credits.tsx b/src/components/Credits/Credits.tsx index 790a86a5..f5f63f46 100644 --- a/src/components/Credits/Credits.tsx +++ b/src/components/Credits/Credits.tsx @@ -1,53 +1,86 @@ import React from 'react'; +import { Box } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; import styles from './Credits.module.scss'; -const Credits: React.FC = () => ( -
-

- ©  - - Ryan Hafen - - , 2023. -

-

- Built with  - - React - -  and several other awesome libraries listed  - { + const theme = useTheme(); + return ( +

+ - here - - . -

-

- Source code available on  - - github - -  – submit issues and feature requests there. -

-

- Many thanks to the Trelliscope{' '} - + Ryan Hafen + + , 2023. + + - contributors - {' '} - and{' '} - - funders - - . -

-
-); + Built with  + + React + +  and several other awesome libraries listed  + + here + + . + + + Source code available on  + + github + +  – submit issues and feature requests there. + + + Many thanks to the Trelliscope{' '} + + contributors + {' '} + and{' '} + + funders + + . + +
+ ); +}; export default Credits; diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index 4fcf1c93..9ab40a01 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { MaterialReactTable } from 'material-react-table'; - import styles from './DataTable.module.scss'; interface DataTableProps { diff --git a/src/components/DisplayInfo/DisplayInfo.module.scss b/src/components/DisplayInfo/DisplayInfo.module.scss index 3460f880..0ee94be9 100644 --- a/src/components/DisplayInfo/DisplayInfo.module.scss +++ b/src/components/DisplayInfo/DisplayInfo.module.scss @@ -1,29 +1,4 @@ .displayInfo { - &Button { - position: absolute; - left: var(--displayInfo-button-position-left); - box-sizing: border-box; - top: -1px; - display: inline-block; - height: var(--displayInfo-button-size); - width: var(--displayInfo-button-size); - font-size: var(--text-3xl); - padding-top: 0; - color: var(--gray-600); - background: none; - text-align: center; - border-right: var(--border-2); - border-bottom: var(--border-2); - border-top: none; - border-left: none; - - &:hover { - transition: var(--displayInfo-button-hover-transition); - background: var(--white-300); - cursor: pointer; - } - } - &Icon { display: flex; justify-content: center; diff --git a/src/components/DisplayInfo/DisplayInfo.tsx b/src/components/DisplayInfo/DisplayInfo.tsx index 80619526..a5c3e0b5 100644 --- a/src/components/DisplayInfo/DisplayInfo.tsx +++ b/src/components/DisplayInfo/DisplayInfo.tsx @@ -9,13 +9,13 @@ import Dialog from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; import DialogActions from '@mui/material/DialogActions'; import Button from '@mui/material/Button'; +import { useTheme } from '@mui/material/styles'; import { fullscreenSelector } from '../../selectors'; import { useDisplayInfo } from '../../slices/displayInfoAPI'; import { DataContext } from '../DataProvider'; import styles from './DisplayInfo.module.scss'; import { selectBasePath } from '../../selectors/app'; import { snakeCase } from '../../utils'; -import { useConfig } from '../../slices/configAPI'; const DisplayInfo: React.FC = () => { const { allData } = useContext(DataContext); @@ -24,7 +24,7 @@ const DisplayInfo: React.FC = () => { const basePath = useSelector(selectBasePath); const [hasInputs, setHasInputs] = useState(false); const [isOpen, setIsOpen] = useState(false); - const { data: configObj } = useConfig(); + const theme = useTheme(); const handleToggle = () => { setIsOpen(!isOpen); @@ -71,19 +71,13 @@ const DisplayInfo: React.FC = () => { return (
- +
- +
{ maxWidth="lg" fullWidth data-testid="display-info-modal" + PaperProps={{ sx: { backgroundColor: theme.palette.secondary.main } }} > @@ -125,11 +120,11 @@ const DisplayInfo: React.FC = () => { /> ) : (
-
+ {displayInfo?.name}
{displayInfo?.description && {displayInfo?.description}} -
+

{`This visualization contains ${allData?.length} "panels" that you can interactively view through various controls. Each panel has a set of variables or metrics, called "metas", that you can use to sort and filter the panels that you want to view.`}

diff --git a/src/components/DisplaySelect/DisplaySelect.tsx b/src/components/DisplaySelect/DisplaySelect.tsx index d3be14d8..dd723d31 100644 --- a/src/components/DisplaySelect/DisplaySelect.tsx +++ b/src/components/DisplaySelect/DisplaySelect.tsx @@ -4,6 +4,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { Button, Menu, MenuItem } from '@mui/material'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import { useTheme } from '@mui/material/styles'; import { clearFilters, selectFilterState, setFilterView, setFiltersandFilterViews } from '../../slices/filterSlice'; import { selectSort, setSort } from '../../slices/sortSlice'; import { selectLabels, setLabels } from '../../slices/labelsSlice'; @@ -15,7 +16,6 @@ import { useDisplayList } from '../../slices/displayListAPI'; import { useDisplayInfo } from '../../slices/displayInfoAPI'; import { useStoredInputValue, getLocalStorageKey } from '../../inputUtils'; import { filterViewSelector } from '../../selectors'; -import { useConfig } from '../../slices/configAPI'; // import styles from './DisplaySelect.module.scss'; import ErrorWrapper from '../ErrorWrapper'; import { setMetaData, setMetaDataState } from '../../slices/appSlice'; @@ -31,7 +31,7 @@ const DisplaySelect: React.FC = () => { const [isOpen, setIsOpen] = useState(false); const STORED_NAME = 'trelliscope_display_switch_state'; const { setStoredValue } = useStoredInputValue(STORED_NAME, ''); - const { data: configObj } = useConfig(); + const theme = useTheme(); const filterViews = useSelector(filterViewSelector); const filters = useSelector(selectFilterState); @@ -128,13 +128,7 @@ const DisplaySelect: React.FC = () => { {activeStep <= 1 && (
- +
); diff --git a/src/components/FilterNum/FilterNum.tsx b/src/components/FilterNum/FilterNum.tsx index ee6b7d07..4aafb5c1 100644 --- a/src/components/FilterNum/FilterNum.tsx +++ b/src/components/FilterNum/FilterNum.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react'; import type { CSSProperties } from 'react'; import { useDispatch } from 'react-redux'; import { TextField } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; import { FILTER_TYPE_NUMBERRANGE } from '../../constants'; import useMetaInfo from '../../selectors/useMetaInfo'; import { addFilter, removeFilter, updateFilter } from '../../slices/filterSlice'; @@ -23,6 +24,7 @@ const FilterNum: React.FC = ({ meta, filter }) => { const metaObj = metas.find((m) => m.varname === meta.varname); const { log } = metaObj as IMeta; const dispatch = useDispatch(); + const theme = useTheme(); useEffect(() => { if (filter?.min === null) { @@ -75,7 +77,7 @@ const FilterNum: React.FC = ({ meta, filter }) => { if (!data?.length) return null; - const inputStyle = { textAlign: 'center', paddingBottom: 2 } as CSSProperties; + const inputStyle = { textAlign: 'center', paddingBottom: 2, color: theme.palette.text.primary } as CSSProperties; if ( filter?.max !== undefined && @@ -150,6 +152,11 @@ const FilterNum: React.FC = ({ meta, filter }) => { style: inputStyle, step, }} + sx={{ + '& .MuiInput-underline:before': { + borderBottomColor: theme.palette.primary.contrastText, + }, + }} type="number" value={minInput} onChange={(e) => setMinInput(e.target.value)} @@ -169,6 +176,11 @@ const FilterNum: React.FC = ({ meta, filter }) => { style: inputStyle, step, }} + sx={{ + '& .MuiInput-underline:before': { + borderBottomColor: theme.palette.primary.contrastText, + }, + }} type="number" value={maxInput} onChange={(e) => setMaxInput(e.target.value)} diff --git a/src/components/Filters/Filters.module.scss b/src/components/Filters/Filters.module.scss index d1bf06dc..d392d4c3 100644 --- a/src/components/Filters/Filters.module.scss +++ b/src/components/Filters/Filters.module.scss @@ -3,6 +3,5 @@ justify-content: center; position: sticky; top: 0; - background-color: #fff; z-index: 1000; } diff --git a/src/components/Filters/Filters.tsx b/src/components/Filters/Filters.tsx index ab77f99d..7b95611c 100644 --- a/src/components/Filters/Filters.tsx +++ b/src/components/Filters/Filters.tsx @@ -3,6 +3,7 @@ import { faChevronUp, faChevronDown, faRotateLeft, faXmark } from '@fortawesome/ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Box, Button, ButtonGroup, ClickAwayListener, Tooltip } from '@mui/material'; import { useDispatch, useSelector } from 'react-redux'; +import { useTheme } from '@mui/material/styles'; import { useDisplayMetas, useMetaGroups } from '../../slices/displayInfoAPI'; import VariableSelector from '../VariableSelector'; import styles from './Filters.module.scss'; @@ -15,7 +16,6 @@ import { } from '../../slices/filterSlice'; import { selectLayout, setLayout } from '../../slices/layoutSlice'; import ConfirmationModal from '../ConfirmationModal'; -import { useConfig } from '../../slices/configAPI'; import ErrorWrapper from '../ErrorWrapper'; interface FiltersProps { @@ -23,6 +23,7 @@ interface FiltersProps { } const Filters: React.FC = ({ setShowFilterHelpText }) => { + const theme = useTheme(); const dispatch = useDispatch(); const activeStateFilters = useSelector(selectFilterState); const activeFilters = useSelector(selectActiveFilterView); @@ -33,7 +34,6 @@ const Filters: React.FC = ({ setShowFilterHelpText }) => { const [confirmationRemoveModalOpen, setConfirmationRemoveModalOpen] = useState(false); const [confirmationClearModalOpen, setConfirmationClearModalOpen] = useState(false); const [valueToRemove, setValueToRemove] = useState<{ varname: string }[]>([]); - const { data: configObj } = useConfig(); const metaGroups = useMetaGroups(unfilterableMetas); @@ -168,7 +168,10 @@ const Filters: React.FC = ({ setShowFilterHelpText }) => { handleConfirm={handleClear} dialogText="This will clear all of the active filters." /> - + { @@ -179,13 +182,12 @@ const Filters: React.FC = ({ setShowFilterHelpText }) => { diff --git a/src/palette.ts b/src/palette.ts new file mode 100644 index 00000000..0f473198 --- /dev/null +++ b/src/palette.ts @@ -0,0 +1,57 @@ +const theme: ITheme = { + palette: { + primary: { + main: '#4489FF', + // ***Summary***: Buttons and background states throughout the app + // ***Components***: chip background, filter count background, mui buttons / navs, checkboxs, variable selector background and hover state, numhistogram selected bottom color + light: '#4CABF5', + // not currently used + dark: '#2E60B0', + // ***Summary***: Button hover states and background hovers for main styles + // ***Components***: mui buttons / navs hover state, chip hover state + contrastText: '#757575', + // ***Summary***: Text color for buttons and icons + // ***Components***: button text, header text, icon button colors, variable selector sub text and checkbox color, + }, + secondary: { + main: '#FEFEFE', + // ***Summary***: Background color for app + // ***Components***: app background color, modal background color, menu background color, popper background color + light: '#EBEBEB', + // ***Summary***: Background color for components / headers + // ***Components***: cat histogram background color, panel label background color, sub header button background color and item background color, display info header background color, + dark: '#E0E0E0', + // ***SUMMARY***: bar chart color, sub header background color, general outlines, buttons on tables + // ***Components***: histogram not selected bar color, sub header background color, outlines on panels, sort / drag buttons on table header + contrastText: '#FFAE25', + // ***SUMMARY***: bar chart selected color + // ***Components***: histogram selected bar color + }, + background: { + default: '#FEFEFE', + // ***Summary***: table background color / table menu background color + // ***Components***: table background / table column selector background for the paper element + }, + action: { + active: '#757575', + // ***Summary***: primarily used for the table column selector icons + // ***Components***: table column selector icon colors + }, + text: { + primary: '#000', // general text throughout the app, histogram tick text, table text etc. + secondary: '#fff', // button text + disabled: '#BCBCBC', // disabled button text + }, + error: { + main: '#ff5252', // error text, link text + }, + }, + typography: { + fontFamily: '"Poppins", sans-serif', + fontWeightLight: 200, + fontWeightRegular: 300, + fontWeightMedium: 400, + }, +}; + +export { theme }; diff --git a/src/types/configs.d.ts b/src/types/configs.d.ts index f952b594..1cd90792 100644 --- a/src/types/configs.d.ts +++ b/src/types/configs.d.ts @@ -471,17 +471,41 @@ interface IConfig { } interface ITheme { - primary: string; - dark: string; - light: string; - isLightTextOnDark: boolean; - darkText: string; - lightText: string; - logo: string; - header: { - background: string; - text: string; + palette: { + primary: { + main: string; + light: string; + dark: string; + contrastText: string; + }; + secondary: { + main: string; + light: string; + dark: string; + contrastText: string; + }; + text: { + primary: string; + secondary: string; + disabled: string; + }; + background: { + default: string; + }; + action: { + active: string; + }; + error: { + main: string; + }; }; + typography?: { + fontFamily: string; + fontWeightLight: number; + fontWeightRegular: number; + fontWeightMedium: number; + }; + logo?: string; } interface Datum {