Skip to content

Commit

Permalink
Theme with logos (#16)
Browse files Browse the repository at this point in the history
Add theme specific colorscheme logos
  • Loading branch information
akademy authored Jan 6, 2025
1 parent 4a85b37 commit b99bccc
Show file tree
Hide file tree
Showing 23 changed files with 683 additions and 90 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

# pnpm pack outputs
/diamondlightsource-sci-react-ui-*.tgz
/storybook-static/
1 change: 0 additions & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const config: StorybookConfig = {
"@chromatic-com/storybook",
"@storybook/addon-interactions",
'@storybook/addon-links',
'@storybook/addon-toolbars',
'storybook-dark-mode'
],
framework: {
Expand Down
6 changes: 3 additions & 3 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import {CssBaseline} from "@mui/material";
import type { Preview } from "@storybook/react";

import {ThemeProvider} from '../src'
import {BaseTheme, DiamondTheme} from '../src'
import {GenericTheme, DiamondTheme} from '../src'

import {ThemeSwapper, TextLight, TextDark} from "./ThemeSwapper";

const TextThemeBase = 'Theme: Base'
const TextThemeBase = 'Theme: Generic'
const TextThemeDiamond = 'Theme: Diamond'

export const decorators = [
Expand All @@ -26,7 +26,7 @@ export const decorators = [
const selectedThemeMode = context.globals.themeMode || TextLight;

return <ThemeProvider
theme={(selectedTheme == TextThemeBase) ? BaseTheme : DiamondTheme}
theme={(selectedTheme == TextThemeBase) ? GenericTheme : DiamondTheme}
defaultMode={(selectedThemeMode == TextLight) ? "light" : "dark"}
>
<CssBaseline/>
Expand Down
23 changes: 17 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 19 additions & 19 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,41 @@ First use the ThemeProvider and supply a theme.

```js
import {
ThemeProvider,
ThemeProvider,
DiamondTheme
} from "@diamondlightsource/sci-react-ui";

root.render(
<ThemeProvider theme={DiamondTheme}>
<App />
</ThemeProvider>
<ThemeProvider theme={DiamondTheme}>
<App />
</ThemeProvider>
)
```

There are currently two themes, `BaseTheme` or `DiamondTheme`, but you can adapt your own.
There are currently two themes, `GenericTheme` or `DiamondTheme`, but you can - and should - adapt your own.

There are various components, here's an example of how to use the NavBar:

```js
import {Container, Typography} from "@mui/material";
import {
Navbar,
NavLink,
NavLinks
Navbar,
NavLink,
NavLinks
} from "@diamondlightsource/sci-react-ui";

function App() {
return <>
<Navbar>
<NavLinks key="links">
<NavLink href="#" key="first">A link</NavLink>
</NavLinks>
</Navbar>
<Container>
<Typography variant="h2">Scientific UI Collection</Typography>
<Typography>A collection of science based React components.</Typography>
</Container>
</>
return <>
<Navbar>
<NavLinks key="links">
<NavLink href="#" key="first">A link</NavLink>
</NavLinks>
</Navbar>
<Container>
<Typography variant="h2">Scientific UI Collection</Typography>
<Typography>A collection of science based React components.</Typography>
</Container>
</>
}
export default App;
```
Expand Down
68 changes: 68 additions & 0 deletions src/components/ImageColorSchemeSwitch.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Meta, StoryObj } from "@storybook/react";
import { ImageColorSchemeSwitch } from "./ImageColorSchemeSwitch";

import imageDark from "../public/generic/logo-dark.svg"
import imageLight from "../public/generic/logo-light.svg"

const meta: Meta<typeof ImageColorSchemeSwitch> = {
title: "SciReactUI/Control/ImageColorSchemeSwitch",
component: ImageColorSchemeSwitch,
tags: ["autodocs"],
parameters: {
docs: {
description: {
component: 'Switch between an image depending on the color scheme mode, light or dark versions'
},
},
},
};

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

export const SwitchingImage: Story = {
args: {
image: {
src: imageDark,
srcDark: imageLight,
alt: "Testing Switching Image",
width: "100"
}
},
parameters: {
docs: {
description: {
story: 'This image changes depending on the color scheme mode selected.'
},
},
},
};


export const LargeSwitchingImage: Story = {
args: {
image: {
src: imageDark,
srcDark: imageLight,
alt: "Testing Switching Image",
width: "300"
}
},
};

export const NonSwitchingImage: Story = {
args: {
image: {
src: imageLight,
alt: "Testing Non-Switching Image",
width: "300"
}
},
parameters: {
docs: {
description: {
story: 'This image only has a single src so will NOT switch when the color scheme mode switches.'
},
},
},
};
94 changes: 94 additions & 0 deletions src/components/ImageColorSchemeSwitch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import "@testing-library/jest-dom";
import { render } from "@testing-library/react";

import { ImageColorSchemeSwitch, getLogoSrc } from "./ImageColorSchemeSwitch";

jest.mock("@mui/material", () => {
return {
useColorScheme: jest.fn().mockReturnValue({mode:"dark"})
};
})

describe("ImageColorSchemeSwitch", () => {
const testVals = {
src: "src/light",
alt: "test-alt"
};

function getRenderImg( image: any) {
const {getByAltText} = render(<ImageColorSchemeSwitch image={{...testVals, ...image}}/>);

const img = getByAltText(testVals.alt)
expect(img).toBeInTheDocument()
return img
}

it("should render without errors", () => {
render(<ImageColorSchemeSwitch image={{...testVals}}/>);
});

it("should have src and alt by default", () => {
const img = getRenderImg({})

expect(img).toHaveAttribute("alt", testVals.alt)
expect(img).toHaveAttribute("src", testVals.src)

expect(img).not.toHaveAttribute("width")
expect(img).not.toHaveAttribute("height")
});

it("should have width 123", () => {
const width = "123";

const img = getRenderImg({width})
expect(img).toHaveAttribute("width", width)
expect(img).not.toHaveAttribute("height")
});

it("should have width 123 and height 124", () => {
const width = "123",
height = "124";

const img = getRenderImg({width,height})

expect(img).toHaveAttribute("width", width)
expect(img).toHaveAttribute("height", height)
});

it("should have alternate src", () => {
const srcDark = "src/dark";

const img = getRenderImg({srcDark})

expect(img).toHaveAttribute("src", srcDark)
});
})

describe("getLogoSrc", ()=>{
const srcLight = "src/light",
srcDark = "src/dark";

it("should be null if no image", () => {
// @ts-ignore: invalid input
expect(getLogoSrc(null,"")).toStrictEqual(undefined);
// @ts-ignore: invalid input, calm down ts
expect(getLogoSrc()).toStrictEqual(undefined);
});

it("should be srcLight if no srcDark", () => {
expect(getLogoSrc({src:srcLight, alt:""},"light")).toStrictEqual(srcLight);
});

it("should be srcLight if mode is dark but no srcDark", () => {
expect(getLogoSrc({src:srcLight, alt:""},"dark")).toStrictEqual(srcLight);
});

it("should be srcLight if srcDark but mode light", () => {
expect(getLogoSrc( {src: srcLight, srcDark: srcDark, alt:""},"light")).toStrictEqual(srcLight);
});

it("should be srcDark if mode dark", () => {
expect( getLogoSrc({src:"src/light", srcDark:srcDark, alt:""},"dark")).toStrictEqual(srcDark);
});

})
42 changes: 42 additions & 0 deletions src/components/ImageColorSchemeSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {useColorScheme} from "@mui/material";

type ImageColorSchemeSwitchType = {
src: string,
srcDark?: string,
alt: string
width?: string,
height?: string,
}

interface ImageColorSchemeSwitchProps {
image: ImageColorSchemeSwitchType;
}

export function getLogoSrc(image:ImageColorSchemeSwitchType, mode: string) {
if( !image ) {
return undefined;
}

if( image.srcDark === undefined ) {
return image.src;
}

return mode === "dark" ? image.srcDark : image.src;
}

const ImageColorSchemeSwitch = ({image}: ImageColorSchemeSwitchProps ) => {
const {mode} = useColorScheme();
if( !mode ) return <></>

const src: string | undefined = getLogoSrc(image, mode)

return <img
src={src}
alt={image.alt}
width={image.width}
height={image.height}
/>
}

export {ImageColorSchemeSwitch}
export type {ImageColorSchemeSwitchProps, ImageColorSchemeSwitchType}
Loading

0 comments on commit b99bccc

Please sign in to comment.