1import 'fontsource-roboto/300.css';
2import 'fontsource-roboto/400.css';
3import 'fontsource-roboto/500.css';
4import 'fontsource-roboto/700.css';
5
6import { createMuiTheme, CssBaseline, IconButton, responsiveFontSizes, ThemeProvider } from '@material-ui/core';
7import { Brightness4, Brightness7 } from '@material-ui/icons';
8import { useLocalStorage } from '@rehooks/local-storage';
9import * as React from 'react';
10import * as ReactDOM from 'react-dom';
11
12import { App } from './app';
13import { AboutButton } from './components/about';
14import * as serviceWorker from './serviceWorker';
15
16function useTheme() {
17 const [themeName, setThemeName] = useLocalStorage<'light' | 'dark'>('themeName', 'dark');
18
19 // Workaround for https://github.com/mui-org/material-ui/issues/20708.
20 //
21 // When in strict mode (development only), this is required to properly allow
22 // the theme to be changed, as unused styles are not cleaned up. Create a new theme
23 // each time, so that they're forced to be injected again at the end of the existing
24 // block of stylesheets (as the styling library will see them as "new" styles, rather than
25 // assuming they can just be reused).
26 //
27 // This is gross, as it means every time the button is clicked it's a slew of extra
28 // stylesheets (each overriding the previous), but in production the cleanup works
29 // so this extra work is "only" a performance hit. If the bug is ever fixed, we can
30 // simply store two global themes and swap between them.
31 const theme = responsiveFontSizes(
32 createMuiTheme({
33 palette: {
34 type: themeName,
35 },
36 })
37 );
38
39 const toggleTheme = React.useMemo(() => {
40 if (themeName === 'light') {
41 return () => setThemeName('dark');
42 } else {
43 return () => setThemeName('light');
44 }
45 }, [themeName, setThemeName]);
46
47 return { theme, toggleTheme, isDark: themeName === 'dark' };
48}
49
50const Root = (_props: {}) => {
51 const { theme, toggleTheme, isDark } = useTheme();
52
53 return (
54 <React.StrictMode>
55 <ThemeProvider theme={theme}>
56 <CssBaseline />
57 <div
58 style={{
59 position: 'absolute',
60 top: 0,
61 right: 0,
62 margin: '0.5rem',
63 }}
64 >
65 <AboutButton style={{ marginRight: '0.5rem' }} />
66 <IconButton size="small" onClick={toggleTheme}>
67 {isDark ? <Brightness7 /> : <Brightness4 />}
68 </IconButton>
69 </div>
70 <App />
71 </ThemeProvider>
72 </React.StrictMode>
73 );
74};
75
76ReactDOM.render(<Root />, document.getElementById('root'));
77
78// If you want your app to work offline and load faster, you can change
79// unregister() to register() below. Note this comes with some pitfalls.
80// Learn more about service workers: https://bit.ly/CRA-PWA
81serviceWorker.unregister();
82
83// TODO: Try using a service worker to aid in reloading when needed.
84// let refreshing = false;
85// serviceWorker.register({
86// onUpdate: () => {
87// if (!refreshing) {
88// refreshing = true;
89// window.location.reload();
90// }
91// }
92// });