Skip to content

Commit

Permalink
feat: implement listener to detect dark mode in the browser
Browse files Browse the repository at this point in the history
  • Loading branch information
fariasmateuss committed Mar 23, 2022
1 parent d0762ea commit 5fce2aa
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 100 deletions.
4 changes: 2 additions & 2 deletions @types/styled.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint @typescript-eslint/no-empty-interface: "off" */
import 'styled-components';

import { dark, light } from 'styles/theme/colors';
import { light as defaultTheme } from 'styles/theme/colors';

export type Theme = typeof light & typeof dark;
export type Theme = typeof defaultTheme;

declare module 'styled-components' {
export interface DefaultTheme extends Theme {}
Expand Down
11 changes: 4 additions & 7 deletions components/Layout/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { LocaleSwitcher } from 'components/LocaleSwitcher';
import { ToggleTheme } from 'components/ToggleTheme';
import {
useStylesDispatch,
useStylesState,
} from 'contexts/styles/StylesContext';
import { useThemeDispatch, useThemeState } from 'contexts/theme/ThemeContext';

import * as S from 'styles/components/Layout/Header';

export function Header() {
const { theme } = useStylesState();
const { switchTheme } = useStylesDispatch();
const { mode } = useThemeState();
const { onSelectMode } = useThemeDispatch();

return (
<S.Wrapper>
<LocaleSwitcher />
<ToggleTheme toggleTheme={() => switchTheme(theme)} />
<ToggleTheme toggleTheme={() => onSelectMode(mode)} />
</S.Wrapper>
);
}
6 changes: 3 additions & 3 deletions components/Logo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Image from 'next/image';

import { useStylesState } from 'contexts/styles/StylesContext';
import { useThemeState } from 'contexts/theme/ThemeContext';
import { useI18nState } from 'contexts/i18n/I18Context';

export function Logo() {
const { theme } = useStylesState();
const { mode } = useThemeState();
const { t } = useI18nState();

return theme === 'light' ? (
return mode === 'light' ? (
<Image
src="/static/light-logo.svg"
alt={t.heading.meme_generator_description}
Expand Down
14 changes: 6 additions & 8 deletions components/ToggleTheme/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import Switch from 'react-switch';
import { shade } from 'polished';

import { colors } from 'styles/theme';
import { useStylesState } from 'contexts/styles/StylesContext';

import { theme } from 'styles/theme';
import { useThemeState } from 'contexts/theme/ThemeContext';
import { ToggleThemeProps } from './types';

export function ToggleTheme({ toggleTheme }: ToggleThemeProps) {
const { theme } = useStylesState();
const { mode } = useThemeState();

return (
<Switch
onChange={toggleTheme}
checked={theme === 'dark'}
checked={mode === 'dark'}
checkedIcon={false}
uncheckedIcon={false}
height={10}
width={40}
handleDiameter={20}
offColor={colors.light.alto}
onColor={colors.light.alto}
offColor={theme.light.alto}
onColor={theme.light.alto}
/>
);
}
2 changes: 1 addition & 1 deletion contexts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const DynamicStylesProvider = dynamic(
);

const DynamicStylesContainer = dynamic(
() => import('./styles/StylesProvider').then(mod => mod.StylesContainer),
() => import('./theme/ThemeProvider').then(mod => mod.ThemeContainer),
{
ssr: false,
},
Expand Down
10 changes: 5 additions & 5 deletions contexts/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { PropsWithChildren } from 'react';
import { ThemeProvider } from 'styled-components';

import { colors } from 'styles/theme';
import GlobalStyle from 'styles/global';

import { useStylesState } from './styles/StylesContext';
import { theme } from 'styles/theme';
import { useThemeState } from './theme/ThemeContext';

export function StylesProvider({ children }: PropsWithChildren<unknown>) {
const { theme } = useStylesState();
const { mode } = useThemeState();
const costumTheme = theme[mode];

return (
<ThemeProvider theme={colors[theme]}>
<ThemeProvider theme={costumTheme}>
<GlobalStyle />
{children}
</ThemeProvider>
Expand Down
33 changes: 0 additions & 33 deletions contexts/styles/StylesContext.ts

This file was deleted.

27 changes: 0 additions & 27 deletions contexts/styles/StylesProvider.tsx

This file was deleted.

7 changes: 0 additions & 7 deletions contexts/styles/types.ts

This file was deleted.

33 changes: 33 additions & 0 deletions contexts/theme/ThemeContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useContext, createContext } from 'react';
import { ThemeDispatchContextData, ThemeStateContextData } from './types';

export const ThemeStateContext = createContext<
ThemeStateContextData | undefined
>(undefined);

export const ThemeDispatchContext = createContext<
ThemeDispatchContextData | undefined
>(undefined);

export const ThemeStateProvider = ThemeStateContext.Provider;
export const ThemeDispatchProvider = ThemeDispatchContext.Provider;

export function useThemeState() {
const context = useContext(ThemeStateContext);

if (!context) {
throw new Error('useThemeState must be used within a ThemeProvider');
}

return context;
}

export function useThemeDispatch() {
const context = useContext(ThemeDispatchContext);

if (!context) {
throw new Error('useThemeDispatch must be used within ThemeProvider');
}

return context;
}
40 changes: 40 additions & 0 deletions contexts/theme/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { PropsWithChildren, useCallback, useEffect, useMemo } from 'react';

import { THEME_STORAGE_KEY } from 'constants/localStorage';
import { usePersistedState } from 'hooks/usePersistedState';
import { ThemeDispatchProvider, ThemeStateProvider } from './ThemeContext';
import { Theme } from './types';

export function ThemeContainer({ children }: PropsWithChildren<unknown>) {
const [mode, setMode] = usePersistedState<Theme>(THEME_STORAGE_KEY, 'light');

const onSelectMode = useCallback((mode: Theme) => {
setMode(mode === 'light' ? 'dark' : 'light');
}, []);

useEffect(() => {
window
.matchMedia('(prefers-color-scheme: light)')
.addEventListener('change', e =>
onSelectMode(e.matches ? 'dark' : 'light'),
);

onSelectMode(
window.matchMedia('(prefers-color-scheme: light)').matches
? 'dark'
: 'light',
);
}, []);

const themeState = useMemo(() => ({ mode }), [mode]);

const themeDispatch = useMemo(() => ({ onSelectMode }), [onSelectMode]);

return (
<ThemeStateProvider value={themeState}>
<ThemeDispatchProvider value={themeDispatch}>
{children}
</ThemeDispatchProvider>
</ThemeStateProvider>
);
}
11 changes: 11 additions & 0 deletions contexts/theme/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { theme } from 'styles/theme';

export type Theme = keyof typeof theme;

export type ThemeStateContextData = {
mode: Theme;
};

export type ThemeDispatchContextData = {
onSelectMode: (mode: Theme) => void;
};
11 changes: 5 additions & 6 deletions styles/theme/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ export const light = {
background: '#f5f6fA',
},
text: '#ffffff',
orange: '#ff9000',
danger: '#c53030',
disabled: '#666360',
loading: '#2e384d',
button: {
background: '#4395D8',
color: '#ffffff',
},
};

export const dark = {
export const dark: typeof light = {
...light,
background: '#171717',
modal: '#444444',
alto: '#dbdbdb',
Expand All @@ -26,10 +30,5 @@ export const dark = {
borderColor: '#5a5a5a',
background: '#404040',
},
text: '#ffffff',
loading: '#ffffff',
button: {
background: '#4395D8',
color: '#ffffff',
},
};
2 changes: 1 addition & 1 deletion styles/theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { light, dark } from './colors';

export const colors = {
export const theme = {
light,
dark,
};

1 comment on commit 5fce2aa

@vercel
Copy link

@vercel vercel bot commented on 5fce2aa Mar 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.