From d60f970e11d18b0553d58e107f8abfb627d09085 Mon Sep 17 00:00:00 2001 From: Arman Jahanpour <77515879+rmanaem@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:45:40 -0500 Subject: [PATCH] [ENH] Made UI responsive for smaller screens (#339) * Implemented a mui theme * Added logo to assets * Replaced logo url with local in navbar * Implemented loading animation for resultcontainer * Set the `textTransform` for buttons to `none` * Updated components' layout * Removed unncessary styles * Modified modalities' bg color * Updated affected test * Removed full screen condition from `AuthDialog` component * Implemented `SmallScreenSizeDialog` component * Updated app layout * Implemented `SmallScreenSizeDialog` component test * Added a test for `SmallScreenSizeDialog` * Renamed `Alert` e2e test to `Feedback` * Addressed comment from PR review --- cypress/component/AuthDialog.cy.tsx | 2 +- cypress/component/ResultCard.cy.tsx | 5 +- .../component/SmallScreenSizeDialog.cy.tsx | 18 ++++ cypress/e2e/{Alert.cy.ts => Feedback.cy.ts} | 9 +- src/App.tsx | 45 +++++++--- src/assets/logo.png | Bin 0 -> 223500 bytes src/components/AuthDialog.tsx | 7 +- src/components/CategoricalField.tsx | 1 - src/components/Navbar.tsx | 7 +- src/components/QueryForm.tsx | 36 ++++---- src/components/ResultCard.tsx | 43 +++++---- src/components/ResultContainer.tsx | 85 +++++++++--------- src/components/SmallScreenSizeDialog.tsx | 33 +++++++ src/main.tsx | 7 +- src/theme.ts | 21 +++++ src/utils/constants.ts | 12 +-- tailwind.config.js | 8 -- 17 files changed, 216 insertions(+), 123 deletions(-) create mode 100644 cypress/component/SmallScreenSizeDialog.cy.tsx rename cypress/e2e/{Alert.cy.ts => Feedback.cy.ts} (86%) create mode 100644 src/assets/logo.png create mode 100644 src/components/SmallScreenSizeDialog.tsx create mode 100644 src/theme.ts diff --git a/cypress/component/AuthDialog.cy.tsx b/cypress/component/AuthDialog.cy.tsx index d501de9a..59bde208 100644 --- a/cypress/component/AuthDialog.cy.tsx +++ b/cypress/component/AuthDialog.cy.tsx @@ -6,7 +6,7 @@ const props = { onClose: () => {}, }; -describe('ContinuousField', () => { +describe('AuthDialog', () => { it('Displays a MUI dialog with the title and "sing in with google" button', () => { cy.mount( diff --git a/cypress/component/ResultCard.cy.tsx b/cypress/component/ResultCard.cy.tsx index c583c4a2..3bb8e563 100644 --- a/cypress/component/ResultCard.cy.tsx +++ b/cypress/component/ResultCard.cy.tsx @@ -41,12 +41,13 @@ describe('ResultCard', () => { cy.get('[data-cy="card-some uuid"]').should('contain', '5 subjects match / 10 total subjects'); cy.get('[data-cy="card-some uuid-checkbox"] input').should('be.checked'); cy.get('[data-cy="card-some uuid"] button') + .eq(1) .should('contain', 'ASL') - .should('have.class', 'bg-zinc-800'); + .should('have.css', 'background-color', 'rgb(113, 113, 122)'); cy.get('[data-cy="card-some uuid"] button') .eq(2) .should('contain', 'DWI') - .should('have.class', 'bg-red-700'); + .should('have.css', 'background-color', 'rgb(205, 92, 92)'); cy.get('[data-cy="card-some uuid-available-pipelines-button"]').trigger('mouseover', { force: true, diff --git a/cypress/component/SmallScreenSizeDialog.cy.tsx b/cypress/component/SmallScreenSizeDialog.cy.tsx new file mode 100644 index 00000000..24869be3 --- /dev/null +++ b/cypress/component/SmallScreenSizeDialog.cy.tsx @@ -0,0 +1,18 @@ +import SmallScreenSizeDialog from '../../src/components/SmallScreenSizeDialog'; + +const props = { + onClose: () => {}, +}; + +describe('SmallScreenSizeDialog', () => { + it('Displays a MUI dialog with the title and "sing in with google" button', () => { + cy.mount(); + cy.get('[data-cy="small-screen-size-dialog"]').should('be.visible'); + cy.get('[data-cy="small-screen-size-dialog"]').should('contain', 'Unsupported Screen Size'); + cy.get('[data-cy="small-screen-size-dialog"]').should( + 'contain', + 'not optimized for use on smaller screens' + ); + cy.get('[data-cy="close-small-screen-size-dialog-button"]').should('be.visible'); + }); +}); diff --git a/cypress/e2e/Alert.cy.ts b/cypress/e2e/Feedback.cy.ts similarity index 86% rename from cypress/e2e/Alert.cy.ts rename to cypress/e2e/Feedback.cy.ts index 9c3ec5e3..2ba028bf 100644 --- a/cypress/e2e/Alert.cy.ts +++ b/cypress/e2e/Feedback.cy.ts @@ -5,7 +5,7 @@ import { nodeOptions, } from '../fixtures/mocked-responses'; -describe('Alert', () => { +describe('Feedback', () => { it('Correctly displays and dismisses the alert', () => { cy.intercept( { @@ -71,4 +71,11 @@ describe('Alert', () => { cy.get('[data-cy="openneuro-alert"]').find('[data-testid="CloseIcon"]').click(); cy.get('[data-cy="openneuro-alert"]').should('not.exist'); }); + it.only('Displays and closes small screen size dialog', () => { + cy.viewport(766, 500); + cy.visit('/'); + cy.get('[data-cy="small-screen-size-dialog"]').should('be.visible'); + cy.get('[data-cy="close-small-screen-size-dialog-button"]').click(); + cy.get('[data-cy="small-screen-size-dialog"]').should('not.exist'); + }); }); diff --git a/src/App.tsx b/src/App.tsx index 1b87d6d5..1a2b98d4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import axios, { AxiosResponse } from 'axios'; import { Alert, Grow, IconButton } from '@mui/material'; +import useMediaQuery from '@mui/material/useMediaQuery'; import CloseIcon from '@mui/icons-material/Close'; import { SnackbarKey, SnackbarProvider, closeSnackbar, enqueueSnackbar } from 'notistack'; import { jwtDecode } from 'jwt-decode'; @@ -24,9 +25,15 @@ import ResultContainer from './components/ResultContainer'; import Navbar from './components/Navbar'; import AuthDialog from './components/AuthDialog'; import ChatbotFeature from './components/Chatbot'; +import SmallScreenSizeDialog from './components/SmallScreenSizeDialog'; import './App.css'; +import logo from './assets/logo.png'; function App() { + // Screen is considered small if the width is less than 768px (according to tailwind docs) + const [isScreenSizeSmall, setIsScreenSizeSmall] = useState( + useMediaQuery('(max-width: 767px)') + ); const [diagnosisOptions, setDiagnosisOptions] = useState([]); const [assessmentOptions, setAssessmentOptions] = useState([]); const [availableNodes, setAvailableNodes] = useState([ @@ -427,15 +434,14 @@ function App() { return ( <> -
- {enableAuth && ( - login(credential)} - onClose={() => setOpenAuthDialog(false)} - /> - )} -
+ {enableAuth && ( + login(credential)} + onClose={() => setOpenAuthDialog(false)} + /> + )} + setIsScreenSizeSmall(false)} /> )} -
{enableChatbot && }
+ {enableChatbot && } -
-
+
+ {/* 380px is currently the smallest width for the query form without dropdowns being affected */} +
submitQuery()} />
-
- +
+ {loading ? ( + Logo + ) : ( + + )}
diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8f691efa8dc89aec96021ca50452bb4f21c547cf GIT binary patch literal 223500 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

~) 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


ILbq^ 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 literal 0 HcmV?d00001 diff --git a/src/components/AuthDialog.tsx b/src/components/AuthDialog.tsx index 66877e10..111c355b 100644 --- a/src/components/AuthDialog.tsx +++ b/src/components/AuthDialog.tsx @@ -3,8 +3,6 @@ import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import DialogActions from '@mui/material/DialogActions'; import Button from '@mui/material/Button'; -import useMediaQuery from '@mui/material/useMediaQuery'; -import { useTheme } from '@mui/material/styles'; import { GoogleLogin } from '@react-oauth/google'; function AuthDialog({ @@ -16,11 +14,8 @@ function AuthDialog({ onAuth: (credential: string | undefined) => void; onClose: () => void; }) { - const theme = useTheme(); - const fullScreen = useMediaQuery(theme.breakpoints.down('md')); - return ( - + You must log in to a trusted identity provider in order to query all available nodes! diff --git a/src/components/CategoricalField.tsx b/src/components/CategoricalField.tsx index c01334a9..a39404bd 100644 --- a/src/components/CategoricalField.tsx +++ b/src/components/CategoricalField.tsx @@ -21,7 +21,6 @@ function CategoricalField({ {...params} label={label} placeholder="Select an option" - className="w-full" /> )} multiple={multiple} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 83246a55..205a5692 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -16,6 +16,7 @@ import Logout from '@mui/icons-material/Logout'; import Login from '@mui/icons-material/Login'; import Avatar from '@mui/material/Avatar'; import { enableAuth } from '../utils/constants'; +import logo from '../assets/logo.png'; function Navbar({ isLoggedIn, @@ -58,11 +59,7 @@ function Navbar({
- Logo + Logo
Neurobagel Query diff --git a/src/components/QueryForm.tsx b/src/components/QueryForm.tsx index ca21f6fd..8c6cfd10 100644 --- a/src/components/QueryForm.tsx +++ b/src/components/QueryForm.tsx @@ -92,8 +92,8 @@ function QueryForm({ minNumImagingSessionsHelperText !== ''; return ( -
-
+
+
({ @@ -105,14 +105,14 @@ function QueryForm({ inputValue={selectedNode} />
-
+
-
+
{minAgeExceedsMaxAge && ( -
+
Value of maximum age must be greater than or equal to value of minimum age
)} -
+
({ @@ -137,9 +137,9 @@ function QueryForm({ inputValue={sex} />
-
-
-
+
+
+
({ @@ -151,7 +151,7 @@ function QueryForm({ disabled={isControl} />
-
+
} @@ -161,21 +161,21 @@ function QueryForm({
-
+
-
+
-
+
({ label: a.Label, id: a.TermURL }))} @@ -183,7 +183,7 @@ function QueryForm({ inputValue={assessmentTool} />
-
+
({ @@ -194,7 +194,7 @@ function QueryForm({ inputValue={imagingModality} />
-
+
({ @@ -211,7 +211,7 @@ function QueryForm({ title={Please select a pipeline name} placement="right" > -
+
) : ( -
+
({ @@ -235,7 +235,7 @@ function QueryForm({
)} -
+
-
+
{imageModals.sort().map((modal) => ( diff --git a/src/components/ResultContainer.tsx b/src/components/ResultContainer.tsx index b94e4f5e..de181496 100644 --- a/src/components/ResultContainer.tsx +++ b/src/components/ResultContainer.tsx @@ -207,24 +207,26 @@ function ResultContainer({ response }: { response: QueryResponse | null }) { return ( <> -
- handleSelectAll(event.target.checked)} - checked={selectAll} - /> - } - /> -
-
- - {summaryStats} - +
+
+ handleSelectAll(event.target.checked)} + checked={selectAll} + /> + } + /> +
+
+ + {summaryStats} + +
-
+
{response.responses.map((item) => ( ))}
-
- - setOpenDialog(false)} /> -
-
- downloadResults(identifier)} - /> - downloadResults(identifier)} - /> +
+
+ + setOpenDialog(false)} /> +
+
+ downloadResults(identifier)} + /> + downloadResults(identifier)} + /> +
); } return ( -
-
- Results -
+
{renderResults()}
); diff --git a/src/components/SmallScreenSizeDialog.tsx b/src/components/SmallScreenSizeDialog.tsx new file mode 100644 index 00000000..d52cf3d4 --- /dev/null +++ b/src/components/SmallScreenSizeDialog.tsx @@ -0,0 +1,33 @@ +import { + Button, + Dialog, + DialogContent, + DialogTitle, + DialogActions, + DialogContentText, +} from '@mui/material'; +import WarningIcon from '@mui/icons-material/Warning'; + +function SmallScreenSizeDialog({ open, onClose }: { open: boolean; onClose: () => void }) { + return ( + + + Unsupported Screen Size! + + + + We're sorry, but the Query Tool is not optimized for use on smaller screens. For the + best experience, please access this tool on a device with a larger screen, such as a + tablet, laptop, or desktop computer. Thank you for your understanding! + + + + + + + ); +} + +export default SmallScreenSizeDialog; diff --git a/src/main.tsx b/src/main.tsx index 27eb04e4..12eccf5a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,11 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; -import { StyledEngineProvider } from '@mui/material/styles'; +import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles'; import { GoogleOAuthProvider } from '@react-oauth/google'; import App from './App'; import { appBasePath, enableAuth, clientID } from './utils/constants'; import './index.css'; +import theme from './theme'; const router = createBrowserRouter([ { @@ -18,7 +19,9 @@ const app = ( {/* CSS injection order for MUI and tailwind: https://mui.com/material-ui/guides/interoperability/#tailwind-css */} - + + + ); diff --git a/src/theme.ts b/src/theme.ts new file mode 100644 index 00000000..7c34b2bf --- /dev/null +++ b/src/theme.ts @@ -0,0 +1,21 @@ +import { createTheme } from '@mui/material'; + +const NBTheme = createTheme({ + palette: { + primary: { + light: '#F5A89B', + main: '#D9748D', + dark: '#A8556F', + contrastText: '#FFFFFF', + }, + }, + components: { + MuiButton: { + defaultProps: { + sx: { textTransform: 'none' }, + }, + }, + }, +}); + +export default NBTheme; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 06be5be5..d641f9ae 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -35,36 +35,36 @@ export const modalities: { label: 'Arterial Spin Labeling', TermURL: 'nidm:ArterialSpinLabeling', name: 'ASL', - bgColor: 'bg-zinc-800', + bgColor: 'rgb(113, 113, 122)', }, 'http://purl.org/nidash/nidm#DiffusionWeighted': { label: 'Diffusion Weighted', TermURL: 'nidm:DiffusionWeighted', name: 'DWI', - bgColor: 'bg-red-700', + bgColor: 'rgb(205, 92, 92)', }, 'http://purl.org/nidash/nidm#EEG': { label: 'Electroencephalogram', TermURL: 'nidm:EEG', name: 'EEG', - bgColor: 'bg-rose-300', + bgColor: 'rgb(253, 164, 164)', }, 'http://purl.org/nidash/nidm#FlowWeighted': { label: 'Flow Weighted', TermURL: 'nidm:FlowWeighted', name: 'Flow', - bgColor: 'bg-sky-700', + bgColor: 'rgb(70, 130, 180)', }, 'http://purl.org/nidash/nidm#T1Weighted': { label: 'T1 Weighted', TermURL: 'nidm:T1Weighted', name: 'T1', - bgColor: 'bg-yellow-500', + bgColor: 'rgb(189, 183, 107)', }, 'http://purl.org/nidash/nidm#T2Weighted': { label: 'T2 Weighted', TermURL: 'nidm:T2Weighted', name: 'T2', - bgColor: 'bg-green-600', + bgColor: 'rgb(143, 188, 143)', }, }; diff --git a/tailwind.config.js b/tailwind.config.js index 07517aba..c652f132 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,14 +1,6 @@ /** @type {import('tailwindcss').Config} */ export default { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], - theme: { - extend: { - gridTemplateRows: { - 9: 'repeat(9, auto)', - 10: 'repeat(10, auto)', - }, - }, - }, plugins: [], corePlugins: { preflight: false,