mirror of
https://github.com/kremalicious/portfolio.git
synced 2024-11-14 09:05:15 +01:00
custom useDarkMode hook
This commit is contained in:
parent
15b5006df4
commit
487461518a
@ -74,11 +74,12 @@ If you want to know how, have a look at the respective components:
|
|||||||
|
|
||||||
### 💅 Theme switcher
|
### 💅 Theme switcher
|
||||||
|
|
||||||
Includes a theme switcher which allows user to toggle between a light and a dark theme. Switching between them also happens automatically based on user's system preferences. If a visitor has set the theme manually that selection is remembered in `localStorage`, and is restored on next visit. All handled by [use-dark-mode](https://github.com/donavon/use-dark-mode)
|
Includes a theme switcher which allows user to toggle between a light and a dark theme. Switching between them also happens automatically based on user's system preferences.
|
||||||
|
|
||||||
If you want to know how, have a look at the respective components:
|
If you want to know how, have a look at the respective components:
|
||||||
|
|
||||||
- [`src/components/molecules/ThemeSwitch.jsx`](src/components/molecules/ThemeSwitch.jsx)
|
- [`src/components/molecules/ThemeSwitch.jsx`](src/components/molecules/ThemeSwitch.jsx)
|
||||||
|
- [`src/hooks/useDarkMode.js`](src/hooks/useDarkMode.js)
|
||||||
|
|
||||||
### 🏆 SEO component
|
### 🏆 SEO component
|
||||||
|
|
||||||
|
@ -73,14 +73,6 @@ module.exports = {
|
|||||||
theme_color_in_head: false // dynamically set in ThemeSwitch
|
theme_color_in_head: false // dynamically set in ThemeSwitch
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
resolve: 'gatsby-plugin-use-dark-mode',
|
|
||||||
options: {
|
|
||||||
classNameDark: 'dark',
|
|
||||||
classNameLight: 'light',
|
|
||||||
minify: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'gatsby-plugin-react-helmet',
|
'gatsby-plugin-react-helmet',
|
||||||
'gatsby-plugin-sitemap',
|
'gatsby-plugin-sitemap',
|
||||||
'gatsby-plugin-offline',
|
'gatsby-plugin-offline',
|
||||||
|
28194
package-lock.json
generated
28194
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,6 @@
|
|||||||
"gatsby-plugin-sharp": "^3.0.1",
|
"gatsby-plugin-sharp": "^3.0.1",
|
||||||
"gatsby-plugin-sitemap": "^3.0.0",
|
"gatsby-plugin-sitemap": "^3.0.0",
|
||||||
"gatsby-plugin-svgr": "^3.0.0-beta.0",
|
"gatsby-plugin-svgr": "^3.0.0-beta.0",
|
||||||
"gatsby-plugin-use-dark-mode": "^1.3.0",
|
|
||||||
"gatsby-plugin-webpack-size": "^2.0.1",
|
"gatsby-plugin-webpack-size": "^2.0.1",
|
||||||
"gatsby-source-filesystem": "^3.0.0",
|
"gatsby-source-filesystem": "^3.0.0",
|
||||||
"gatsby-transformer-json": "^3.0.0",
|
"gatsby-transformer-json": "^3.0.0",
|
||||||
@ -51,7 +50,6 @@
|
|||||||
"remark-parse": "^9.0.0",
|
"remark-parse": "^9.0.0",
|
||||||
"remark-react": "^8.0.0",
|
"remark-react": "^8.0.0",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
"use-dark-mode": "^2.3.1",
|
|
||||||
"vcf": "^2.1.0"
|
"vcf": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -4,7 +4,7 @@ import posed, { PoseGroup } from 'react-pose'
|
|||||||
import { fadeIn } from './atoms/Transitions'
|
import { fadeIn } from './atoms/Transitions'
|
||||||
import Typekit from './atoms/Typekit'
|
import Typekit from './atoms/Typekit'
|
||||||
import HostnameCheck from './atoms/HostnameCheck'
|
import HostnameCheck from './atoms/HostnameCheck'
|
||||||
// import ThemeSwitch from './molecules/ThemeSwitch'
|
import ThemeSwitch from './molecules/ThemeSwitch'
|
||||||
import Header from './organisms/Header'
|
import Header from './organisms/Header'
|
||||||
import Footer from './organisms/Footer'
|
import Footer from './organisms/Footer'
|
||||||
import { screen } from './Layout.module.css'
|
import { screen } from './Layout.module.css'
|
||||||
@ -40,7 +40,7 @@ export default function Layout({ children, location }) {
|
|||||||
<>
|
<>
|
||||||
<Typekit />
|
<Typekit />
|
||||||
<HostnameCheck allowedHosts={allowedHosts} />
|
<HostnameCheck allowedHosts={allowedHosts} />
|
||||||
{/* <ThemeSwitch /> */}
|
<ThemeSwitch />
|
||||||
|
|
||||||
<PoseGroup animateOnMount={process.env.NODE_ENV !== 'test'}>
|
<PoseGroup animateOnMount={process.env.NODE_ENV !== 'test'}>
|
||||||
<RoutesContainer
|
<RoutesContainer
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { memo, useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import useDarkMode from 'use-dark-mode'
|
|
||||||
import Icon from '../atoms/Icon'
|
import Icon from '../atoms/Icon'
|
||||||
import {
|
import {
|
||||||
checkboxContainer,
|
checkboxContainer,
|
||||||
@ -10,16 +9,15 @@ import {
|
|||||||
checkbox,
|
checkbox,
|
||||||
label
|
label
|
||||||
} from './ThemeSwitch.module.css'
|
} from './ThemeSwitch.module.css'
|
||||||
|
import useDarkMode from '../../hooks/useDarkMode'
|
||||||
|
|
||||||
const ThemeToggle = memo(({ dark }) => (
|
const ThemeToggle = ({ dark }) => (
|
||||||
<span id="toggle" className={checkboxContainer} aria-live="assertive">
|
<span id="toggle" className={checkboxContainer} aria-live="assertive">
|
||||||
<Icon name="Sun" className={!dark ? null : 'active'} />
|
<Icon name="Sun" className={!dark ? null : 'active'} />
|
||||||
<span className={checkboxFake} />
|
<span className={checkboxFake} />
|
||||||
<Icon name="Moon" className={dark ? 'active' : null} />
|
<Icon name="Moon" className={dark ? 'active' : null} />
|
||||||
</span>
|
</span>
|
||||||
))
|
)
|
||||||
|
|
||||||
ThemeToggle.displayName = 'ThemeToggle'
|
|
||||||
|
|
||||||
ThemeToggle.propTypes = {
|
ThemeToggle.propTypes = {
|
||||||
dark: PropTypes.bool.isRequired
|
dark: PropTypes.bool.isRequired
|
||||||
@ -27,7 +25,7 @@ ThemeToggle.propTypes = {
|
|||||||
|
|
||||||
const ThemeToggleInput = ({ dark, toggleDark }) => (
|
const ThemeToggleInput = ({ dark, toggleDark }) => (
|
||||||
<input
|
<input
|
||||||
onChange={() => toggleDark()}
|
onChange={() => toggleDark(!dark)}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="toggle"
|
name="toggle"
|
||||||
value="toggle"
|
value="toggle"
|
||||||
@ -36,8 +34,6 @@ const ThemeToggleInput = ({ dark, toggleDark }) => (
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
ThemeToggleInput.displayName = 'ThemeToggleInput'
|
|
||||||
|
|
||||||
ThemeToggleInput.propTypes = {
|
ThemeToggleInput.propTypes = {
|
||||||
dark: PropTypes.bool.isRequired,
|
dark: PropTypes.bool.isRequired,
|
||||||
toggleDark: PropTypes.func.isRequired
|
toggleDark: PropTypes.func.isRequired
|
||||||
@ -60,10 +56,7 @@ HeadItems.propTypes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ThemeSwitch() {
|
export default function ThemeSwitch() {
|
||||||
const { value, toggle } = useDarkMode(false, {
|
const { value, toggle } = useDarkMode()
|
||||||
classNameDark: 'dark',
|
|
||||||
classNameLight: 'light'
|
|
||||||
})
|
|
||||||
const [themeColor, setThemeColor] = useState('')
|
const [themeColor, setThemeColor] = useState('')
|
||||||
const [bodyClass, setBodyClass] = useState('')
|
const [bodyClass, setBodyClass] = useState('')
|
||||||
|
|
||||||
|
60
src/hooks/useDarkMode.js
Normal file
60
src/hooks/useDarkMode.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// adapted from
|
||||||
|
// https://github.com/daveschumaker/react-dark-mode-hook/blob/master/useDarkMode.js
|
||||||
|
//
|
||||||
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
|
|
||||||
|
const isClient = typeof window === 'object'
|
||||||
|
|
||||||
|
function getDarkMode() {
|
||||||
|
// if (localStorage.getItem('theme') === 'dark') {
|
||||||
|
// return true
|
||||||
|
// } else if (localStorage.getItem('theme') === 'light') {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (
|
||||||
|
isClient &&
|
||||||
|
window.matchMedia &&
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useDarkMode() {
|
||||||
|
const [darkMode, setDarkMode] = useState(getDarkMode)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle system theme change events
|
||||||
|
//
|
||||||
|
const handleChange = useCallback(() => {
|
||||||
|
setDarkMode(getDarkMode())
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isClient) return false
|
||||||
|
|
||||||
|
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Handle Chrome & Firefox
|
||||||
|
darkModeQuery.addEventListener('change', handleChange)
|
||||||
|
} catch (addEventListenerError) {
|
||||||
|
try {
|
||||||
|
// Handle Safari
|
||||||
|
darkModeQuery.addListener('change', handleChange)
|
||||||
|
} catch (addListenerError) {
|
||||||
|
console.error(addListenerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () =>
|
||||||
|
window
|
||||||
|
.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
.removeEventListener('change', handleChange)
|
||||||
|
}, [handleChange])
|
||||||
|
|
||||||
|
return { value: darkMode, toggle: setDarkMode }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user