From 4bed60a9e8ec86e4fe713a3af289ba97287d2a84 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Thu, 21 Nov 2024 11:32:45 +0100 Subject: [PATCH] [examples] Add dark mode example for Material UI + Pigment CSS (#44480) --- .../next-env.d.ts | 2 +- .../next.config.mjs | 4 +- .../src/app/layout.tsx | 20 +++--- .../src/app/page.tsx | 14 +++++ .../src/components/App.tsx | 18 ++++++ .../src/components/ColorSchemeProvider.tsx | 63 +++++++++++++++++++ .../tsconfig.json | 3 +- 7 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 examples/material-ui-pigment-css-nextjs-ts/src/components/App.tsx create mode 100644 examples/material-ui-pigment-css-nextjs-ts/src/components/ColorSchemeProvider.tsx diff --git a/examples/material-ui-pigment-css-nextjs-ts/next-env.d.ts b/examples/material-ui-pigment-css-nextjs-ts/next-env.d.ts index a4a7b3f5cfa2f9..40c3d68096c270 100644 --- a/examples/material-ui-pigment-css-nextjs-ts/next-env.d.ts +++ b/examples/material-ui-pigment-css-nextjs-ts/next-env.d.ts @@ -2,4 +2,4 @@ /// // 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. diff --git a/examples/material-ui-pigment-css-nextjs-ts/next.config.mjs b/examples/material-ui-pigment-css-nextjs-ts/next.config.mjs index 064c4bfb543ef2..5bc722ac72e0b6 100644 --- a/examples/material-ui-pigment-css-nextjs-ts/next.config.mjs +++ b/examples/material-ui-pigment-css-nextjs-ts/next.config.mjs @@ -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)', diff --git a/examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx b/examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx index f98f4082fb09b0..ab2f3e59d177ab 100644 --- a/examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx +++ b/examples/material-ui-pigment-css-nextjs-ts/src/app/layout.tsx @@ -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 ( - {children} + + {children} + ); } diff --git a/examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx b/examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx index 8e4da13a0cdadd..8bd74d2db8e1de 100644 --- a/examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx +++ b/examples/material-ui-pigment-css-nextjs-ts/src/app/page.tsx @@ -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, @@ -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 (
+
+ + {colorScheme === 'light' ? '🌙' : '🔆'} + +
) { + const { colorScheme } = useColorScheme(); + return ; +} + +export default App; diff --git a/examples/material-ui-pigment-css-nextjs-ts/src/components/ColorSchemeProvider.tsx b/examples/material-ui-pigment-css-nextjs-ts/src/components/ColorSchemeProvider.tsx new file mode 100644 index 00000000000000..ffd4f25ba29e05 --- /dev/null +++ b/examples/material-ui-pigment-css-nextjs-ts/src/components/ColorSchemeProvider.tsx @@ -0,0 +1,63 @@ +'use client'; +import * as React from 'react'; + +const ColorSchemeContext = React.createContext<{ + colorScheme: string; + setColorScheme: React.Dispatch>; +}>({ + 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(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 {children}; +} + +export const useColorScheme = () => { + return React.useContext(ColorSchemeContext); +}; diff --git a/examples/material-ui-pigment-css-nextjs-ts/tsconfig.json b/examples/material-ui-pigment-css-nextjs-ts/tsconfig.json index 264ef7bbd1ef91..ffbaaf135fb346 100644 --- a/examples/material-ui-pigment-css-nextjs-ts/tsconfig.json +++ b/examples/material-ui-pigment-css-nextjs-ts/tsconfig.json @@ -19,7 +19,8 @@ ], "paths": { "@/*": ["./src/*"] - } + }, + "target": "ES2017" }, "include": [ "next-env.d.ts",