From 62888701b66366eb7b39457403aa81c21538af49 Mon Sep 17 00:00:00 2001 From: Cano Date: Sun, 18 Feb 2024 15:30:49 +0900 Subject: [PATCH] using css vars provider (#161) --- src/components/generate.tsx | 2 +- src/core/theme.ts | 484 ++++++++++++++++++------------------ src/pages/_app.tsx | 20 +- src/pages/_document.tsx | 2 + 4 files changed, 255 insertions(+), 253 deletions(-) diff --git a/src/components/generate.tsx b/src/components/generate.tsx index f94cc7a..26a2445 100644 --- a/src/components/generate.tsx +++ b/src/components/generate.tsx @@ -11,7 +11,7 @@ const Output = styled(InputBase)(({ theme }) => ({ padding: "0 16px", height: "56px", borderRadius: "4px", - backgroundColor: theme.palette.surfaceVariant.main, + backgroundColor: theme.vars.palette.surfaceVariant.main, fontFamily: "monospace", })); diff --git a/src/core/theme.ts b/src/core/theme.ts index c25c209..14cbbf9 100644 --- a/src/core/theme.ts +++ b/src/core/theme.ts @@ -1,274 +1,272 @@ -import { hexFromArgb, Scheme } from "@material/material-color-utilities"; +import { Scheme, hexFromArgb } from "@material/material-color-utilities"; import { - alpha, - createTheme as createMuiTheme, - darken, - PaletteColor, - PaletteColorOptions, - PaletteMode, - PaletteOptions, - TypeBackground, + PaletteColorOptions, + PaletteMode, + PaletteOptions, + experimental_extendTheme as extendTheme, } from "@mui/material"; +import type {} from "@mui/material/themeCssVarsAugmentation"; type M3ColorSchemeKeys = - | "primary" - | "primaryContainer" - | "onPrimary" - | "onPrimaryContainer" - | "secondary" - | "secondaryContainer" - | "onSecondary" - | "onSecondaryContainer" - | "tertiary" - | "tertiaryContainer" - | "onTertiary" - | "onTertiaryContainer" - | "error" - | "errorContainer" - | "onError" - | "onErrorContainer" - | "background" - | "onBackground" - | "surface" - | "onSurface" - | "surfaceVariant" - | "onSurfaceVariant" - | "outline" - | "shadow" - | "inverseSurface" - | "inverseOnSurface" - | "inversePrimary"; + | "primary" + | "primaryContainer" + | "onPrimary" + | "onPrimaryContainer" + | "secondary" + | "secondaryContainer" + | "onSecondary" + | "onSecondaryContainer" + | "tertiary" + | "tertiaryContainer" + | "onTertiary" + | "onTertiaryContainer" + | "error" + | "errorContainer" + | "onError" + | "onErrorContainer" + | "background" + | "onBackground" + | "surface" + | "onSurface" + | "surfaceVariant" + | "onSurfaceVariant" + | "outline" + | "shadow" + | "inverseSurface" + | "inverseOnSurface" + | "inversePrimary"; // Augmentation MUI theme with Material 3 declare module "@mui/material/styles" { - interface PaletteOptions { - primary?: PaletteColorOptions; - primaryContainer?: PaletteColorOptions; - onPrimary?: PaletteColorOptions; - onPrimaryContainer?: PaletteColorOptions; - secondary?: PaletteColorOptions; - secondaryContainer?: PaletteColorOptions; - onSecondary?: PaletteColorOptions; - onSecondaryContainer?: PaletteColorOptions; - tertiary?: PaletteColorOptions; - tertiaryContainer?: PaletteColorOptions; - onTertiary?: PaletteColorOptions; - onTertiaryContainer?: PaletteColorOptions; - error?: PaletteColorOptions; - errorContainer?: PaletteColorOptions; - onError?: PaletteColorOptions; - onErrorContainer?: PaletteColorOptions; - background?: Partial; - onBackground?: PaletteColorOptions; - surface?: PaletteColorOptions; - onSurface?: PaletteColorOptions; - surfaceVariant?: PaletteColorOptions; - onSurfaceVariant?: PaletteColorOptions; - outline?: PaletteColorOptions; - shadow?: PaletteColorOptions; - inverseSurface?: PaletteColorOptions; - inverseOnSurface?: PaletteColorOptions; - inversePrimary?: PaletteColorOptions; - } + interface PaletteOptions { + primary?: PaletteColorOptions; + primaryContainer?: PaletteColorOptions; + onPrimary?: PaletteColorOptions; + onPrimaryContainer?: PaletteColorOptions; + secondary?: PaletteColorOptions; + secondaryContainer?: PaletteColorOptions; + onSecondary?: PaletteColorOptions; + onSecondaryContainer?: PaletteColorOptions; + tertiary?: PaletteColorOptions; + tertiaryContainer?: PaletteColorOptions; + onTertiary?: PaletteColorOptions; + onTertiaryContainer?: PaletteColorOptions; + error?: PaletteColorOptions; + errorContainer?: PaletteColorOptions; + onError?: PaletteColorOptions; + onErrorContainer?: PaletteColorOptions; + background?: Partial; + onBackground?: PaletteColorOptions; + surface?: PaletteColorOptions; + onSurface?: PaletteColorOptions; + surfaceVariant?: PaletteColorOptions; + onSurfaceVariant?: PaletteColorOptions; + outline?: PaletteColorOptions; + shadow?: PaletteColorOptions; + inverseSurface?: PaletteColorOptions; + inverseOnSurface?: PaletteColorOptions; + inversePrimary?: PaletteColorOptions; + } - interface Palette { - primary: PaletteColor; - primaryContainer: PaletteColor; - onPrimary: PaletteColor; - onPrimaryContainer: PaletteColor; - secondary: PaletteColor; - secondaryContainer: PaletteColor; - onSecondary: PaletteColor; - onSecondaryContainer: PaletteColor; - tertiary: PaletteColor; - tertiaryContainer: PaletteColor; - onTertiary: PaletteColor; - onTertiaryContainer: PaletteColor; - error: PaletteColor; - errorContainer: PaletteColor; - onError: PaletteColor; - onErrorContainer: PaletteColor; - background: TypeBackground; - onBackground: PaletteColor; - surface: PaletteColor; - onSurface: PaletteColor; - surfaceVariant: PaletteColor; - onSurfaceVariant: PaletteColor; - outline: PaletteColor; - shadow: PaletteColor; - inverseSurface: PaletteColor; - inverseOnSurface: PaletteColor; - inversePrimary: PaletteColor; - } + interface Palette { + primary: PaletteColor; + primaryContainer: PaletteColor; + onPrimary: PaletteColor; + onPrimaryContainer: PaletteColor; + secondary: PaletteColor; + secondaryContainer: PaletteColor; + onSecondary: PaletteColor; + onSecondaryContainer: PaletteColor; + tertiary: PaletteColor; + tertiaryContainer: PaletteColor; + onTertiary: PaletteColor; + onTertiaryContainer: PaletteColor; + error: PaletteColor; + errorContainer: PaletteColor; + onError: PaletteColor; + onErrorContainer: PaletteColor; + background: TypeBackground; + onBackground: PaletteColor; + surface: PaletteColor; + onSurface: PaletteColor; + surfaceVariant: PaletteColor; + onSurfaceVariant: PaletteColor; + outline: PaletteColor; + shadow: PaletteColor; + inverseSurface: PaletteColor; + inverseOnSurface: PaletteColor; + inversePrimary: PaletteColor; + } } // Custom Button variants declare module "@mui/material/Button" { - interface ButtonPropsVariantOverrides { - filledTonal: true; - } + interface ButtonPropsVariantOverrides { + filledTonal: true; + } } const SEED_COLOR = 0x6750a4; const createPalette = (mode: PaletteMode): PaletteOptions => { - const scheme = - mode === "light" ? Scheme.light(SEED_COLOR) : Scheme.dark(SEED_COLOR); + const scheme = + mode === "light" ? Scheme.light(SEED_COLOR) : Scheme.dark(SEED_COLOR); - const options: PaletteOptions = { mode: mode }; - Object.entries(scheme.toJSON()).forEach(([k, v]) => { - const key = k as M3ColorSchemeKeys; - const color = hexFromArgb(v); + const options: PaletteOptions = { mode: mode }; + Object.entries(scheme.toJSON()).forEach(([k, v]) => { + const key = k as M3ColorSchemeKeys; + const color = hexFromArgb(v); - if (key === "background") { - options[key] = { default: color, paper: color }; - } else { - options[key] = { main: color }; - } - }); + if (key === "background") { + options[key] = { default: color, paper: color }; + } else { + options[key] = { main: color }; + } + }); - return options; + return options; }; -export const createTheme = (mode: PaletteMode) => { - return createMuiTheme({ - palette: createPalette(mode), +export const createTheme = () => { + return extendTheme({ + colorSchemes: { + light: { palette: createPalette("light") }, + dark: { palette: createPalette("dark") }, + }, - components: { - MuiListSubheader: { - styleOverrides: { - root: { backgroundColor: "transparent" }, - }, - }, + components: { + MuiListSubheader: { + styleOverrides: { + root: { backgroundColor: "transparent" }, + }, + }, - MuiPaper: { - styleOverrides: { - root: { borderRadius: "28px" }, - }, - }, - MuiDialogTitle: { - styleOverrides: { - root: { padding: "24px", paddingBottom: "16px" }, - }, - }, - MuiDialogContent: { - styleOverrides: { - root: { padding: "24px", paddingTop: 0 }, - }, - }, - MuiDialogActions: { - styleOverrides: { - root: { padding: "24px", paddingTop: 0 }, - }, - }, + MuiPaper: { + styleOverrides: { + root: { borderRadius: "28px" }, + }, + }, + MuiDialogTitle: { + styleOverrides: { + root: { padding: "24px", paddingBottom: "16px" }, + }, + }, + MuiDialogContent: { + styleOverrides: { + root: { padding: "24px", paddingTop: 0 }, + }, + }, + MuiDialogActions: { + styleOverrides: { + root: { padding: "24px", paddingTop: 0 }, + }, + }, - MuiButton: { - styleOverrides: { - root: { - height: "40px", - minWidth: "48px", - borderRadius: "20px", - textTransform: "none", - }, - }, - variants: [ - { - props: { variant: "filledTonal" }, - style: ({ theme }) => ({ - padding: "0 24px", - backgroundColor: theme.palette.secondaryContainer.main, + MuiButton: { + styleOverrides: { + root: { + height: "40px", + minWidth: "48px", + borderRadius: "20px", + textTransform: "none", + }, + }, + variants: [ + { + props: { variant: "filledTonal" }, + style: ({ theme }) => { + console.log(theme.vars.palette.secondaryContainer); - "&:hover": { - backgroundColor: darken( - theme.palette.secondaryContainer.main, - theme.palette.action.hoverOpacity - ), - boxShadow: theme.shadows[1], - }, - }), - }, - { - props: { variant: "text" }, - style: ({ theme }) => ({ - padding: "0 12px", - color: theme.palette.primary.main, + return { + padding: "0 24px", + backgroundColor: theme.vars.palette.secondaryContainer.main, - "&:hover": { - backgroundColor: alpha( - theme.palette.primary.main, - theme.palette.action.hoverOpacity - ), - }, - }), - }, - ], - }, + "&:hover": { + backgroundColor: `rgb(${theme.vars.palette.secondaryContainer.mainChannel} / calc(1 - ${theme.vars.palette.action.hoverOpacity}))`, + boxShadow: theme.shadows[1], + }, + }; + }, + }, + { + props: { variant: "text" }, + style: ({ theme }) => ({ + padding: "0 12px", + color: theme.vars.palette.primary.main, - MuiSwitch: { - styleOverrides: { - root: ({ ownerState, theme }) => ({ - justifyContent: "center", - padding: 0, - width: 51, - height: 32, - borderRadius: 16, - border: `2px solid ${theme.palette.outline.main}`, - backgroundColor: theme.palette.surfaceVariant.main, - transition: theme.transitions.create( - ["background-color", "border-color"], - { - duration: "150ms", - } - ), + "&:hover": { + backgroundColor: `rgb(${theme.vars.palette.primary.mainChannel} / calc(1 - ${theme.vars.palette.action.hoverOpacity}))`, + }, + }), + }, + ], + }, - ...(ownerState.checked && { - borderColor: "transparent", - backgroundColor: theme.palette.primary.main, - }), - ...(ownerState.disabled && { - opacity: 0.3, - }), - }), - switchBase: () => ({ - position: "relative", - top: -6, - padding: 0, - width: 40, - height: 40, - transform: "translateX(-10px)", - "&.Mui-checked": { - transform: "translateX(10px)", - }, - }), - track: { - display: "none", - }, - thumb: ({ ownerState, theme }) => ({ - width: 16, - height: 16, - boxShadow: "none", - backgroundColor: theme.palette.outline.main, - transition: theme.transitions.create( - ["transform", "background-color"], - { - duration: "150ms", - } - ), + MuiSwitch: { + styleOverrides: { + root: ({ ownerState, theme }) => ({ + justifyContent: "center", + padding: 0, + width: 51, + height: 32, + borderRadius: 16, + border: `2px solid ${theme.vars.palette.outline.main}`, + backgroundColor: theme.vars.palette.surfaceVariant.main, + transition: theme.transitions.create( + ["background-color", "border-color"], + { + duration: "150ms", + }, + ), - // ...(ownerState && { - // backgroundColor: theme.palette.onPrimary.main, - // transform: "scale(1.5)", - // }), - ...(ownerState.checked && { - backgroundColor: theme.palette.onPrimary.main, - transform: "scale(1.5)", - }), - ...(ownerState.disabled && { - opacity: 0.3, - }), - }), - }, - }, - }, - }); + ...(ownerState.checked && { + borderColor: "transparent", + backgroundColor: theme.vars.palette.primary.main, + }), + ...(ownerState.disabled && { + opacity: 0.3, + }), + }), + switchBase: () => ({ + position: "relative", + top: -6, + padding: 0, + width: 40, + height: 40, + transform: "translateX(-10px)", + "&.Mui-checked": { + transform: "translateX(10px)", + }, + }), + track: { + display: "none", + }, + thumb: ({ ownerState, theme }) => ({ + width: 16, + height: 16, + boxShadow: "none", + backgroundColor: theme.vars.palette.outline.main, + transition: theme.transitions.create( + ["transform", "background-color"], + { + duration: "150ms", + }, + ), + + // ...(ownerState && { + // backgroundColor: theme.palette.onPrimary.main, + // transform: "scale(1.5)", + // }), + ...(ownerState.checked && { + backgroundColor: theme.vars.palette.onPrimary.main, + transform: "scale(1.5)", + }), + ...(ownerState.disabled && { + opacity: 0.3, + }), + }), + }, + }, + }, + }); }; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 65057d8..37a1c23 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,27 +1,29 @@ -import { CssBaseline, ThemeProvider, useMediaQuery } from "@mui/material"; +import { + CssBaseline, + Experimental_CssVarsProvider as CssVarsProvider, +} from "@mui/material"; import type { AppProps } from "next/app"; import Head from "next/head"; -import { useMemo } from "react"; import { createTheme } from "../core/theme"; function MyApp({ Component, pageProps }: AppProps) { - const isLightScheme = useMediaQuery("(prefers-color-scheme:light)"); - const mode = isLightScheme ? "light" : "dark"; - - const theme = useMemo(() => createTheme(mode), [mode]); + const theme = createTheme(); return ( <> - + - + - + ); } diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index e23a460..0e31c01 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -1,3 +1,4 @@ +import { getInitColorSchemeScript } from "@mui/material"; import Document, { Head, Html, Main, NextScript } from "next/document"; export default class MyDocument extends Document { @@ -18,6 +19,7 @@ export default class MyDocument extends Document { + {getInitColorSchemeScript()}