Skip to content

Commit

Permalink
add theme context for switching dark mode and remembering with localS…
Browse files Browse the repository at this point in the history
…torage
  • Loading branch information
ayan4m1 committed Jan 13, 2024
1 parent 4040ce8 commit 6215310
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 69 deletions.
48 changes: 13 additions & 35 deletions src/components/header.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
import { useSpring, animated } from '@react-spring/web';
import { Link, useStaticQuery, graphql } from 'gatsby';
import { Container, Navbar, Nav, NavDropdown } from 'react-bootstrap';

import usePrefersReducedMotion from 'hooks/usePrefersReducedMotion';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faFileArchive,
faGamepad,
faHeart,
faMoon,
faNewspaper,
faRectangleList,
faSun,
faTable
} from '@fortawesome/free-solid-svg-icons';
import { Fragment } from 'react';
import { Link, useStaticQuery, graphql } from 'gatsby';
import { Container, Navbar, Nav, NavDropdown, Button } from 'react-bootstrap';

const bobbleSpring = {
from: { y: 4 },
to: [{ y: -4 }, { y: 4 }],
config: {
mass: 0.1,
tension: 20,
friction: 0.1
},
loop: true,
reset: false
};
import { useThemeContext } from 'hooks/useThemeContext';

export default function Header() {
const [springs] = useSpring(() => bobbleSpring);
const disableMotion = usePrefersReducedMotion();
const { darkMode, toggleDarkMode } = useThemeContext();
const data = useStaticQuery(graphql`
query {
site {
Expand Down Expand Up @@ -97,23 +85,13 @@ export default function Header() {
</Nav.Link>
</NavDropdown>
</Nav>
<Nav className="ms-auto text-light">
{disableMotion ? (
<p style={{ textShadow: '1px 1px 4px rgba(0,0,0,0.6)' }}>
More Coming Soon &trade;
</p>
) : (
<animated.p
className="mb-0"
style={{
position: 'relative',
textShadow: '1px 1px 4px rgba(0,0,0,0.6)',
...springs
}}
>
More Coming Soon &trade;
</animated.p>
)}
<Nav
className="ms-lg-auto text-light d-flex align-items-center justify-content-end"
style={{ flexDirection: 'row' }}
>
<Button variant="info" onClick={toggleDarkMode}>
<FontAwesomeIcon icon={darkMode ? faMoon : faSun} fixedWidth />
</Button>
</Nav>
</Navbar.Collapse>
</Container>
Expand Down
9 changes: 3 additions & 6 deletions src/components/layout.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import PropTypes from 'prop-types';
import { Fragment } from 'react';
import Snowfall from 'react-snowfall';
import { getDate, getMonth } from 'date-fns';

import Header from 'components/header';
import useDarkMode from 'hooks/useDarkMode';
import usePrefersReducedMotion from 'hooks/usePrefersReducedMotion';
import ThemeProvider from './themeProvider';

export default function Layout({ children }) {
useDarkMode();

const disableMotion = usePrefersReducedMotion();
const isChristmas =
getMonth(Date.now()) === 11 && [24, 25, 26].includes(getDate(Date.now()));

return (
<Fragment>
<ThemeProvider>
{!disableMotion && isChristmas && <Snowfall />}
<Header />
<main className="mt-3 mb-2">{children}</main>
</Fragment>
</ThemeProvider>
);
}

Expand Down
43 changes: 43 additions & 0 deletions src/components/themeProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import PropTypes from 'prop-types';
import { useCallback, useEffect } from 'react';
import useLocalStorageState from 'use-local-storage-state';

import useMediaQuery from 'hooks/useMediaQuery';
import { ThemeContext } from 'hooks/useThemeContext';

const mediaQuery = '(prefers-color-scheme: dark)';

export default function ThemeProvider({ children }) {
const [darkMode, setDarkMode] = useLocalStorageState('darkMode', {
defaultValue: useMediaQuery(mediaQuery)
});
const toggleDarkMode = useCallback(
() => setDarkMode((val) => !val),
[setDarkMode]
);

useEffect(() => {
if (darkMode) {
document.body.classList.remove('light-mode');
document.body.classList.add('dark-mode');
} else {
document.body.classList.remove('dark-mode');
document.body.classList.add('light-mode');
}
}, [darkMode]);

return (
<ThemeContext.Provider
value={{
darkMode,
toggleDarkMode
}}
>
{children}
</ThemeContext.Provider>
);
}

ThemeProvider.propTypes = {
children: PropTypes.node.isRequired
};
24 changes: 0 additions & 24 deletions src/hooks/useDarkMode.js

This file was deleted.

11 changes: 7 additions & 4 deletions src/hooks/useMediaQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { useState, useEffect } from 'react';
const queryMatches = (query) =>
typeof window !== 'undefined' ? window.matchMedia(query).matches : false;

const bindListener = (object, event, handler) => {
object.addEventListener(event, handler);

return () => object.removeEventListener(event, handler);
};

export default function useMediaQuery(query) {
const [matches, setMatches] = useState(queryMatches(query));

Expand All @@ -11,12 +17,9 @@ export default function useMediaQuery(query) {
return;
}

const mediaQueryList = window.matchMedia(query);
const listener = (event) => setMatches(event.matches);

mediaQueryList.addEventListener('change', listener);

return () => mediaQueryList.removeEventListener('change', listener);
return bindListener(window.matchMedia(query), 'change', listener);
}, [query]);

return matches;
Expand Down
7 changes: 7 additions & 0 deletions src/hooks/useThemeContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createContext, useContext } from 'react';

export const ThemeContext = createContext({
darkMode: false
});

export const useThemeContext = () => useContext(ThemeContext);

0 comments on commit 6215310

Please sign in to comment.