Skip to content

Commit

Permalink
Colour scheme switcher.
Browse files Browse the repository at this point in the history
  • Loading branch information
akademy committed Jan 8, 2025
1 parent a1840b8 commit 3a75984
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/components/ColourSchemeButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Meta, StoryObj } from "@storybook/react";
import { ColourSchemeButton } from "./ColourSchemeButton";

const meta: Meta<typeof ColourSchemeButton> = {
title: "SciReactUI/Control/ColorSchemeButton",
component: ColourSchemeButton,
tags: ["autodocs"],
parameters: {
docs: {
description: {
component: "Switch between dark and light modes.",
},
},
},
};

export default meta;
type Story = StoryObj<typeof meta>;

export const LightSelected: Story = {
args: {},
};
51 changes: 51 additions & 0 deletions src/components/ColourSchemeButton.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<ColourSchemeButton />);
});

it("should show dark icon and button", () => {
const { getByTestId, getByRole } = render(<ColourSchemeButton />);

const button = getByRole("button");
expect(button).toBeInTheDocument();

const icon = getByTestId("BedtimeIcon");
expect(icon).toBeInTheDocument();
});

it("should change colour scheme on click", () => {
const { getByRole } = render(<ColourSchemeButton />);

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(<ColourSchemeButton onClick={mockOnClick} />);

const button = getByRole("button");
fireEvent.click(button);

expect(mockOnClick).toHaveBeenCalled();
});
});
44 changes: 44 additions & 0 deletions src/components/ColourSchemeButton.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<IconButton
sx={{
height: 35,
width: 35,
borderRadius: "5px",
backgroundColor: theme.palette.primary.light,
color: theme.palette.primary.contrastText,
"&:hover": {
opacity: 0.8,
backgroundImage: "",
backgroundColor: isDark() ? "#111" : "skyblue",
color: "yellow",
},
}}
aria-label={`Colour scheme switcher: ${colourScheme}`}
{...props}
onClick={(event) => {
setColourScheme(isDark() ? ColourSchemes.Light : ColourSchemes.Dark);
if (props.onClick) props.onClick(event);
}}
>
{isDark() ? <Bedtime /> : <LightMode />}
</IconButton>
);
};

export type { IconButtonProps };
export { ColourSchemeButton };
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
4 changes: 4 additions & 0 deletions src/utils/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum ColourSchemes {
Light = "light",
Dark = "dark",
}

0 comments on commit 3a75984

Please sign in to comment.