Skip to content

Commit 6a841b3

Browse files
committed
feat(ui): ThemeProvider
1 parent 7e612e4 commit 6a841b3

File tree

4 files changed

+66
-6
lines changed

4 files changed

+66
-6
lines changed

packages/ui/src/app/app.jsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { HashRouter, NavLink, Route, Switch, useLocation } from 'react-router-do
55
import { COMPONENT } from '@bundle-stats/utils';
66

77
import { URLS } from '../constants';
8+
import { ThemeProvider } from '../context/theme';
89
import { BundleAssets } from '../components/bundle-assets';
910
import { BundleAssetsTotals } from '../components/bundle-assets-totals';
1011
import { BundleModules } from '../components/bundle-modules';
@@ -205,10 +206,12 @@ AppComponent.propTypes = {
205206
};
206207

207208
export const App = (props) => (
208-
<HashRouter>
209-
<ScrollToTop />
210-
<QueryStateProvider>
211-
<AppComponent {...props} />
212-
</QueryStateProvider>
213-
</HashRouter>
209+
<ThemeProvider>
210+
<HashRouter>
211+
<ScrollToTop />
212+
<QueryStateProvider>
213+
<AppComponent {...props} />
214+
</QueryStateProvider>
215+
</HashRouter>
216+
</ThemeProvider>
214217
);

packages/ui/src/context/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './theme';

packages/ui/src/context/theme.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { ReactNode } from 'react';
2+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
3+
import { useCookie } from 'react-use';
4+
5+
type ThemeName = 'light' | 'dark';
6+
7+
type ThemeContextProps = {
8+
name: ThemeName;
9+
update: (newTheme: ThemeName) => void;
10+
};
11+
12+
const ThemeContext = createContext<ThemeContextProps>({
13+
name: 'light',
14+
update: () => {},
15+
});
16+
17+
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
18+
const [cookieValue, setCookieValue] = useCookie('theme');
19+
const [name, setName] = useState<ThemeName>(cookieValue === 'dark' ? 'dark' : 'light');
20+
21+
const updateClassList = useCallback((newTheme: ThemeName) => {
22+
const htmlElm = document.querySelector('html');
23+
24+
if (newTheme === 'dark') {
25+
htmlElm?.classList.replace('light-theme', 'dark-theme');
26+
} else {
27+
htmlElm?.classList.replace('dark-theme', 'light-theme');
28+
}
29+
}, []);
30+
31+
const updateTheme = useCallback((nextTheme: ThemeName) => {
32+
setName(nextTheme);
33+
updateClassList(nextTheme);
34+
setCookieValue(nextTheme);
35+
}, []);
36+
37+
// Sync classList
38+
useEffect(() => {
39+
updateClassList(name);
40+
}, [name]);
41+
42+
const value = useMemo(
43+
() => ({
44+
name,
45+
update: updateTheme,
46+
}),
47+
[name, updateTheme],
48+
);
49+
50+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
51+
};
52+
53+
export const useTheme = (): ThemeContextProps => {
54+
return useContext(ThemeContext);
55+
};

packages/ui/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './ui';
22
export * from './layout';
3+
export * from './context';
34
export * from './components';
45
export * from './utils';
56
export * from './app';

0 commit comments

Comments
 (0)