Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[examples] Add dark mode example for Material UI + Pigment CSS #44480

Merged
merged 8 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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