Skip to content

Commit

Permalink
refactor: dark mode strategy through context api
Browse files Browse the repository at this point in the history
  • Loading branch information
willianantunes committed May 9, 2021
1 parent 023b791 commit c705c8d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 87 deletions.
5 changes: 3 additions & 2 deletions gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { initializeDarkThemeStrategy } from "./src/business/dark-mode-strategy"
import "prismjs/themes/prism-tomorrow.css"
import React from "react"
import { wrapWithDarkThemeProvider } from "./src/contexts/dark-theme-context"

initializeDarkThemeStrategy()
export const wrapRootElement = wrapWithDarkThemeProvider
3 changes: 3 additions & 0 deletions gatsby-ssr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { wrapWithDarkThemeProvider } from "./src/contexts/dark-theme-context"

export const wrapRootElement = wrapWithDarkThemeProvider
74 changes: 0 additions & 74 deletions src/business/dark-mode-strategy.js

This file was deleted.

23 changes: 17 additions & 6 deletions src/components/ToggleTheme/index.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import React, { useEffect, useState } from "react"
import * as S from "./styled"
import { Helmet } from "react-helmet/es/Helmet"
import { isCurrentThemeDark, toggleTheme } from "../../business/dark-mode-strategy"
import {
paletteTypeDark,
paletteTypeLight,
paletteTypeLocalStorageKey,
useDarkThemeContext,
} from "../../contexts/dark-theme-context"

export default function ToggleTheme() {
const { paletteType, setPaletteType } = useDarkThemeContext()
const [isDarkMode, setIsDarkMode] = useState(null)

function evaluateCurrentTheme() {
const evaluation = isCurrentThemeDark()
const evaluation = paletteType === paletteTypeDark
setIsDarkMode(evaluation)
return evaluation
}

function toggleTheme() {
const newTheme = paletteType === paletteTypeLight ? paletteTypeDark : paletteTypeLight
setPaletteType(newTheme)
try {
localStorage.setItem(paletteTypeLocalStorageKey, newTheme)
} catch (exceptionToBeIgnored) {}
}

useEffect(() => {
evaluateCurrentTheme()
}, [])
}, [paletteType])

const onClick = () => {
// Please see dark-mode-strategy.js to understand what is going on
toggleTheme()
// So the component can be rendered properly
evaluateCurrentTheme()
}

return (
Expand Down
36 changes: 36 additions & 0 deletions src/contexts/dark-theme-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from "react"

export const paletteTypeLight = "light"
export const paletteTypeDark = "dark"
export const paletteTypeLocalStorageKey = "custom-palette-type"
const mediaQueryColorTheme = `(prefers-color-scheme: ${paletteTypeDark})`

const DarkThemeContext = React.createContext(null)
const useDarkThemeContext = () => React.useContext(DarkThemeContext)

function currentTheme() {
const prefersDark = typeof window !== "undefined" && window.matchMedia(mediaQueryColorTheme).matches

try {
const themeInWindow = typeof window !== "undefined" && localStorage.getItem(paletteTypeLocalStorageKey)
if (themeInWindow) {
return localStorage.getItem(paletteTypeLocalStorageKey)
}
} catch (exceptionToBeIgnored) {}

return prefersDark ? paletteTypeDark : paletteTypeLight
}

function DarkThemeProvider({ children }) {
const themeToUse = currentTheme()
const [paletteType, setPaletteType] = React.useState(themeToUse)
const properties = { paletteType, setPaletteType }

return <DarkThemeContext.Provider value={properties}>{children}</DarkThemeContext.Provider>
}

function wrapWithDarkThemeProvider({ element }) {
return <DarkThemeProvider>{element}</DarkThemeProvider>
}

export { useDarkThemeContext, wrapWithDarkThemeProvider }
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import CssBaseline from "@material-ui/core/CssBaseline"
import Viewport from "gatsby-theme-material-ui-top-layout/src/components/viewport"
import { createMuiTheme } from "@material-ui/core"
import { themeConfiguration } from "../theme"
import { useWindowDarkModeStrategy } from "../../business/dark-mode-strategy"
import { useDarkThemeContext } from "../../contexts/dark-theme-context"

// Sadly the injected theme can't be updated, that is why I import the one in theme.js
export default function TopLayout({ children }) {
// https://material-ui.com/customization/palette/#user-preference
const paletteType = useWindowDarkModeStrategy()
const { paletteType } = useDarkThemeContext()

const memoizedTheme = useMemo(() => {
themeConfiguration.palette.type = paletteType
Expand Down
14 changes: 11 additions & 3 deletions src/templates/blog-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import Layout from "../components/Layout"
import { useSiteMetadata } from "../hooks/use-site-metadata"
import BlogPost from "../components/BlogPost"
import CommentSection from "../components/CommentSection"
import { isCurrentThemeDark } from "../business/dark-mode-strategy"
import { paletteTypeDark, useDarkThemeContext } from "../contexts/dark-theme-context"

const BlogPostTemplate = ({ data }) => {
const { siteUrl } = useSiteMetadata()
// TODO: previousPost and nextPost should be used!
const { previousPost, nextPost, markdownRemark: currentPost } = data
const { paletteType } = useDarkThemeContext()
const commentSectionRef = createRef()

useEffect(() => {
const commentScript = document.createElement("script")
// TODO: When the user changes theme, this should be updated too
const theme = typeof window !== "undefined" && isCurrentThemeDark() ? "github-dark" : "github-light"
const theme = paletteType === paletteTypeDark ? "github-dark" : "github-light"
commentScript.async = true
commentScript.src = "https://utteranc.es/client.js"
// TODO: Use ENV variables for it
Expand All @@ -30,7 +31,14 @@ const BlogPostTemplate = ({ data }) => {
} else {
console.log(`Error adding utterances comments on: ${commentSectionRef}`)
}
}, [])

const cleanUpFunctionToRemoveCommentSection = () => {
commentScript.remove()
document.querySelectorAll(".utterances").forEach(el => el.remove())
}

return cleanUpFunctionToRemoveCommentSection
}, [paletteType])

const description = currentPost.frontmatter.description
const date = currentPost.frontmatter.date
Expand Down

0 comments on commit c705c8d

Please sign in to comment.