Skip to content

Commit

Permalink
[examples] Add dark mode example for Material UI + Pigment CSS (#44480)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova authored Nov 21, 2024
1 parent 6aaa61f commit 4bed60a
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 14 deletions.
2 changes: 1 addition & 1 deletion examples/material-ui-pigment-css-nextjs-ts/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
4 changes: 3 additions & 1 deletion examples/material-ui-pigment-css-nextjs-ts/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const nextConfig = {};

export default withPigment(nextConfig, {
theme: createTheme({
cssVariables: true,
cssVariables: {
colorSchemeSelector: 'class',
},
colorSchemes: { light: true, dark: true },
typography: {
fontFamily: 'var(--font-roboto)',
Expand Down
20 changes: 9 additions & 11 deletions examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import * as React from 'react';
import type { Metadata } from 'next';
import { Roboto } from 'next/font/google';
import { cookies } from 'next/headers';
import '@mui/material-pigment-css/styles.css';

const roboto = Roboto({
subsets: ['latin'],
weight: ['400', '500', '700'],
display: 'swap',
variable: '--font-roboto',
});
import { ColorSchemeProvider } from '../components/ColorSchemeProvider';
import App from '../components/App';

export const metadata: Metadata = {
title: 'Material UI x Pigment CSS',
description: 'Generated by create next app',
};

export default function RootLayout({
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const cookieStore = await cookies();
const { value: colorScheme = 'light' } = cookieStore.get('colorScheme') ?? {};
return (
<html lang="en">
<body className={roboto.variable}>{children}</body>
<ColorSchemeProvider colorScheme={colorScheme}>
<App>{children}</App>
</ColorSchemeProvider>
</html>
);
}
14 changes: 14 additions & 0 deletions examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
'use client';
import * as React from 'react';
import DefaultPropsProvider from '@mui/material/DefaultPropsProvider';
import CssBaseline from '@mui/material/CssBaseline';
import IconButton from '@mui/material/IconButton';
import Container from '@mui/material-pigment-css/Container';
import Grid from '@mui/material-pigment-css/Grid';
import Stack from '@mui/material-pigment-css/Stack';
import Typography from '@mui/material/Typography';
import Chip from '@mui/material/Chip';
import { styled } from '@mui/material-pigment-css';
import { useColorScheme } from '../components/ColorSchemeProvider';

const Title = styled('div')(({ theme }) => ({
color: theme.vars.palette.text.primary,
Expand All @@ -16,6 +19,12 @@ const Title = styled('div')(({ theme }) => ({
}));

export default function Home() {
const { colorScheme, setColorScheme } = useColorScheme();

const toggleColorScheme = () => {
setColorScheme(colorScheme === 'dark' ? 'light' : 'dark');
};

return (
<main sx={{ minHeight: '100lvh', display: 'grid', placeItems: 'center' }}>
<DefaultPropsProvider
Expand All @@ -27,6 +36,11 @@ export default function Home() {
>
<CssBaseline />
<Container>
<div sx={{ position: 'absolute', top: 10, right: 10 }}>
<IconButton sx={{ fontSize: 20, px: 1.5 }} onClick={toggleColorScheme}>
{colorScheme === 'light' ? '🌙' : '🔆'}
</IconButton>
</div>
<Grid container spacing={{ xs: 2, sm: 3, md: 4 }}>
<Grid size={{ xs: 12, md: 6 }} sx={{ pl: 4.5 }}>
<Chip
Expand Down
18 changes: 18 additions & 0 deletions examples/material-ui-pigment-css-nextjs-ts/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';
import * as React from 'react';
import { Roboto } from 'next/font/google';
import { useColorScheme } from './ColorSchemeProvider';

const roboto = Roboto({
subsets: ['latin'],
weight: ['400', '500', '700'],
display: 'swap',
variable: '--font-roboto',
});

function App({ className, ...other }: React.PropsWithChildren<{ className?: string }>) {
const { colorScheme } = useColorScheme();
return <body {...other} className={`${roboto.variable} ${colorScheme}`} />;
}

export default App;
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client';
import * as React from 'react';

const ColorSchemeContext = React.createContext<{
colorScheme: string;
setColorScheme: React.Dispatch<React.SetStateAction<string>>;
}>({
colorScheme: 'dark',
setColorScheme: () => '',
});

function setCookie(name: string, value: string, days: number = 100) {
let expires = '';
if (days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
expires = `; expires=${date.toUTCString()}`;
}
document.cookie = `${name}=${value || ''}${expires}; path=/`;
}

export function ColorSchemeProvider({
colorScheme: initialColorScheme,
children,
}: React.PropsWithChildren<{ colorScheme: string }>) {
const [colorScheme, setColorScheme] = React.useState<string>(initialColorScheme);

const contextValue = React.useMemo(
() => ({ colorScheme, setColorScheme }),
[colorScheme, setColorScheme],
);

// Set the colorScheme in localStorage
React.useEffect(() => {
setCookie('colorScheme', colorScheme);
localStorage.setItem('colorScheme', colorScheme);
}, [colorScheme]);

// Handle when localStorage has changed
React.useEffect(() => {
const handleStorage = (event: StorageEvent) => {
const value = event.newValue;
if (
typeof event.key === 'string' &&
event.key === 'colorScheme' &&
typeof value === 'string'
) {
setColorScheme(value);
}
};
// For syncing color-scheme changes between iframes
window.addEventListener('storage', handleStorage);
return () => {
window.removeEventListener('storage', handleStorage);
};
}, [setColorScheme]);

return <ColorSchemeContext.Provider value={contextValue}>{children}</ColorSchemeContext.Provider>;
}

export const useColorScheme = () => {
return React.useContext(ColorSchemeContext);
};
3 changes: 2 additions & 1 deletion examples/material-ui-pigment-css-nextjs-ts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
],
"paths": {
"@/*": ["./src/*"]
}
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
Expand Down

0 comments on commit 4bed60a

Please sign in to comment.