Skip to content

Instantly share code, notes, and snippets.

@JayMGurav
Created June 9, 2021 08:33
Show Gist options
  • Save JayMGurav/c8e6318a25cf29e96a6e3368c6ec8a64 to your computer and use it in GitHub Desktop.
Save JayMGurav/c8e6318a25cf29e96a6e3368c6ec8a64 to your computer and use it in GitHub Desktop.
Dark Mode using Next.js
import NextDocument, { Html, Head, Main, NextScript } from 'next/document';
import React from 'react';
import {
COLORS,
COLOR_MODE_KEY,
INITIAL_COLOR_MODE_CSS_PROPERTY,
} from '@/styles/themeConfig';
/**
* COLORS = theme colors
* COLOR_MODE = Key for localstorage
* "INITIAL_COLOR_MODE_CSS_PROPERTY" property for colorMode
*/
function setColorByTheme() {
const COLORS = '๐ŸŒˆ';
const COLOR_MODE_KEY = '๐Ÿ”‘';
const INITIAL_COLOR_MODE_CSS_PROPERTY = '๐Ÿบ';
const prefersDarkModeFromMeadiaQuery = window.matchMedia(
'(prefers-color-scheme: dark)'
).matches;
const userPersistedPreference = window.localStorage.getItem(COLOR_MODE_KEY);
let colorMode = 'light';
const userHasUsedToggle = typeof userPersistedPreference === 'string';
if (userHasUsedToggle) {
colorMode = userPersistedPreference;
} else {
colorMode = prefersDarkModeFromMeadiaQuery ? 'dark' : 'light';
window.localStorage.setItem(COLOR_MODE_KEY, colorMode);
}
const root = document.documentElement;
root.style.setProperty(INITIAL_COLOR_MODE_CSS_PROPERTY, colorMode);
Object.entries(COLORS).forEach(([value, colorByTheme]) => {
const cssVarName = `--color-${value}`;
root.style.setProperty(cssVarName, colorByTheme[colorMode]);
});
}
const minifiedCorrectedSetColorByTheme = () => {
const corrected = String(setColorByTheme)
.replace("'๐ŸŒˆ'", JSON.stringify(COLORS))
.replace('๐Ÿ”‘', COLOR_MODE_KEY)
.replace('๐Ÿบ', INITIAL_COLOR_MODE_CSS_PROPERTY);
const called = `(${corrected})()`;
return called;
};
class Document extends NextDocument {
render() {
return (
<Html>
<Head />
<body>
<script
dangerouslySetInnerHTML={{
__html: minifiedCorrectedSetColorByTheme(),
}}></script>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default Document;
export const COLORS = {
background: {
light: 'hsl(207, 100%, 99%)',
dark: 'hsl(0, 0%, 2%)',
},
text: {
light: 'hsl(0, 0%, 2%)',
dark: 'hsl(207, 100%, 99%)',
},
gray1: {
light: 'hsl(204, 15%, 94%)',
dark: 'hsl(0,0%, 6%)',
},
gray2: {
light: 'hsl(0, 0%, 88%)',
dark: 'hsl(0,0%, 12%)',
},
gray3: {
light: 'hsl(0, 0%, 82%)',
dark: 'hsl(0,0%, 18%)',
},
};
export const COLOR_MODE_KEY = 'color-mode';
export const INITIAL_COLOR_MODE_CSS_PROPERTY = '--initial-color-mode';
import {
COLORS,
COLOR_MODE_KEY,
INITIAL_COLOR_MODE_CSS_PROPERTY,
} from '@/styles/themeConfig';
import { createContext, useEffect, useMemo, useState } from 'react';
import { ChildrenOnlyProps, ColorMode } from '@/types/index';
export const ThemeContext = createContext<{
colorMode?: 'dark' | 'light';
changeColorMode?: (mode: ColorMode) => void;
}>({});
function ThemeProvider(props: ChildrenOnlyProps) {
const [colorMode, setColorMode] = useState<ColorMode | null>(null);
useEffect(() => {
const root = window.document.documentElement;
const initiallySetColorMode: ColorMode = root.style.getPropertyValue(
INITIAL_COLOR_MODE_CSS_PROPERTY
) as ColorMode;
setColorMode(initiallySetColorMode);
}, []);
function themeContextValue() {
function setColors(mode: ColorMode) {
console.log(mode);
const root = window.document.documentElement;
window.localStorage.setItem(COLOR_MODE_KEY, mode);
Object.entries(COLORS).forEach(([value, colorByMode]) => {
const cssVarName = `--color-${value}`;
root.style.setProperty(cssVarName, colorByMode[mode]);
setColorMode(mode);
});
}
return { colorMode, changeColorMode: setColors };
}
const memorizedThemeContextValue = useMemo(themeContextValue, [
colorMode,
themeContextValue,
]);
return (
<ThemeContext.Provider value={memorizedThemeContextValue}>
{props.children}
</ThemeContext.Provider>
);
}
export default ThemeProvider;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment