diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts index 6762bfb8a7..d6ff1f75f8 100644 --- a/frontend/.storybook/main.ts +++ b/frontend/.storybook/main.ts @@ -45,6 +45,7 @@ const config: StorybookConfig = { "@storybook/addon-essentials", "@storybook/addon-links", "@storybook/addon-a11y", + "@storybook/addon-themes" ], }; diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index 6e534887d7..f97832a553 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -1,25 +1,48 @@ -import React from "react"; -import { Theme } from "./../packages/core/src/AppProvider/themes"; +import { DecoratorHelpers } from "@storybook/addon-themes"; +import { withClutchTheme } from "./withClutchTheme.decorator"; +import { Global, css } from "@emotion/react"; +import { clutchColors } from "../packages/core/src/Theme/colors"; + +const { pluckThemeFromContext } = DecoratorHelpers; + +const withGlobalStyles = (Story, context) => { + const selectedTheme = pluckThemeFromContext(context); + const GlobalStyles = css` + body { + background: ${clutchColors(selectedTheme).neutral["50"]}; + } + `; + + return ( + <> + + + + ); +}; export const decorators = [ - (Story) => ( - - - - ), + withClutchTheme({ + themes: { + light: "light", + dark: "dark", + }, + defaultTheme: "light", + }), + withGlobalStyles, ]; export const parameters = { backgrounds: { - default: "clutch", + default: "light", values: [ { - name: "clutch", - value: "#f9fafe", + name: "light", + value: clutchColors("light").neutral["50"], }, { - name: "light", - value: "#ffffff", + name: "dark", + value: clutchColors("dark").neutral["50"], }, ], }, diff --git a/frontend/.storybook/withClutchTheme.decorator.js b/frontend/.storybook/withClutchTheme.decorator.js new file mode 100644 index 0000000000..e30b6f8137 --- /dev/null +++ b/frontend/.storybook/withClutchTheme.decorator.js @@ -0,0 +1,25 @@ +import { DecoratorHelpers } from "@storybook/addon-themes"; +import { ThemeProvider } from "../packages/core/src/Theme"; + +const { + initializeThemeState, + pluckThemeFromContext, + useThemeParameters, +} = DecoratorHelpers; + +export const withClutchTheme = ({ themes, defaultTheme }) => { + initializeThemeState(Object.keys(themes), defaultTheme); + + return (Story, context) => { + const selectedTheme = pluckThemeFromContext(context); + const { themeOverride } = useThemeParameters(); + + const selected = themeOverride || selectedTheme || defaultTheme; + + return ( + + + + ); + }; +}; diff --git a/frontend/package.json b/frontend/package.json index 95562f4ca5..983432d084 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -103,6 +103,7 @@ "@storybook/addon-actions": "^7.6.0", "@storybook/addon-essentials": "^7.6.0", "@storybook/addon-links": "^7.6.0", + "@storybook/addon-themes": "^7.6.17", "@storybook/node-logger": "^7.6.0", "@storybook/preset-typescript": "^3.0.0", "@storybook/react-webpack5": "^7.6.0", diff --git a/frontend/packages/core/src/AppLayout/header.tsx b/frontend/packages/core/src/AppLayout/header.tsx index 6100e8f403..18bd8e955e 100644 --- a/frontend/packages/core/src/AppLayout/header.tsx +++ b/frontend/packages/core/src/AppLayout/header.tsx @@ -11,6 +11,7 @@ import Logo from "./logo"; import Notifications from "./notifications"; import SearchField from "./search"; import ShortLinker from "./shortLinker"; +import ThemeSwitcher from "./theme-switcher"; import { UserInformation } from "./user"; export const APP_BAR_HEIGHT = "64px"; @@ -115,7 +116,11 @@ const Header: React.FC = ({ )} {children && children} - {userInfo && } + {userInfo && ( + + + + )} diff --git a/frontend/packages/core/src/AppLayout/search.tsx b/frontend/packages/core/src/AppLayout/search.tsx index b1b6e110b0..139c938a0b 100644 --- a/frontend/packages/core/src/AppLayout/search.tsx +++ b/frontend/packages/core/src/AppLayout/search.tsx @@ -80,7 +80,7 @@ const ResultLabel = styled(Typography)(({ theme }: { theme: Theme }) => ({ // main search icon on header const SearchIconButton = styled(IconButton)(({ theme }: { theme: Theme }) => ({ - color: theme.palette.contrastColor, + color: theme.palette.common.white, fontSize: "24px", padding: "12px", marginRight: "8px", diff --git a/frontend/packages/core/src/AppLayout/stories/searchfield.stories.tsx b/frontend/packages/core/src/AppLayout/stories/searchfield.stories.tsx index c378d880b5..cdf7538fbd 100644 --- a/frontend/packages/core/src/AppLayout/stories/searchfield.stories.tsx +++ b/frontend/packages/core/src/AppLayout/stories/searchfield.stories.tsx @@ -5,6 +5,7 @@ import { Box, Grid as MuiGrid, Theme } from "@mui/material"; import type { Meta } from "@storybook/react"; import { ApplicationContext } from "../../Contexts/app-context"; +import { THEME_VARIANTS } from "../../Theme/colors"; import SearchFieldComponent from "../search"; export default { @@ -62,7 +63,10 @@ export default { const Grid = styled(MuiGrid)(({ theme }: { theme: Theme }) => ({ height: "64px", - backgroundColor: theme.palette.primary[900], + backgroundColor: + theme.palette.mode === THEME_VARIANTS.light + ? theme.palette.primary[900] + : theme.palette.headerGradient, })); const Template = () => ( diff --git a/frontend/packages/core/src/AppLayout/theme-switcher.tsx b/frontend/packages/core/src/AppLayout/theme-switcher.tsx new file mode 100644 index 0000000000..0806658f63 --- /dev/null +++ b/frontend/packages/core/src/AppLayout/theme-switcher.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import DarkModeIcon from "@mui/icons-material/DarkMode"; +import LightModeIcon from "@mui/icons-material/LightMode"; +import { Grid } from "@mui/material"; +import get from "lodash/get"; + +import { useUserPreferences } from "../Contexts"; +import { Select } from "../Input"; +import { THEME_VARIANTS } from "../Theme/colors"; + +const ThemeSwitcher = () => { + const { preferences, dispatch } = useUserPreferences(); + + const options = [ + { + label: THEME_VARIANTS.light, + startAdornment: , + }, + { + label: THEME_VARIANTS.dark, + startAdornment: , + }, + ]; + + const handleOnChange = (value: string) => { + dispatch({ + type: "SetPref", + payload: { key: "theme", value }, + }); + }; + + return ( + + Theme + +