diff --git a/src/components/App/tests/index.test.tsx b/src/components/App/tests/index.test.tsx
index de656201c8..4d427a8f79 100644
--- a/src/components/App/tests/index.test.tsx
+++ b/src/components/App/tests/index.test.tsx
@@ -1,3 +1,4 @@
+import { ThemeProvider } from "@mui/material/styles";
import { render } from "@testing-library/react";
import "jest-canvas-mock";
import { act } from "react";
@@ -7,6 +8,7 @@ import thunk from "redux-thunk";
import App from "components/App";
import { defaultState } from "rootRedux/types";
+import theme from "types/theme";
jest.mock("react-router-dom");
@@ -22,9 +24,11 @@ describe("App", () => {
it("renders without crashing", async () => {
await act(async () => {
render(
-
-
-
+
+
+
+
+
);
});
});
diff --git a/src/components/AppBar/Logo.tsx b/src/components/AppBar/Logo.tsx
index ec5b9769a5..09164addde 100644
--- a/src/components/AppBar/Logo.tsx
+++ b/src/components/AppBar/Logo.tsx
@@ -1,4 +1,4 @@
-import { Button, Hidden } from "@mui/material";
+import { Button, Theme, useMediaQuery } from "@mui/material";
import { ReactElement } from "react";
import { useNavigate } from "react-router-dom";
@@ -10,6 +10,8 @@ import { themeColors } from "types/theme";
/** A button that redirects to the home page */
export default function Logo(): ReactElement {
+ const isSmDown = useMediaQuery((th) => th.breakpoints.down("sm"));
+ const isMdDown = useMediaQuery((th) => th.breakpoints.down("md"));
const navigate = useNavigate();
return (
);
}
diff --git a/src/components/AppBar/NavigationButtons.tsx b/src/components/AppBar/NavigationButtons.tsx
index 39c5765840..56640c49fe 100644
--- a/src/components/AppBar/NavigationButtons.tsx
+++ b/src/components/AppBar/NavigationButtons.tsx
@@ -1,6 +1,12 @@
import { PlaylistAdd, Rule } from "@mui/icons-material";
-import { Button, Hidden, Tooltip, Typography } from "@mui/material";
-import { ReactElement, useEffect, useState } from "react";
+import {
+ Button,
+ type Theme,
+ Tooltip,
+ Typography,
+ useMediaQuery,
+} from "@mui/material";
+import { type ReactElement, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@@ -71,6 +77,7 @@ function NavButton(props: NavButtonProps): ReactElement {
const { t } = useTranslation();
const navigate = useNavigate();
const { windowWidth } = useWindowSize();
+ const showText = useMediaQuery((th) => th.breakpoints.up("sm"));
return (
);
}
diff --git a/src/components/AppBar/ProjectButtons.tsx b/src/components/AppBar/ProjectButtons.tsx
index af9293a686..4507ce2961 100644
--- a/src/components/AppBar/ProjectButtons.tsx
+++ b/src/components/AppBar/ProjectButtons.tsx
@@ -1,5 +1,11 @@
import { BarChart, Settings } from "@mui/icons-material";
-import { Button, Hidden, Tooltip, Typography } from "@mui/material";
+import {
+ Button,
+ Theme,
+ Tooltip,
+ Typography,
+ useMediaQuery,
+} from "@mui/material";
import { ReactElement, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
@@ -42,6 +48,15 @@ export default function ProjectButtons(props: TabProps): ReactElement {
const { t } = useTranslation();
const navigate = useNavigate();
+ const isMdUp = useMediaQuery((th) => th.breakpoints.up("md"));
+ const isLg = useMediaQuery((th) => th.breakpoints.only("lg"));
+ const isXl = useMediaQuery((th) => th.breakpoints.only("xl"));
+ const nameLength = isXl
+ ? projNameLength.xl
+ : isLg
+ ? projNameLength.lg
+ : projNameLength.md;
+
useEffect(() => {
hasPermission(Permission.Statistics).then(setHasStatsPermission);
}, []);
@@ -77,22 +92,14 @@ export default function ProjectButtons(props: TabProps): ReactElement {
}}
>
-
+ {isMdUp && (
-
- {shortenName(projectName, projNameLength.xl)}
-
-
- {shortenName(projectName, projNameLength.lg)}
-
-
- {shortenName(projectName, projNameLength.md)}
-
+ {shortenName(projectName, nameLength)}
-
+ )}
{showSpeaker && }
diff --git a/src/components/AppBar/UserMenu.tsx b/src/components/AppBar/UserMenu.tsx
index 429d5860e0..5cdbdcfd3a 100644
--- a/src/components/AppBar/UserMenu.tsx
+++ b/src/components/AppBar/UserMenu.tsx
@@ -7,15 +7,15 @@ import {
import {
Avatar,
Button,
- Hidden,
Menu,
MenuItem,
+ type Theme,
Typography,
+ useMediaQuery,
} from "@mui/material";
import {
type CSSProperties,
type ForwardedRef,
- Fragment,
type MouseEvent,
type ReactElement,
useState,
@@ -53,6 +53,10 @@ export default function UserMenu(props: TabProps): ReactElement {
const [isAdmin, setIsAdmin] = useState(false);
const username = LocalStorage.getCurrentUser()?.username;
+ const isLgUp = useMediaQuery((th) => th.breakpoints.up("lg"));
+ const isXl = useMediaQuery((th) => th.breakpoints.only("xl"));
+ const nameLength = isXl ? usernameLength.xl : usernameLength.lg;
+
function handleClick(event: MouseEvent): void {
setAnchorElement(event.currentTarget);
}
@@ -78,17 +82,10 @@ export default function UserMenu(props: TabProps): ReactElement {
padding: 0,
}}
>
- {username ? (
-
-
- {shortenName(username, usernameLength.xl)}
-
- {shortenName(username, usernameLength.lg)}
-
-
-
- ) : (
-
+ {!!username && isLgUp && (
+
+ {shortenName(username, nameLength)}
+
)}
{avatar ? (
diff --git a/src/components/AppBar/tests/AppBarComponent.test.tsx b/src/components/AppBar/tests/AppBarComponent.test.tsx
index a3c78dee6e..5d880ca1fe 100644
--- a/src/components/AppBar/tests/AppBarComponent.test.tsx
+++ b/src/components/AppBar/tests/AppBarComponent.test.tsx
@@ -1,3 +1,4 @@
+import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { MemoryRouter } from "react-router-dom";
import { act, create } from "react-test-renderer";
@@ -5,6 +6,7 @@ import configureMockStore from "redux-mock-store";
import AppBar from "components/AppBar/AppBarComponent";
import { defaultState } from "rootRedux/types";
+import theme from "types/theme";
jest.mock("backend", () => ({
isSiteAdmin: () => mockIsSiteAdmin(),
@@ -26,11 +28,13 @@ describe("AppBar", () => {
it("renders", async () => {
await act(async () => {
create(
-
-
-
-
-
+
+
+
+
+
+
+
);
});
});
diff --git a/src/components/AppBar/tests/Logo.test.tsx b/src/components/AppBar/tests/Logo.test.tsx
index ba558672c4..90011be056 100644
--- a/src/components/AppBar/tests/Logo.test.tsx
+++ b/src/components/AppBar/tests/Logo.test.tsx
@@ -1,8 +1,10 @@
import { Button } from "@mui/material";
+import { ThemeProvider } from "@mui/material/styles";
import renderer from "react-test-renderer";
import Logo from "components/AppBar/Logo";
import { Path } from "types/path";
+import theme from "types/theme";
jest.mock("react-router-dom", () => ({
useNavigate:
@@ -17,7 +19,11 @@ let testRenderer: renderer.ReactTestRenderer;
beforeAll(() => {
renderer.act(() => {
- testRenderer = renderer.create();
+ testRenderer = renderer.create(
+
+
+
+ );
});
});
diff --git a/src/components/AppBar/tests/NavigationButtons.test.tsx b/src/components/AppBar/tests/NavigationButtons.test.tsx
index 45d02e0f55..ac0b442af7 100644
--- a/src/components/AppBar/tests/NavigationButtons.test.tsx
+++ b/src/components/AppBar/tests/NavigationButtons.test.tsx
@@ -1,3 +1,4 @@
+import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import renderer, { type ReactTestInstance } from "react-test-renderer";
import configureMockStore from "redux-mock-store";
@@ -8,7 +9,7 @@ import NavigationButtons, {
dataEntryButtonId,
} from "components/AppBar/NavigationButtons";
import { Path } from "types/path";
-import { themeColors } from "types/theme";
+import theme, { themeColors } from "types/theme";
jest.mock("react-router-dom", () => ({
useNavigate: jest.fn(),
@@ -34,9 +35,11 @@ const renderNavButtons = async (
mockGetCurrentPermissions.mockResolvedValue([permission]);
await renderer.act(async () => {
testRenderer = renderer.create(
-
-
-
+
+
+
+
+
);
});
};
diff --git a/src/components/AppBar/tests/ProjectButtons.test.tsx b/src/components/AppBar/tests/ProjectButtons.test.tsx
index b5ea3f7b36..cf66ae5343 100644
--- a/src/components/AppBar/tests/ProjectButtons.test.tsx
+++ b/src/components/AppBar/tests/ProjectButtons.test.tsx
@@ -1,4 +1,5 @@
import { Button } from "@mui/material";
+import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { ReactTestRenderer, act, create } from "react-test-renderer";
import configureMockStore, { MockStoreEnhanced } from "redux-mock-store";
@@ -14,7 +15,7 @@ import { MergeDups } from "goals/MergeDuplicates/MergeDupsTypes";
import { ReviewEntries } from "goals/ReviewEntries/ReviewEntriesTypes";
import { Goal, GoalStatus } from "types/goals";
import { Path } from "types/path";
-import { themeColors } from "types/theme";
+import theme, { themeColors } from "types/theme";
jest.mock("react-router-dom", () => ({
useNavigate: jest.fn(),
@@ -46,9 +47,11 @@ const renderProjectButtons = async (
): Promise => {
await act(async () => {
testRenderer = create(
-
-
-
+
+
+
+
+
);
});
};
diff --git a/src/components/AppBar/tests/UserMenu.test.tsx b/src/components/AppBar/tests/UserMenu.test.tsx
index 853885fd5d..5fc178b73e 100644
--- a/src/components/AppBar/tests/UserMenu.test.tsx
+++ b/src/components/AppBar/tests/UserMenu.test.tsx
@@ -1,10 +1,12 @@
import { Button, MenuItem } from "@mui/material";
+import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { act, create, ReactTestRenderer } from "react-test-renderer";
import configureMockStore from "redux-mock-store";
import UserMenu, { UserMenuList } from "components/AppBar/UserMenu";
import { Path } from "types/path";
+import theme from "types/theme";
jest.mock("backend", () => ({
isSiteAdmin: () => mockIsSiteAdmin(),
@@ -37,9 +39,11 @@ describe("UserMenu", () => {
it("renders", async () => {
await act(async () => {
testRenderer = create(
-
-
-
+
+
+
+
+
);
});
expect(testRenderer.root.findAllByType(Button).length).toEqual(1);
diff --git a/src/components/LandingPage/TopBar.tsx b/src/components/LandingPage/TopBar.tsx
index 9b67e40819..f0ecd1eb84 100644
--- a/src/components/LandingPage/TopBar.tsx
+++ b/src/components/LandingPage/TopBar.tsx
@@ -1,4 +1,11 @@
-import { AppBar, Hidden, Stack, Toolbar, Typography } from "@mui/material";
+import {
+ AppBar,
+ Stack,
+ Theme,
+ Toolbar,
+ Typography,
+ useMediaQuery,
+} from "@mui/material";
import { ReactElement } from "react";
import { useTranslation } from "react-i18next";
@@ -8,6 +15,8 @@ export const topBarHeight = 70;
/** A bar shown at the top of the landing page. */
export default function TopBar(): ReactElement {
+ const showSubtitle = useMediaQuery((th) => th.breakpoints.up("sm"));
+ const isMdUp = useMediaQuery((th) => th.breakpoints.up("md"));
const { t } = useTranslation();
return (
@@ -22,12 +31,11 @@ export default function TopBar(): ReactElement {
style={{ width: "100%" }}
>
-
- {t("landingPage.subtitle")}
-
-
- {t("landingPage.subtitle")}
-
+ {showSubtitle && (
+
+ {t("landingPage.subtitle")}
+
+ )}
diff --git a/src/components/LandingPage/index.tsx b/src/components/LandingPage/index.tsx
index 98c94533f1..f167ff75bf 100644
--- a/src/components/LandingPage/index.tsx
+++ b/src/components/LandingPage/index.tsx
@@ -1,4 +1,11 @@
-import { Box, Grid, Hidden, Stack, Typography } from "@mui/material";
+import {
+ Box,
+ Grid,
+ Stack,
+ Theme,
+ Typography,
+ useMediaQuery,
+} from "@mui/material";
import { ReactElement, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@@ -21,42 +28,31 @@ const heightBetweenBars =
parseInt(theme.spacing(1));
export default function LandingPage(): ReactElement {
+ const isXs = useMediaQuery((th) => th.breakpoints.only("xs"));
const navigate = useNavigate();
+
useEffect(() => {
// If there is an AnnouncementBanner and somebody enters the URL for
// the LandingPage when displaying page without an AppBar, this
// prevents banner misalignment.
navigate(Path.Root);
}, [navigate]);
+
+ const maxBodyHeight =
+ heightBetweenBars - (isXs ? horizontalButtonsHeight : 0);
+
return (
<>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
>
diff --git a/src/components/ProjectScreen/index.tsx b/src/components/ProjectScreen/index.tsx
index cb9e57e928..287aebf0ea 100644
--- a/src/components/ProjectScreen/index.tsx
+++ b/src/components/ProjectScreen/index.tsx
@@ -1,4 +1,4 @@
-import { Hidden, Stack } from "@mui/material";
+import { Stack, Theme, useMediaQuery } from "@mui/material";
import { ReactElement, useEffect } from "react";
import { clearCurrentProject } from "components/Project/ProjectActions";
@@ -10,6 +10,8 @@ import { useAppDispatch } from "rootRedux/hooks";
/** Where users create a project or choose an existing one */
export default function ProjectScreen(): ReactElement {
const dispatch = useAppDispatch();
+ const isXs = useMediaQuery((th) => th.breakpoints.only("xs"));
+
/* Disable Data Entry, Data Cleanup, Project Settings until a project is selected or created. */
useEffect(() => {
dispatch(clearCurrentProject());
@@ -17,19 +19,14 @@ export default function ProjectScreen(): ReactElement {
}, [dispatch]);
return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- >
+
+
+
+
);
}
diff --git a/src/components/ProjectScreen/tests/index.test.tsx b/src/components/ProjectScreen/tests/index.test.tsx
index 6fe5ffbd22..4df46944d6 100644
--- a/src/components/ProjectScreen/tests/index.test.tsx
+++ b/src/components/ProjectScreen/tests/index.test.tsx
@@ -1,6 +1,8 @@
+import { ThemeProvider } from "@mui/material/styles";
import renderer from "react-test-renderer";
import ProjectScreen from "components/ProjectScreen";
+import theme from "types/theme";
jest.mock("components/ProjectScreen/ChooseProject", () => "div");
jest.mock("components/ProjectScreen/CreateProject", () => "div");
@@ -12,7 +14,11 @@ const mockDispatch = jest.fn();
it("renders without crashing", () => {
renderer.act(() => {
- renderer.create();
+ renderer.create(
+
+
+
+ );
});
expect(mockDispatch).toHaveBeenCalledTimes(2);
});
diff --git a/src/components/ProjectSettings/index.tsx b/src/components/ProjectSettings/index.tsx
index fe8cc7d3c2..c21fa820fe 100644
--- a/src/components/ProjectSettings/index.tsx
+++ b/src/components/ProjectSettings/index.tsx
@@ -16,12 +16,13 @@ import {
import {
Box,
Divider,
- Hidden,
Stack,
Tab,
Tabs,
+ type Theme,
Tooltip,
Typography,
+ useMediaQuery,
} from "@mui/material";
import {
type ReactElement,
@@ -90,6 +91,7 @@ export default function ProjectSettingsComponent(): ReactElement {
const project = useAppSelector(
(state: StoreState) => state.currentProjectState.project
);
+ const hideLabels = useMediaQuery((th) => th.breakpoints.down("md"));
const navigate = useNavigate();
const { t } = useTranslation();
@@ -139,23 +141,13 @@ export default function ProjectSettingsComponent(): ReactElement {
-
-
-
-
-
-
+
diff --git a/src/components/ProjectSettings/tests/index.test.tsx b/src/components/ProjectSettings/tests/index.test.tsx
index 31138ed374..ef1ee8e3a4 100644
--- a/src/components/ProjectSettings/tests/index.test.tsx
+++ b/src/components/ProjectSettings/tests/index.test.tsx
@@ -1,3 +1,4 @@
+import { ThemeProvider } from "@mui/material/styles";
import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import "@testing-library/jest-dom";
@@ -20,6 +21,7 @@ import {
whichTabs,
} from "components/ProjectSettings/tests/SettingsTabTypes";
import { randomProject } from "types/project";
+import theme from "types/theme";
jest.mock("react-router-dom", () => ({
useNavigate: jest.fn(),
@@ -62,9 +64,11 @@ const updateProjSettings = async (hasSchedule = false): Promise => {
// This is accomplished by randomProject() in createMockStore().
render(
-
-
-
+
+
+
+
+
);
});
@@ -88,16 +92,18 @@ const createMatchMedia = (
};
beforeAll(async () => {
- // Required for the elements to show up
+ // Required (along with a `ThemeProvider`) for `useMediaQuery` to work
window.matchMedia = createMatchMedia(window.innerWidth);
resetMocks();
await act(async () => {
render(
-
-
-
+
+
+
+
+
);
});
diff --git a/src/components/TreeView/TreeDepiction/index.tsx b/src/components/TreeView/TreeDepiction/index.tsx
index 74a4dafce3..60518b94dd 100644
--- a/src/components/TreeView/TreeDepiction/index.tsx
+++ b/src/components/TreeView/TreeDepiction/index.tsx
@@ -1,4 +1,4 @@
-import { Grid, Hidden } from "@mui/material";
+import { Grid, Theme, useMediaQuery } from "@mui/material";
import { ReactElement, useEffect, useState } from "react";
import ChildrenRow from "components/TreeView/TreeDepiction/ChildrenRow";
@@ -13,6 +13,8 @@ import { parent } from "resources/tree";
import { useWindowSize } from "utilities/useWindowSize";
export default function TreeDepiction(props: TreeDepictionProps): ReactElement {
+ const showTree = useMediaQuery((th) => th.breakpoints.up("sm"));
+
const [colWidth, setColWidth] = useState(0);
const { windowWidth } = useWindowSize();
@@ -25,45 +27,36 @@ export default function TreeDepiction(props: TreeDepictionProps): ReactElement {
return (
<>
{/* Display parent domain, if available. */}
-
- {currentDomain.parent && (
- <>
-
-
-
-
-
-
- >
- )}
-
+ {showTree && currentDomain.parent && (
+ <>
+
+
+
+
+
+
+ >
+ )}
{/* Display current domain and (if available) left and right brothers. */}
-
-
-
-
-
-
+
{/* Display subdomains, if available. */}
-
-
- {currentDomain.children.length > 0 && (
-
- )}
-
-
+
+ {showTree && currentDomain.children.length > 0 && (
+
+ )}
+
>
);
}
diff --git a/src/components/TreeView/TreeDepiction/tests/__snapshots__/index.test.tsx.snap b/src/components/TreeView/TreeDepiction/tests/__snapshots__/index.test.tsx.snap
index 224caf1d8e..65f7bdfe9e 100644
--- a/src/components/TreeView/TreeDepiction/tests/__snapshots__/index.test.tsx.snap
+++ b/src/components/TreeView/TreeDepiction/tests/__snapshots__/index.test.tsx.snap
@@ -6,7 +6,7 @@ Array [
className="MuiGrid-root MuiGrid-item css-13i4rnv-MuiGrid-root"
>