hupe1980 / gatsby-theme-material-ui

Gatsby theme for Material-UI
MIT License
100 stars 42 forks source link

[Question] Updating theme dynamically (e.g. dark mode) #50

Open Lane opened 4 years ago

Lane commented 4 years ago

Hi, thanks for this theme, it's great.

I'm wondering if there is a way to dynamically update the theme?

Currently I have a custom theme for my site in src/gatsby-theme-material-ui-top-layout/theme.js which defines my theme, but I'd like to make changes to it on the fly.

For example, if I had a dark mode toggle on my site, I'd like to update the theme to use { pallete: { type: "dark" } }

I'm still new to gatsby, so unsure about the best approach to doing this. Is there a way this could this be easily done?

Lane commented 4 years ago

I've tried overriding the top layout to provide an updated theme when dark mode is on, but for some reason the theme used in the site will only use what's in src/gatsby-theme-material-ui-top-layout/theme.js

This is what I have in src/gatsby-theme-material-ui-top-layout/components/top-layout.js:

import React, { useContext, useMemo } from "react"
import { createMuiTheme } from "@material-ui/core/styles"
import ThemeTopLayout from "gatsby-theme-material-ui-top-layout/src/components/top-layout"
import { SiteContext } from "../../utils/site-context"

export default function TopLayout({ children, theme }) {
  const { isDarkMode } = useContext(SiteContext)
  const adjustedTheme = useMemo(
    () =>
      createMuiTheme(theme, {
        palette: { type: isDarkMode ? "dark" : "light" },
      }),
    [theme, isDarkMode]
  )
  console.log("theme", adjustedTheme, adjustedTheme.palette.type)
  return <ThemeTopLayout theme={adjustedTheme}>{children}</ThemeTopLayout>
}

Anytime I toggle dark mode, it logs the correct theme to the console, but there are no changes to the theme used on the page. Any ideas where I'm going wrong?

Lane commented 4 years ago

I have a solution working, but in order for it to work the theme in theme.js must be defined as an object and not using createMuiTheme. I don't quite understand why it doesn't work properly when creating the theme in theme.js using createMuiTheme.

src/gatsby-theme-material-ui-top-layout/theme.js:

import { blue } from "@material-ui/core/colors"

const theme = {
  palette: {
    primary: {
      light: blue[400],
      main: blue[500],
      dark: blue[600],
    },
  },
  typography: {
    fontFamily: ["Montserrat", "sans-serif"].join(","),
  },
}

export default theme

src/gatsby-theme-material-ui-top-layout/components/top-layout.js:

import React, { useContext, useMemo } from "react"
import { deepmerge } from "@material-ui/utils"
import { createMuiTheme } from "@material-ui/core/styles"
import ThemeTopLayout from "gatsby-theme-material-ui-top-layout/src/components/top-layout"
import { SiteContext } from "../../utils/site-context"

export default function TopLayout({ children, theme }) {
  const { isDarkMode } = useContext(SiteContext)
  const adjustedTheme = useMemo(() => {
    const base = {
      palette: {
        type: isDarkMode ? "dark" : "light",
      },
    }
    const merged = deepmerge(base, theme)
    return createMuiTheme(merged)
  }, [isDarkMode])
  return <ThemeTopLayout theme={adjustedTheme}>{children}</ThemeTopLayout>
}