Skip to content

Commit

Permalink
Manage dark mode with the MUI library
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivm committed Aug 20, 2024
1 parent 876b24b commit 87a2d15
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 102 deletions.
68 changes: 0 additions & 68 deletions src/app/[locale]/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,6 @@
--font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;

--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;

--primary-glow: conic-gradient(
from 180deg at 50% 50%,
#16abff33 0deg,
#0885ff33 55deg,
#54d6ff33 120deg,
#0071ff33 160deg,
transparent 360deg
);
--secondary-glow: radial-gradient(
rgba(255, 255, 255, 1),
rgba(255, 255, 255, 0)
);

--tile-start-rgb: 239, 245, 249;
--tile-end-rgb: 228, 232, 233;
--tile-border: conic-gradient(
#00000080,
#00000040,
#00000030,
#00000020,
#00000010,
#00000010,
#00000080
);

--callout-rgb: 238, 240, 241;
--callout-border-rgb: 172, 175, 176;
--card-rgb: 180, 185, 188;
--card-border-rgb: 131, 134, 135;
--container-grey-rgb: rgb(244, 244, 244);
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;

--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
--secondary-glow: linear-gradient(
to bottom right,
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0.3)
);

--tile-start-rgb: 2, 13, 46;
--tile-end-rgb: 2, 5, 19;
--tile-border: conic-gradient(
#ffffff80,
#ffffff40,
#ffffff30,
#ffffff20,
#ffffff10,
#ffffff10,
#ffffff80
);

--callout-rgb: 20, 20, 20;
--callout-border-rgb: 108, 108, 108;
--card-rgb: 100, 100, 100;
--card-border-rgb: 200, 200, 200;
}
}

* {
Expand Down
15 changes: 6 additions & 9 deletions src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter';
import { ThemeProvider } from '@mui/material/styles';
import theme from '@/theme';
import ThemeProvider from '@/providers/ThemeProvider';
import StoreProvider from '@/providers/StoreProvider';
import { NextIntlClientProvider, useMessages } from 'next-intl';
import pick from 'lodash.pick';
Expand All @@ -29,13 +28,11 @@ export default function RootLayout({
<html lang={locale}>
<body className={inter.className}>
<AppRouterCacheProvider>
<ThemeProvider theme={theme}>
<StoreProvider>
<NextIntlClientProvider messages={pick(messages, 'Dashboard')}>
{children}
</NextIntlClientProvider>
</StoreProvider>
</ThemeProvider>
<StoreProvider>
<NextIntlClientProvider messages={pick(messages, 'Dashboard')}>
<ThemeProvider>{children}</ThemeProvider>
</NextIntlClientProvider>
</StoreProvider>
</AppRouterCacheProvider>
</body>
</html>
Expand Down
37 changes: 37 additions & 0 deletions src/components/Settings/AppSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ import { styles } from './styles';
import { supportedLocales } from '@/intl/intl.constants';
import { startTransition } from 'react';
import { useRouter, usePathname } from '@/navigation';
import { useBoundStore } from '@/providers/StoreProvider';
import { useShallow } from 'zustand/react/shallow';

type ColorTheme = 'auto' | 'dark' | 'light';
const themeOptions = ['auto', 'dark', 'light'];

export default function AppSection() {
const router = useRouter();
const pathname = usePathname();
const messages = useTranslations('Settings');
const locale = useLocale();
const [theme, setTheme] = useBoundStore(
useShallow((state) => [state.theme, state.setTheme]),
);

const handleOnChange = (event: SelectChangeEvent<string>) => {
const nextLocale = event.target.value;
Expand Down Expand Up @@ -63,6 +71,35 @@ export default function AppSection() {
<ListItemText id={'labelId'} primary={messages('language')} />
</ListItemButton>
</ListItem>
<ListItem
disablePadding
secondaryAction={
<FormControl sx={styles.formControl} size="small">
<Select
labelId="theme-color-select"
id="theme-color-select"
value={theme}
onChange={(event) => {
const value = event.target.value;
setTheme(value as ColorTheme);
}}
>
{themeOptions.map((option) => (
<MenuItem key={option} value={option}>
{option.toUpperCase()}
</MenuItem>
))}
</Select>
</FormControl>
}
>
<ListItemButton>
<ListItemIcon>
<LanguageIcon />
</ListItemIcon>
<ListItemText id={'theme-switch'} primary={messages('theme')} />
</ListItemButton>
</ListItem>
</List>
);
}
3 changes: 2 additions & 1 deletion src/intl/cbuilder.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"user": "User",
"application": "Application",
"language": "Language",
"signOut": "Sign out"
"signOut": "Sign out",
"theme": "Theme"
}
}
28 changes: 28 additions & 0 deletions src/providers/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client'; // This directive ensures the component is treated as a client component

import React, { useMemo } from 'react';
import CssBaseline from '@mui/material/CssBaseline';
import {
ThemeProvider as MuiThemeProvider,
useMediaQuery,
} from '@mui/material';
import getTheme from '@/theme';
import { useBoundStore } from './StoreProvider';

const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
// Detect the system preference for dark mode
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');

const storeTheme = useBoundStore((state) => state.theme);
const colorTheme =
storeTheme !== 'auto' ? storeTheme : prefersDarkMode ? 'dark' : 'light';
const theme = useMemo(() => getTheme(colorTheme), [colorTheme]);
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
{children}
</MuiThemeProvider>
);
};

export default ThemeProvider;
10 changes: 10 additions & 0 deletions src/stores/dashboard-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ type DashboardRecord = {
board: BoardRecord | null;
};

type ColorTheme = 'auto' | 'dark' | 'light';

export type DashboardStoreRecord = {
hydrated: boolean;
isGenerationPending: boolean;
stashedDashboard: DashboardRecord;
theme: ColorTheme;
};

export type DashboardActions = {
setHydrated: () => void;
setGenerationPending: (pending: boolean) => void;
stashDashboard: () => void;
setTheme: (theme: ColorTheme) => void;
};
export type DashboardSlice = DashboardStoreRecord & DashboardActions;

Expand All @@ -30,6 +34,7 @@ export const defaultDashboardState: DashboardStoreRecord = {
prompt: null,
board: null,
},
theme: 'dark',
};

export const createDashboardSlice: StateCreator<
Expand Down Expand Up @@ -61,4 +66,9 @@ export const createDashboardSlice: StateCreator<
},
);
},
setTheme: (theme: ColorTheme) => {
set(() => ({ theme }), false, {
type: 'Dashboard/setTheme',
});
},
});
39 changes: 15 additions & 24 deletions src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
'use client';
import { createTheme } from '@mui/material/styles';
declare module '@mui/material/styles/createPalette' {
interface Palette {
custom: {
filledBackground: string;
};
}
interface PaletteOptions {
custom?: {
filledBackground?: string;
};
}
}

const theme = createTheme({
palette: {
primary: {
main: '#7b1fa2',
light: '#D7B3FF',
const getTheme = (mode: 'dark' | 'light') =>
createTheme({
palette: {
mode: mode,
primary: {
main: mode === 'dark' ? '#D7B3FF' : '#7b1fa2',
light: mode === 'dark' ? '#7b1fa2' : '#D7B3FF',
},
secondary: {
main: '#7b1fa2',
light: '#D7B3FF',
},
grey: { 100: mode === 'dark' ? 'rgba(255, 255, 255, 0.09)' : '#f5f5f5' },
},
custom: {
filledBackground: 'rgba(0, 0, 0, 0.06)',
},
},
});
});

export default theme;
export default getTheme;

0 comments on commit 87a2d15

Please sign in to comment.