From 3a759844d9dc22919f18f0922d3a6c60118da581 Mon Sep 17 00:00:00 2001 From: Matthew Wilcoxson Date: Wed, 18 Dec 2024 17:02:15 +0000 Subject: [PATCH] Colour scheme switcher. --- src/components/ColourSchemeButton.stories.tsx | 22 ++++++++ src/components/ColourSchemeButton.test.tsx | 51 +++++++++++++++++++ src/components/ColourSchemeButton.tsx | 44 ++++++++++++++++ src/index.ts | 3 +- src/utils/globals.ts | 4 ++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/components/ColourSchemeButton.stories.tsx create mode 100644 src/components/ColourSchemeButton.test.tsx create mode 100644 src/components/ColourSchemeButton.tsx create mode 100644 src/utils/globals.ts diff --git a/src/components/ColourSchemeButton.stories.tsx b/src/components/ColourSchemeButton.stories.tsx new file mode 100644 index 0000000..26ca7fd --- /dev/null +++ b/src/components/ColourSchemeButton.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { ColourSchemeButton } from "./ColourSchemeButton"; + +const meta: Meta = { + title: "SciReactUI/Control/ColorSchemeButton", + component: ColourSchemeButton, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: "Switch between dark and light modes.", + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const LightSelected: Story = { + args: {}, +}; diff --git a/src/components/ColourSchemeButton.test.tsx b/src/components/ColourSchemeButton.test.tsx new file mode 100644 index 0000000..da246b1 --- /dev/null +++ b/src/components/ColourSchemeButton.test.tsx @@ -0,0 +1,51 @@ +import "@testing-library/jest-dom"; +import { render, fireEvent } from "@testing-library/react"; + +import { ColourSchemeButton } from "./ColourSchemeButton"; +import { ColourSchemes } from "../utils/globals"; + +const mockSetColorScheme = jest.fn(); +jest.mock("@mui/material", () => { + return { + ...jest.requireActual("@mui/material"), + useColorScheme: jest.fn().mockReturnValue({ + colorScheme: jest.requireActual("../utils/globals").ColourSchemes.Dark, + setColorScheme: (scheme: ColourSchemes) => mockSetColorScheme(scheme), + }), + }; +}); + +describe("ColourSchemeButton", () => { + it("should render without errors", () => { + render(); + }); + + it("should show dark icon and button", () => { + const { getByTestId, getByRole } = render(); + + const button = getByRole("button"); + expect(button).toBeInTheDocument(); + + const icon = getByTestId("BedtimeIcon"); + expect(icon).toBeInTheDocument(); + }); + + it("should change colour scheme on click", () => { + const { getByRole } = render(); + + const button = getByRole("button"); + fireEvent.click(button); + + expect(mockSetColorScheme).toHaveBeenCalledWith(ColourSchemes.Light); + }); + + it("should call local onclick when button clicked", () => { + const mockOnClick = jest.fn(); + const { getByRole } = render(); + + const button = getByRole("button"); + fireEvent.click(button); + + expect(mockOnClick).toHaveBeenCalled(); + }); +}); diff --git a/src/components/ColourSchemeButton.tsx b/src/components/ColourSchemeButton.tsx new file mode 100644 index 0000000..8373ad5 --- /dev/null +++ b/src/components/ColourSchemeButton.tsx @@ -0,0 +1,44 @@ +import { useColorScheme, useTheme } from "@mui/material"; +import { IconButton, IconButtonProps } from "@mui/material"; +import { LightMode, Bedtime } from "@mui/icons-material"; + +import { ColourSchemes } from "../utils/globals"; + +const ColourSchemeButton = (props: IconButtonProps) => { + const theme = useTheme(); + const { colorScheme: colourScheme, setColorScheme: setColourScheme } = + useColorScheme(); + + if (!colourScheme) return undefined; + + const isDark = (): boolean => colourScheme === ColourSchemes.Dark; + + return ( + { + setColourScheme(isDark() ? ColourSchemes.Light : ColourSchemes.Dark); + if (props.onClick) props.onClick(event); + }} + > + {isDark() ? : } + + ); +}; + +export type { IconButtonProps }; +export { ColourSchemeButton }; diff --git a/src/index.ts b/src/index.ts index eee9b6a..0b4b2c6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,8 @@ // components export * from "./components/Breadcrumbs"; -export * from "./components/Navbar"; +export * from "./components/ColourSchemeButton"; export * from "./components/Footer"; +export * from "./components/Navbar"; export * from "./components/User"; export * from "./components/VisitInput"; export * from "./components/ImageColorSchemeSwitch"; diff --git a/src/utils/globals.ts b/src/utils/globals.ts new file mode 100644 index 0000000..5dc4a29 --- /dev/null +++ b/src/utils/globals.ts @@ -0,0 +1,4 @@ +export enum ColourSchemes { + Light = "light", + Dark = "dark", +}