diff --git a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js index c44cd5f38ef..6f63933ad51 100644 --- a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.js @@ -3,11 +3,7 @@ import { AppProvider } from '@toolpad/core/AppProvider'; import { SignInPage } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; -const providers = [ - { id: 'github', name: 'GitHub' }, - { id: 'google', name: 'Google' }, -]; - +const providers = [{ id: 'credentials', name: 'Credentials' }]; // preview-start const BRANDING = { logo: ( diff --git a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx index a21cbf4b8d3..8b54d4fcc3e 100644 --- a/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/BrandingSignInPage.tsx @@ -3,10 +3,7 @@ import { AppProvider } from '@toolpad/core/AppProvider'; import { SignInPage, type AuthProvider } from '@toolpad/core/SignInPage'; import { useTheme } from '@mui/material/styles'; -const providers = [ - { id: 'github', name: 'GitHub' }, - { id: 'google', name: 'Google' }, -]; +const providers = [{ id: 'credentials', name: 'Credentials' }]; // preview-start const BRANDING = { logo: ( diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js index 5173ec90edc..9b75f82997b 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js +++ b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.js @@ -7,6 +7,7 @@ import { TextField, InputAdornment, Link, + Alert, IconButton, } from '@mui/material'; import AccountCircle from '@mui/icons-material/AccountCircle'; @@ -95,7 +96,7 @@ function CustomButton() { fullWidth sx={{ my: 2 }} > - Sign In + Log In ); } @@ -116,6 +117,18 @@ function ForgotPasswordLink() { ); } +function Title() { + return

Login

; +} + +function Subtitle() { + return ( + + We are investigating an ongoing outage. + + ); +} + export default function SlotsSignIn() { const theme = useTheme(); return ( @@ -123,10 +136,12 @@ export default function SlotsSignIn() { alert( - `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}`, + `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}`, ) } slots={{ + title: Title, + subtitle: Subtitle, emailField: CustomEmailField, passwordField: CustomPasswordField, submitButton: CustomButton, diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx index fdea6fc5db8..04472072364 100644 --- a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx @@ -7,6 +7,7 @@ import { TextField, InputAdornment, Link, + Alert, IconButton, } from '@mui/material'; import AccountCircle from '@mui/icons-material/AccountCircle'; @@ -95,7 +96,7 @@ function CustomButton() { fullWidth sx={{ my: 2 }} > - Sign In + Log In ); } @@ -116,6 +117,18 @@ function ForgotPasswordLink() { ); } +function Title() { + return

Login

; +} + +function Subtitle() { + return ( + + We are investigating an ongoing outage. + + ); +} + export default function SlotsSignIn() { const theme = useTheme(); return ( @@ -123,10 +136,12 @@ export default function SlotsSignIn() { alert( - `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}`, + `Logging in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}`, ) } slots={{ + title: Title, + subtitle: Subtitle, emailField: CustomEmailField, passwordField: CustomPasswordField, submitButton: CustomButton, diff --git a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx.preview deleted file mode 100644 index 136df8f726a..00000000000 --- a/docs/data/toolpad/core/components/sign-in-page/SlotsSignIn.tsx.preview +++ /dev/null @@ -1,15 +0,0 @@ - - alert( - `Signing in with "${provider.name}" and credentials: ${formData.get('email')}, ${formData.get('password')}`, - ) - } - slots={{ - emailField: CustomEmailField, - passwordField: CustomPasswordField, - submitButton: CustomButton, - signUpLink: SignUpLink, - forgotPasswordLink: ForgotPasswordLink, - }} - providers={providers} -/> \ No newline at end of file diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js index deb2dd12dd8..824dda0beff 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.js @@ -3,7 +3,7 @@ import { AppProvider } from '@toolpad/core/AppProvider'; import { SignInPage } from '@toolpad/core/SignInPage'; import { createTheme } from '@mui/material/styles'; import { useColorSchemeShim } from 'docs/src/modules/components/ThemeContext'; -import { getDesignTokens } from './brandingTheme'; +import { getDesignTokens, inputsCustomizations } from './customTheme'; const providers = [ { id: 'github', name: 'GitHub' }, @@ -32,6 +32,9 @@ export default function ThemeSignInPage() { ...brandingDesignTokens.palette, mode: calculatedMode, }, + components: { + ...inputsCustomizations, + }, }); // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx index 797983ef77a..7d8ef141527 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx @@ -3,7 +3,7 @@ import { AppProvider } from '@toolpad/core/AppProvider'; import { SignInPage, type AuthProvider } from '@toolpad/core/SignInPage'; import { createTheme } from '@mui/material/styles'; import { useColorSchemeShim } from 'docs/src/modules/components/ThemeContext'; -import { getDesignTokens } from './brandingTheme'; +import { getDesignTokens, inputsCustomizations } from './customTheme'; const providers = [ { id: 'github', name: 'GitHub' }, @@ -32,6 +32,9 @@ export default function ThemeSignInPage() { ...brandingDesignTokens.palette, mode: calculatedMode, }, + components: { + ...inputsCustomizations, + }, }); // preview-end diff --git a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview index 01eecbdf4fe..b654f182518 100644 --- a/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview +++ b/docs/data/toolpad/core/components/sign-in-page/ThemeSignInPage.tsx.preview @@ -4,6 +4,9 @@ const THEME = createTheme({ ...brandingDesignTokens.palette, mode: calculatedMode, }, + components: { + ...inputsCustomizations, + }, }); // ... diff --git a/docs/data/toolpad/core/components/sign-in-page/brandingTheme.js b/docs/data/toolpad/core/components/sign-in-page/brandingTheme.js deleted file mode 100644 index 3c4e67a9552..00000000000 --- a/docs/data/toolpad/core/components/sign-in-page/brandingTheme.js +++ /dev/null @@ -1,242 +0,0 @@ -import { createTheme, alpha } from '@mui/material/styles'; - -const defaultTheme = createTheme(); - -const blue = { - 50: '#F0F7FF', - 100: '#C2E0FF', - 200: '#99CCF3', - 300: '#66B2FF', - 400: '#3399FF', - main: '#007FFF', - 500: '#007FFF', - 600: '#0072E5', // vs blueDark 900: WCAG 4.6 AAA (large), APCA 36 Not for reading text - 700: '#0059B2', - 800: '#004C99', - 900: '#003A75', -}; -const blueDark = { - 50: '#E2EDF8', - 100: '#CEE0F3', - 200: '#91B9E3', - 300: '#5090D3', - main: '#5090D3', - 400: '#265D97', - 500: '#1E4976', - 600: '#173A5E', - 700: '#132F4C', // contrast 13.64:1 - 800: '#001E3C', - 900: '#0A1929', -}; -const grey = { - 50: '#F3F6F9', - 100: '#E7EBF0', - 200: '#E0E3E7', - 300: '#CDD2D7', // vs blueDark 900: WCAG 11.6 AAA, APCA 78 Best for text - 400: '#B2BAC2', // vs blueDark 900: WCAG 9 AAA, APCA 63.3 Ok for text - 500: '#A0AAB4', // vs blueDark 900: WCAG 7.5 AAA, APCA 54.3 Only for large text - 600: '#6F7E8C', // vs white bg: WCAG 4.1 AA, APCA 68.7 Ok for text - 700: '#3E5060', // vs white bg: WCAG 8.3 AAA, APCA 88.7 Best for text - 800: '#2D3843', // vs white bg: WCAG 11.9 AAA, APCA 97.3 Best for text - 900: '#1A2027', -}; - -const systemFont = [ - '-apple-system', - 'BlinkMacSystemFont', - '"Segoe UI"', - 'Roboto', - '"Helvetica Neue"', - 'Arial', - 'sans-serif', - '"Apple Color Emoji"', - '"Segoe UI Emoji"', - '"Segoe UI Symbol"', -]; - -export const getDesignTokens = (mode) => ({ - palette: { - primary: { - ...blue, - ...(mode === 'dark' && { - main: blue[400], - }), - }, - divider: mode === 'dark' ? alpha(blue[100], 0.08) : grey[100], - primaryDark: blueDark, - mode, - ...(mode === 'dark' && { - background: { - default: blueDark[800], - paper: blueDark[900], - }, - }), - common: { - black: '#1D1D1D', - }, - text: { - ...(mode === 'light' && { - primary: grey[900], - secondary: grey[700], - }), - ...(mode === 'dark' && { - primary: '#fff', - secondary: grey[400], - }), - }, - grey: { - ...(mode === 'light' && { - main: grey[100], - contrastText: grey[600], - }), - ...(mode === 'dark' && { - main: blueDark[700], - contrastText: grey[600], - }), - }, - error: { - 50: '#FFF0F1', - 100: '#FFDBDE', - 200: '#FFBDC2', - 300: '#FF99A2', - 400: '#FF7A86', - 500: '#FF505F', - main: '#EB0014', // contrast 4.63:1 - 600: '#EB0014', - 700: '#C70011', - 800: '#94000D', - 900: '#570007', - }, - success: { - 50: '#E9FBF0', - 100: '#C6F6D9', - 200: '#9AEFBC', - 300: '#6AE79C', - 400: '#3EE07F', - 500: '#21CC66', - 600: '#1DB45A', - ...(mode === 'light' && { - main: '#1AA251', // contrast 3.31:1 - }), - ...(mode === 'dark' && { - main: '#1DB45A', // contrast 6.17:1 (blueDark.800) - }), - 700: '#1AA251', - 800: '#178D46', - 900: '#0F5C2E', - }, - warning: { - 50: '#FFF9EB', - 100: '#FFF3C1', - 200: '#FFECA1', - 300: '#FFDC48', // vs blueDark900: WCAG 10.4 AAA, APCA 72 Ok for text - 400: '#F4C000', // vs blueDark900: WCAG 6.4 AA normal, APCA 48 Only large text - 500: '#DEA500', // vs blueDark900: WCAG 8 AAA normal, APCA 58 Only large text - main: '#DEA500', - 600: '#D18E00', // vs blueDark900: WCAG 6.4 AA normal, APCA 48 Only large text - 700: '#AB6800', // vs white bg: WCAG 4.4 AA large, APCA 71 Ok for text - 800: '#8C5800', // vs white bg: WCAG 5.9 AAA large, APCA 80 Best for text - 900: '#5A3600', // vs white bg: WCAG 10.7 AAA, APCA 95 Best for text - }, - action: { - ...(mode === 'dark' && { - hoverOpacity: 0.08, - active: grey[700], - disabled: grey[200], - }), - ...(mode === 'light' && { - hoverOpacity: 0.04, - active: grey[700], - disabled: alpha(grey[700], 0.3), - }), - }, - }, - shape: { - borderRadius: 10, - }, - spacing: 10, - typography: { - fontFamily: ['"IBM Plex Sans"', ...systemFont].join(','), - fontFamilyCode: [ - 'Consolas', - 'Menlo', - 'Monaco', - 'Andale Mono', - 'Ubuntu Mono', - 'monospace', - ].join(','), - fontFamilyTagline: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontFamilySystem: systemFont.join(','), - fontWeightSemiBold: 600, - fontWeightExtraBold: 800, - h1: { - fontFamily: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontSize: 'clamp(2.625rem, 1.2857rem + 3.5714vw, 4rem)', - fontWeight: 800, - lineHeight: 78 / 70, - ...(mode === 'light' && { - color: blueDark[900], - }), - }, - h2: { - fontFamily: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontSize: 'clamp(1.5rem, 0.9643rem + 1.4286vw, 2.25rem)', - fontWeight: 800, - lineHeight: 44 / 36, - color: mode === 'dark' ? grey[100] : blueDark[700], - }, - h3: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(36), - lineHeight: 44 / 36, - letterSpacing: 0.2, - }, - h4: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(28), - lineHeight: 42 / 28, - letterSpacing: 0.2, - }, - h5: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(24), - lineHeight: 36 / 24, - letterSpacing: 0.1, - color: mode === 'dark' ? blue[300] : blue.main, - }, - h6: { - fontSize: defaultTheme.typography.pxToRem(20), - lineHeight: 30 / 20, - }, - button: { - textTransform: 'initial', - fontWeight: 700, - letterSpacing: 0, - }, - subtitle1: { - fontSize: defaultTheme.typography.pxToRem(18), - lineHeight: 24 / 18, - letterSpacing: 0, - fontWeight: 500, - }, - body1: { - fontSize: defaultTheme.typography.pxToRem(16), // 16px - lineHeight: 24 / 16, - letterSpacing: 0, - }, - body2: { - fontSize: defaultTheme.typography.pxToRem(14), // 14px - lineHeight: 21 / 14, - letterSpacing: 0, - }, - caption: { - fontSize: defaultTheme.typography.pxToRem(12), // 12px - lineHeight: 18 / 12, - letterSpacing: 0, - fontWeight: 700, - }, - allVariants: { - scrollMarginTop: 'calc(var(--MuiDocs-header-height) + 32px)', - }, - }, -}); diff --git a/docs/data/toolpad/core/components/sign-in-page/brandingTheme.ts b/docs/data/toolpad/core/components/sign-in-page/brandingTheme.ts deleted file mode 100644 index 4fffbe86298..00000000000 --- a/docs/data/toolpad/core/components/sign-in-page/brandingTheme.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { createTheme, ThemeOptions, alpha } from '@mui/material/styles'; - -const defaultTheme = createTheme(); - -const blue = { - 50: '#F0F7FF', - 100: '#C2E0FF', - 200: '#99CCF3', - 300: '#66B2FF', - 400: '#3399FF', - main: '#007FFF', - 500: '#007FFF', - 600: '#0072E5', // vs blueDark 900: WCAG 4.6 AAA (large), APCA 36 Not for reading text - 700: '#0059B2', - 800: '#004C99', - 900: '#003A75', -}; -const blueDark = { - 50: '#E2EDF8', - 100: '#CEE0F3', - 200: '#91B9E3', - 300: '#5090D3', - main: '#5090D3', - 400: '#265D97', - 500: '#1E4976', - 600: '#173A5E', - 700: '#132F4C', // contrast 13.64:1 - 800: '#001E3C', - 900: '#0A1929', -}; -const grey = { - 50: '#F3F6F9', - 100: '#E7EBF0', - 200: '#E0E3E7', - 300: '#CDD2D7', // vs blueDark 900: WCAG 11.6 AAA, APCA 78 Best for text - 400: '#B2BAC2', // vs blueDark 900: WCAG 9 AAA, APCA 63.3 Ok for text - 500: '#A0AAB4', // vs blueDark 900: WCAG 7.5 AAA, APCA 54.3 Only for large text - 600: '#6F7E8C', // vs white bg: WCAG 4.1 AA, APCA 68.7 Ok for text - 700: '#3E5060', // vs white bg: WCAG 8.3 AAA, APCA 88.7 Best for text - 800: '#2D3843', // vs white bg: WCAG 11.9 AAA, APCA 97.3 Best for text - 900: '#1A2027', -}; - -const systemFont = [ - '-apple-system', - 'BlinkMacSystemFont', - '"Segoe UI"', - 'Roboto', - '"Helvetica Neue"', - 'Arial', - 'sans-serif', - '"Apple Color Emoji"', - '"Segoe UI Emoji"', - '"Segoe UI Symbol"', -]; - -export const getDesignTokens = (mode: 'light' | 'dark') => - ({ - palette: { - primary: { - ...blue, - ...(mode === 'dark' && { - main: blue[400], - }), - }, - divider: mode === 'dark' ? alpha(blue[100], 0.08) : grey[100], - primaryDark: blueDark, - mode, - ...(mode === 'dark' && { - background: { - default: blueDark[800], - paper: blueDark[900], - }, - }), - common: { - black: '#1D1D1D', - }, - text: { - ...(mode === 'light' && { - primary: grey[900], - secondary: grey[700], - }), - ...(mode === 'dark' && { - primary: '#fff', - secondary: grey[400], - }), - }, - grey: { - ...(mode === 'light' && { - main: grey[100], - contrastText: grey[600], - }), - ...(mode === 'dark' && { - main: blueDark[700], - contrastText: grey[600], - }), - }, - error: { - 50: '#FFF0F1', - 100: '#FFDBDE', - 200: '#FFBDC2', - 300: '#FF99A2', - 400: '#FF7A86', - 500: '#FF505F', - main: '#EB0014', // contrast 4.63:1 - 600: '#EB0014', - 700: '#C70011', - 800: '#94000D', - 900: '#570007', - }, - success: { - 50: '#E9FBF0', - 100: '#C6F6D9', - 200: '#9AEFBC', - 300: '#6AE79C', - 400: '#3EE07F', - 500: '#21CC66', - 600: '#1DB45A', - ...(mode === 'light' && { - main: '#1AA251', // contrast 3.31:1 - }), - ...(mode === 'dark' && { - main: '#1DB45A', // contrast 6.17:1 (blueDark.800) - }), - 700: '#1AA251', - 800: '#178D46', - 900: '#0F5C2E', - }, - warning: { - 50: '#FFF9EB', - 100: '#FFF3C1', - 200: '#FFECA1', - 300: '#FFDC48', // vs blueDark900: WCAG 10.4 AAA, APCA 72 Ok for text - 400: '#F4C000', // vs blueDark900: WCAG 6.4 AA normal, APCA 48 Only large text - 500: '#DEA500', // vs blueDark900: WCAG 8 AAA normal, APCA 58 Only large text - main: '#DEA500', - 600: '#D18E00', // vs blueDark900: WCAG 6.4 AA normal, APCA 48 Only large text - 700: '#AB6800', // vs white bg: WCAG 4.4 AA large, APCA 71 Ok for text - 800: '#8C5800', // vs white bg: WCAG 5.9 AAA large, APCA 80 Best for text - 900: '#5A3600', // vs white bg: WCAG 10.7 AAA, APCA 95 Best for text - }, - action: { - ...(mode === 'dark' && { - hoverOpacity: 0.08, - active: grey[700], - disabled: grey[200], - }), - ...(mode === 'light' && { - hoverOpacity: 0.04, - active: grey[700], - disabled: alpha(grey[700], 0.3), - }), - }, - }, - shape: { - borderRadius: 10, - }, - spacing: 10, - typography: { - fontFamily: ['"IBM Plex Sans"', ...systemFont].join(','), - fontFamilyCode: [ - 'Consolas', - 'Menlo', - 'Monaco', - 'Andale Mono', - 'Ubuntu Mono', - 'monospace', - ].join(','), - fontFamilyTagline: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontFamilySystem: systemFont.join(','), - fontWeightSemiBold: 600, - fontWeightExtraBold: 800, - h1: { - fontFamily: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontSize: 'clamp(2.625rem, 1.2857rem + 3.5714vw, 4rem)', - fontWeight: 800, - lineHeight: 78 / 70, - ...(mode === 'light' && { - color: blueDark[900], - }), - }, - h2: { - fontFamily: ['"PlusJakartaSans-ExtraBold"', ...systemFont].join(','), - fontSize: 'clamp(1.5rem, 0.9643rem + 1.4286vw, 2.25rem)', - fontWeight: 800, - lineHeight: 44 / 36, - color: mode === 'dark' ? grey[100] : blueDark[700], - }, - h3: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(36), - lineHeight: 44 / 36, - letterSpacing: 0.2, - }, - h4: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(28), - lineHeight: 42 / 28, - letterSpacing: 0.2, - }, - h5: { - fontFamily: ['"PlusJakartaSans-Bold"', ...systemFont].join(','), - fontSize: defaultTheme.typography.pxToRem(24), - lineHeight: 36 / 24, - letterSpacing: 0.1, - color: mode === 'dark' ? blue[300] : blue.main, - }, - h6: { - fontSize: defaultTheme.typography.pxToRem(20), - lineHeight: 30 / 20, - }, - button: { - textTransform: 'initial', - fontWeight: 700, - letterSpacing: 0, - }, - subtitle1: { - fontSize: defaultTheme.typography.pxToRem(18), - lineHeight: 24 / 18, - letterSpacing: 0, - fontWeight: 500, - }, - body1: { - fontSize: defaultTheme.typography.pxToRem(16), // 16px - lineHeight: 24 / 16, - letterSpacing: 0, - }, - body2: { - fontSize: defaultTheme.typography.pxToRem(14), // 14px - lineHeight: 21 / 14, - letterSpacing: 0, - }, - caption: { - fontSize: defaultTheme.typography.pxToRem(12), // 12px - lineHeight: 18 / 12, - letterSpacing: 0, - fontWeight: 700, - }, - allVariants: { - scrollMarginTop: 'calc(var(--MuiDocs-header-height) + 32px)', - }, - }, - }) as ThemeOptions; diff --git a/docs/data/toolpad/core/components/sign-in-page/customTheme.js b/docs/data/toolpad/core/components/sign-in-page/customTheme.js new file mode 100644 index 00000000000..4aff672b14e --- /dev/null +++ b/docs/data/toolpad/core/components/sign-in-page/customTheme.js @@ -0,0 +1,552 @@ +import * as React from 'react'; + +import { alpha, createTheme } from '@mui/material/styles'; +import { outlinedInputClasses } from '@mui/material/OutlinedInput'; +import CheckBoxOutlineBlankRoundedIcon from '@mui/icons-material/CheckBoxOutlineBlankRounded'; +import CheckRoundedIcon from '@mui/icons-material/CheckRounded'; +import RemoveRoundedIcon from '@mui/icons-material/RemoveRounded'; + +const defaultTheme = createTheme(); + +const customShadows = [...defaultTheme.shadows]; + +export const brand = { + 50: 'hsl(210, 100%, 95%)', + 100: 'hsl(210, 100%, 92%)', + 200: 'hsl(210, 100%, 80%)', + 300: 'hsl(210, 100%, 65%)', + 400: 'hsl(210, 98%, 48%)', + 500: 'hsl(210, 98%, 42%)', + 600: 'hsl(210, 98%, 55%)', + 700: 'hsl(210, 100%, 35%)', + 800: 'hsl(210, 100%, 16%)', + 900: 'hsl(210, 100%, 21%)', +}; + +export const gray = { + 50: 'hsl(220, 35%, 97%)', + 100: 'hsl(220, 30%, 94%)', + 200: 'hsl(220, 20%, 88%)', + 300: 'hsl(220, 20%, 80%)', + 400: 'hsl(220, 20%, 65%)', + 500: 'hsl(220, 20%, 42%)', + 600: 'hsl(220, 20%, 35%)', + 700: 'hsl(220, 20%, 25%)', + 800: 'hsl(220, 30%, 6%)', + 900: 'hsl(220, 35%, 3%)', +}; + +export const green = { + 50: 'hsl(120, 80%, 98%)', + 100: 'hsl(120, 75%, 94%)', + 200: 'hsl(120, 75%, 87%)', + 300: 'hsl(120, 61%, 77%)', + 400: 'hsl(120, 44%, 53%)', + 500: 'hsl(120, 59%, 30%)', + 600: 'hsl(120, 70%, 25%)', + 700: 'hsl(120, 75%, 16%)', + 800: 'hsl(120, 84%, 10%)', + 900: 'hsl(120, 87%, 6%)', +}; + +export const orange = { + 50: 'hsl(45, 100%, 97%)', + 100: 'hsl(45, 92%, 90%)', + 200: 'hsl(45, 94%, 80%)', + 300: 'hsl(45, 90%, 65%)', + 400: 'hsl(45, 90%, 40%)', + 500: 'hsl(45, 90%, 35%)', + 600: 'hsl(45, 91%, 25%)', + 700: 'hsl(45, 94%, 20%)', + 800: 'hsl(45, 95%, 16%)', + 900: 'hsl(45, 93%, 12%)', +}; + +export const red = { + 50: 'hsl(0, 100%, 97%)', + 100: 'hsl(0, 92%, 90%)', + 200: 'hsl(0, 94%, 80%)', + 300: 'hsl(0, 90%, 65%)', + 400: 'hsl(0, 90%, 40%)', + 500: 'hsl(0, 90%, 30%)', + 600: 'hsl(0, 91%, 25%)', + 700: 'hsl(0, 94%, 18%)', + 800: 'hsl(0, 95%, 12%)', + 900: 'hsl(0, 93%, 6%)', +}; + +export const getDesignTokens = (mode) => { + customShadows[1] = + mode === 'dark' + ? 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px' + : 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px'; + + customShadows[4] = + '0px 5px 15px rgba(9, 11, 17, 0.05), 0px 15px 35px -5px rgba(19, 23, 32, 0.05)'; + + return { + palette: { + mode, + primary: { + light: brand[200], + main: brand[400], + dark: brand[700], + contrastText: brand[50], + ...(mode === 'dark' && { + contrastText: brand[50], + light: brand[300], + main: brand[400], + dark: brand[700], + }), + }, + info: { + light: brand[100], + main: brand[300], + dark: brand[600], + contrastText: gray[50], + ...(mode === 'dark' && { + contrastText: brand[300], + light: brand[500], + main: brand[700], + dark: brand[900], + }), + }, + warning: { + light: orange[300], + main: orange[400], + dark: orange[800], + ...(mode === 'dark' && { + light: orange[400], + main: orange[500], + dark: orange[700], + }), + }, + error: { + light: red[300], + main: red[400], + dark: red[800], + ...(mode === 'dark' && { + light: red[400], + main: red[500], + dark: red[700], + }), + }, + success: { + light: green[300], + main: green[400], + dark: green[800], + ...(mode === 'dark' && { + light: green[400], + main: green[500], + dark: green[700], + }), + }, + grey: { + ...gray, + }, + divider: mode === 'dark' ? alpha(gray[700], 0.6) : alpha(gray[300], 0.4), + background: { + default: 'hsl(0, 0%, 99%)', + paper: 'hsl(220, 35%, 97%)', + ...(mode === 'dark' && { + default: gray[900], + paper: 'hsl(220, 30%, 7%)', + }), + }, + text: { + primary: gray[800], + secondary: gray[600], + warning: orange[400], + ...(mode === 'dark' && { + primary: 'hsl(0, 0%, 100%)', + secondary: gray[400], + }), + }, + action: { + hover: alpha(gray[200], 0.2), + selected: `${alpha(gray[200], 0.3)}`, + ...(mode === 'dark' && { + hover: alpha(gray[600], 0.2), + selected: alpha(gray[600], 0.3), + }), + }, + }, + typography: { + h1: { + fontSize: defaultTheme.typography.pxToRem(48), + fontWeight: 600, + lineHeight: 1.2, + letterSpacing: -0.5, + }, + h2: { + fontSize: defaultTheme.typography.pxToRem(36), + fontWeight: 600, + lineHeight: 1.2, + }, + h3: { + fontSize: defaultTheme.typography.pxToRem(30), + lineHeight: 1.2, + }, + h4: { + fontSize: defaultTheme.typography.pxToRem(24), + fontWeight: 600, + lineHeight: 1.5, + }, + h5: { + fontSize: defaultTheme.typography.pxToRem(20), + fontWeight: 600, + }, + h6: { + fontSize: defaultTheme.typography.pxToRem(18), + fontWeight: 600, + }, + subtitle1: { + fontSize: defaultTheme.typography.pxToRem(18), + }, + subtitle2: { + fontSize: defaultTheme.typography.pxToRem(14), + fontWeight: 500, + }, + body1: { + fontSize: defaultTheme.typography.pxToRem(14), + }, + body2: { + fontSize: defaultTheme.typography.pxToRem(14), + fontWeight: 400, + }, + caption: { + fontSize: defaultTheme.typography.pxToRem(12), + fontWeight: 400, + }, + }, + shape: { + borderRadius: 8, + }, + shadows: customShadows, + }; +}; + +export const inputsCustomizations = { + MuiButtonBase: { + defaultProps: { + disableTouchRipple: true, + disableRipple: true, + }, + styleOverrides: { + root: ({ theme }) => ({ + boxSizing: 'border-box', + transition: 'all 100ms ease-in', + '&:focus-visible': { + outline: `3px solid ${alpha(theme.palette.primary.main, 0.5)}`, + outlineOffset: '2px', + }, + }), + }, + }, + MuiButton: { + styleOverrides: { + root: ({ theme }) => ({ + boxShadow: 'none', + borderRadius: theme.shape.borderRadius, + textTransform: 'none', + variants: [ + { + props: { + size: 'small', + }, + style: { + height: '2.25rem', + padding: '8px 12px', + }, + }, + { + props: { + size: 'medium', + }, + style: { + height: '2.5rem', // 40px + }, + }, + { + props: { + color: 'primary', + variant: 'contained', + }, + style: { + color: 'white', + backgroundColor: gray[900], + backgroundImage: `linear-gradient(to bottom, ${gray[700]}, ${gray[800]})`, + boxShadow: `inset 0 1px 0 ${gray[600]}, inset 0 -1px 0 1px hsl(220, 0%, 0%)`, + border: `1px solid ${gray[700]}`, + '&:hover': { + backgroundImage: 'none', + backgroundColor: gray[700], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: gray[800], + }, + ...theme.applyStyles('dark', { + color: 'black', + backgroundColor: gray[50], + backgroundImage: `linear-gradient(to bottom, ${gray[100]}, ${gray[50]})`, + boxShadow: 'inset 0 -1px 0 hsl(220, 30%, 80%)', + border: `1px solid ${gray[50]}`, + '&:hover': { + backgroundImage: 'none', + backgroundColor: gray[300], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: gray[400], + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'contained', + }, + style: { + color: 'white', + backgroundColor: brand[300], + backgroundImage: `linear-gradient(to bottom, ${alpha(brand[400], 0.8)}, ${brand[500]})`, + boxShadow: `inset 0 2px 0 ${alpha(brand[200], 0.2)}, inset 0 -2px 0 ${alpha(brand[700], 0.4)}`, + border: `1px solid ${brand[500]}`, + '&:hover': { + backgroundColor: brand[700], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: brand[700], + backgroundImage: 'none', + }, + }, + }, + { + props: { + variant: 'outlined', + }, + style: { + color: theme.palette.text.primary, + border: '1px solid', + borderColor: gray[200], + backgroundColor: alpha(gray[50], 0.3), + '&:hover': { + backgroundColor: gray[100], + borderColor: gray[300], + }, + '&:active': { + backgroundColor: gray[200], + }, + ...theme.applyStyles('dark', { + backgroundColor: gray[800], + borderColor: gray[700], + '&:hover': { + backgroundColor: gray[900], + borderColor: gray[600], + }, + '&:active': { + backgroundColor: gray[900], + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'outlined', + }, + style: { + color: brand[700], + border: '1px solid', + borderColor: brand[200], + backgroundColor: brand[50], + '&:hover': { + backgroundColor: brand[100], + borderColor: brand[400], + }, + '&:active': { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles('dark', { + color: brand[50], + border: '1px solid', + borderColor: brand[900], + backgroundColor: alpha(brand[900], 0.3), + '&:hover': { + borderColor: brand[700], + backgroundColor: alpha(brand[900], 0.6), + }, + '&:active': { + backgroundColor: alpha(brand[900], 0.5), + }, + }), + }, + }, + { + props: { + variant: 'text', + }, + style: { + color: gray[600], + '&:hover': { + backgroundColor: gray[100], + }, + '&:active': { + backgroundColor: gray[200], + }, + ...theme.applyStyles('dark', { + color: gray[50], + '&:hover': { + backgroundColor: gray[700], + }, + '&:active': { + backgroundColor: alpha(gray[700], 0.7), + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'text', + }, + style: { + color: brand[700], + '&:hover': { + backgroundColor: alpha(brand[100], 0.5), + }, + '&:active': { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles('dark', { + color: brand[100], + '&:hover': { + backgroundColor: alpha(brand[900], 0.5), + }, + '&:active': { + backgroundColor: alpha(brand[900], 0.3), + }, + }), + }, + }, + ], + }), + }, + }, + MuiLoadingButton: { + styleOverrides: { + root: ({ theme }) => ({ + '& .MuiLoadingButton-loadingIndicator': { + color: gray[400], + ...theme.applyStyles('dark', { + color: gray[600], + }), + }, + }), + }, + }, + MuiCheckbox: { + defaultProps: { + disableRipple: true, + icon: ( + + ), + checkedIcon: , + indeterminateIcon: , + }, + styleOverrides: { + root: ({ theme }) => ({ + margin: 10, + height: 16, + width: 16, + borderRadius: 5, + border: '1px solid ', + borderColor: alpha(gray[300], 0.8), + boxShadow: '0 0 0 1.5px hsla(210, 0%, 0%, 0.04) inset', + backgroundColor: alpha(gray[100], 0.4), + transition: 'border-color, background-color, 120ms ease-in', + '&:hover': { + borderColor: brand[300], + }, + '&.Mui-focusVisible': { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: '2px', + borderColor: brand[400], + }, + '&.Mui-checked': { + color: 'white', + backgroundColor: brand[500], + borderColor: brand[500], + boxShadow: `none`, + '&:hover': { + backgroundColor: brand[600], + }, + }, + ...theme.applyStyles('dark', { + borderColor: alpha(gray[700], 0.8), + boxShadow: '0 0 0 1.5px hsl(210, 0%, 0%) inset', + backgroundColor: alpha(gray[900], 0.8), + '&:hover': { + borderColor: brand[300], + }, + '&.Mui-focusVisible': { + borderColor: brand[400], + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: '2px', + }, + }), + }), + }, + }, + MuiOutlinedInput: { + styleOverrides: { + input: { + padding: 0, + }, + root: ({ theme }) => ({ + padding: '8px 12px', + color: theme.palette.text.primary, + borderRadius: theme.shape.borderRadius, + border: `1px solid ${theme.palette.divider}`, + backgroundColor: theme.palette.background.default, + transition: 'border 120ms ease-in', + '&:hover': { + borderColor: gray[400], + }, + [`&.${outlinedInputClasses.focused}`]: { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + borderColor: brand[400], + }, + ...theme.applyStyles('dark', { + '&:hover': { + borderColor: gray[500], + }, + }), + variants: [ + { + props: { + size: 'small', + }, + style: { + height: '2.25rem', + }, + }, + { + props: { + size: 'medium', + }, + style: { + height: '2.5rem', + }, + }, + ], + }), + notchedOutline: { + border: 'none', + }, + }, + }, +}; diff --git a/docs/data/toolpad/core/components/sign-in-page/customTheme.tsx b/docs/data/toolpad/core/components/sign-in-page/customTheme.tsx new file mode 100644 index 00000000000..c08aaa2f6d0 --- /dev/null +++ b/docs/data/toolpad/core/components/sign-in-page/customTheme.tsx @@ -0,0 +1,584 @@ +import * as React from 'react'; +import { PaletteMode } from '@mui/material'; +import { + alpha, + createTheme, + Shadows, + Theme, + Components, +} from '@mui/material/styles'; +import { outlinedInputClasses } from '@mui/material/OutlinedInput'; +import CheckBoxOutlineBlankRoundedIcon from '@mui/icons-material/CheckBoxOutlineBlankRounded'; +import CheckRoundedIcon from '@mui/icons-material/CheckRounded'; +import RemoveRoundedIcon from '@mui/icons-material/RemoveRounded'; + +declare module '@mui/material/Paper' { + interface PaperPropsVariantOverrides { + highlighted: true; + } +} +declare module '@mui/material/styles/createPalette' { + interface ColorRange { + 50: string; + 100: string; + 200: string; + 300: string; + 400: string; + 500: string; + 600: string; + 700: string; + 800: string; + 900: string; + } + + interface PaletteColor extends ColorRange {} +} + +const defaultTheme = createTheme(); + +const customShadows: Shadows = [...defaultTheme.shadows]; + +export const brand = { + 50: 'hsl(210, 100%, 95%)', + 100: 'hsl(210, 100%, 92%)', + 200: 'hsl(210, 100%, 80%)', + 300: 'hsl(210, 100%, 65%)', + 400: 'hsl(210, 98%, 48%)', + 500: 'hsl(210, 98%, 42%)', + 600: 'hsl(210, 98%, 55%)', + 700: 'hsl(210, 100%, 35%)', + 800: 'hsl(210, 100%, 16%)', + 900: 'hsl(210, 100%, 21%)', +}; + +export const gray = { + 50: 'hsl(220, 35%, 97%)', + 100: 'hsl(220, 30%, 94%)', + 200: 'hsl(220, 20%, 88%)', + 300: 'hsl(220, 20%, 80%)', + 400: 'hsl(220, 20%, 65%)', + 500: 'hsl(220, 20%, 42%)', + 600: 'hsl(220, 20%, 35%)', + 700: 'hsl(220, 20%, 25%)', + 800: 'hsl(220, 30%, 6%)', + 900: 'hsl(220, 35%, 3%)', +}; + +export const green = { + 50: 'hsl(120, 80%, 98%)', + 100: 'hsl(120, 75%, 94%)', + 200: 'hsl(120, 75%, 87%)', + 300: 'hsl(120, 61%, 77%)', + 400: 'hsl(120, 44%, 53%)', + 500: 'hsl(120, 59%, 30%)', + 600: 'hsl(120, 70%, 25%)', + 700: 'hsl(120, 75%, 16%)', + 800: 'hsl(120, 84%, 10%)', + 900: 'hsl(120, 87%, 6%)', +}; + +export const orange = { + 50: 'hsl(45, 100%, 97%)', + 100: 'hsl(45, 92%, 90%)', + 200: 'hsl(45, 94%, 80%)', + 300: 'hsl(45, 90%, 65%)', + 400: 'hsl(45, 90%, 40%)', + 500: 'hsl(45, 90%, 35%)', + 600: 'hsl(45, 91%, 25%)', + 700: 'hsl(45, 94%, 20%)', + 800: 'hsl(45, 95%, 16%)', + 900: 'hsl(45, 93%, 12%)', +}; + +export const red = { + 50: 'hsl(0, 100%, 97%)', + 100: 'hsl(0, 92%, 90%)', + 200: 'hsl(0, 94%, 80%)', + 300: 'hsl(0, 90%, 65%)', + 400: 'hsl(0, 90%, 40%)', + 500: 'hsl(0, 90%, 30%)', + 600: 'hsl(0, 91%, 25%)', + 700: 'hsl(0, 94%, 18%)', + 800: 'hsl(0, 95%, 12%)', + 900: 'hsl(0, 93%, 6%)', +}; + +export const getDesignTokens = (mode: PaletteMode) => { + customShadows[1] = + mode === 'dark' + ? 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px' + : 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px'; + + customShadows[4] = + '0px 5px 15px rgba(9, 11, 17, 0.05), 0px 15px 35px -5px rgba(19, 23, 32, 0.05)'; + + return { + palette: { + mode, + primary: { + light: brand[200], + main: brand[400], + dark: brand[700], + contrastText: brand[50], + ...(mode === 'dark' && { + contrastText: brand[50], + light: brand[300], + main: brand[400], + dark: brand[700], + }), + }, + info: { + light: brand[100], + main: brand[300], + dark: brand[600], + contrastText: gray[50], + ...(mode === 'dark' && { + contrastText: brand[300], + light: brand[500], + main: brand[700], + dark: brand[900], + }), + }, + warning: { + light: orange[300], + main: orange[400], + dark: orange[800], + ...(mode === 'dark' && { + light: orange[400], + main: orange[500], + dark: orange[700], + }), + }, + error: { + light: red[300], + main: red[400], + dark: red[800], + ...(mode === 'dark' && { + light: red[400], + main: red[500], + dark: red[700], + }), + }, + success: { + light: green[300], + main: green[400], + dark: green[800], + ...(mode === 'dark' && { + light: green[400], + main: green[500], + dark: green[700], + }), + }, + grey: { + ...gray, + }, + divider: mode === 'dark' ? alpha(gray[700], 0.6) : alpha(gray[300], 0.4), + background: { + default: 'hsl(0, 0%, 99%)', + paper: 'hsl(220, 35%, 97%)', + ...(mode === 'dark' && { + default: gray[900], + paper: 'hsl(220, 30%, 7%)', + }), + }, + text: { + primary: gray[800], + secondary: gray[600], + warning: orange[400], + ...(mode === 'dark' && { + primary: 'hsl(0, 0%, 100%)', + secondary: gray[400], + }), + }, + action: { + hover: alpha(gray[200], 0.2), + selected: `${alpha(gray[200], 0.3)}`, + ...(mode === 'dark' && { + hover: alpha(gray[600], 0.2), + selected: alpha(gray[600], 0.3), + }), + }, + }, + typography: { + h1: { + fontSize: defaultTheme.typography.pxToRem(48), + fontWeight: 600, + lineHeight: 1.2, + letterSpacing: -0.5, + }, + h2: { + fontSize: defaultTheme.typography.pxToRem(36), + fontWeight: 600, + lineHeight: 1.2, + }, + h3: { + fontSize: defaultTheme.typography.pxToRem(30), + lineHeight: 1.2, + }, + h4: { + fontSize: defaultTheme.typography.pxToRem(24), + fontWeight: 600, + lineHeight: 1.5, + }, + h5: { + fontSize: defaultTheme.typography.pxToRem(20), + fontWeight: 600, + }, + h6: { + fontSize: defaultTheme.typography.pxToRem(18), + fontWeight: 600, + }, + subtitle1: { + fontSize: defaultTheme.typography.pxToRem(18), + }, + subtitle2: { + fontSize: defaultTheme.typography.pxToRem(14), + fontWeight: 500, + }, + body1: { + fontSize: defaultTheme.typography.pxToRem(14), + }, + body2: { + fontSize: defaultTheme.typography.pxToRem(14), + fontWeight: 400, + }, + caption: { + fontSize: defaultTheme.typography.pxToRem(12), + fontWeight: 400, + }, + }, + shape: { + borderRadius: 8, + }, + shadows: customShadows, + }; +}; + +export const inputsCustomizations: Components = { + MuiButtonBase: { + defaultProps: { + disableTouchRipple: true, + disableRipple: true, + }, + styleOverrides: { + root: ({ theme }) => ({ + boxSizing: 'border-box', + transition: 'all 100ms ease-in', + '&:focus-visible': { + outline: `3px solid ${alpha(theme.palette.primary.main, 0.5)}`, + outlineOffset: '2px', + }, + }), + }, + }, + MuiButton: { + styleOverrides: { + root: ({ theme }) => ({ + boxShadow: 'none', + borderRadius: theme.shape.borderRadius, + textTransform: 'none', + variants: [ + { + props: { + size: 'small', + }, + style: { + height: '2.25rem', + padding: '8px 12px', + }, + }, + { + props: { + size: 'medium', + }, + style: { + height: '2.5rem', // 40px + }, + }, + { + props: { + color: 'primary', + variant: 'contained', + }, + style: { + color: 'white', + backgroundColor: gray[900], + backgroundImage: `linear-gradient(to bottom, ${gray[700]}, ${gray[800]})`, + boxShadow: `inset 0 1px 0 ${gray[600]}, inset 0 -1px 0 1px hsl(220, 0%, 0%)`, + border: `1px solid ${gray[700]}`, + '&:hover': { + backgroundImage: 'none', + backgroundColor: gray[700], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: gray[800], + }, + ...theme.applyStyles('dark', { + color: 'black', + backgroundColor: gray[50], + backgroundImage: `linear-gradient(to bottom, ${gray[100]}, ${gray[50]})`, + boxShadow: 'inset 0 -1px 0 hsl(220, 30%, 80%)', + border: `1px solid ${gray[50]}`, + '&:hover': { + backgroundImage: 'none', + backgroundColor: gray[300], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: gray[400], + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'contained', + }, + style: { + color: 'white', + backgroundColor: brand[300], + backgroundImage: `linear-gradient(to bottom, ${alpha(brand[400], 0.8)}, ${brand[500]})`, + boxShadow: `inset 0 2px 0 ${alpha(brand[200], 0.2)}, inset 0 -2px 0 ${alpha(brand[700], 0.4)}`, + border: `1px solid ${brand[500]}`, + '&:hover': { + backgroundColor: brand[700], + boxShadow: 'none', + }, + '&:active': { + backgroundColor: brand[700], + backgroundImage: 'none', + }, + }, + }, + { + props: { + variant: 'outlined', + }, + style: { + color: theme.palette.text.primary, + border: '1px solid', + borderColor: gray[200], + backgroundColor: alpha(gray[50], 0.3), + '&:hover': { + backgroundColor: gray[100], + borderColor: gray[300], + }, + '&:active': { + backgroundColor: gray[200], + }, + ...theme.applyStyles('dark', { + backgroundColor: gray[800], + borderColor: gray[700], + + '&:hover': { + backgroundColor: gray[900], + borderColor: gray[600], + }, + '&:active': { + backgroundColor: gray[900], + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'outlined', + }, + style: { + color: brand[700], + border: '1px solid', + borderColor: brand[200], + backgroundColor: brand[50], + '&:hover': { + backgroundColor: brand[100], + borderColor: brand[400], + }, + '&:active': { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles('dark', { + color: brand[50], + border: '1px solid', + borderColor: brand[900], + backgroundColor: alpha(brand[900], 0.3), + '&:hover': { + borderColor: brand[700], + backgroundColor: alpha(brand[900], 0.6), + }, + '&:active': { + backgroundColor: alpha(brand[900], 0.5), + }, + }), + }, + }, + { + props: { + variant: 'text', + }, + style: { + color: gray[600], + '&:hover': { + backgroundColor: gray[100], + }, + '&:active': { + backgroundColor: gray[200], + }, + ...theme.applyStyles('dark', { + color: gray[50], + '&:hover': { + backgroundColor: gray[700], + }, + '&:active': { + backgroundColor: alpha(gray[700], 0.7), + }, + }), + }, + }, + { + props: { + color: 'secondary', + variant: 'text', + }, + style: { + color: brand[700], + '&:hover': { + backgroundColor: alpha(brand[100], 0.5), + }, + '&:active': { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles('dark', { + color: brand[100], + '&:hover': { + backgroundColor: alpha(brand[900], 0.5), + }, + '&:active': { + backgroundColor: alpha(brand[900], 0.3), + }, + }), + }, + }, + ], + }), + }, + }, + // @ts-ignore TODO: MuiLoadingButton is not present in the default `theme` + MuiLoadingButton: { + styleOverrides: { + // @ts-ignore + root: ({ theme }) => ({ + '& .MuiLoadingButton-loadingIndicator': { + color: gray[400], + ...theme.applyStyles('dark', { + color: gray[600], + }), + }, + }), + }, + }, + MuiCheckbox: { + defaultProps: { + disableRipple: true, + icon: ( + + ), + checkedIcon: , + indeterminateIcon: , + }, + styleOverrides: { + root: ({ theme }) => ({ + margin: 10, + height: 16, + width: 16, + borderRadius: 5, + border: '1px solid ', + borderColor: alpha(gray[300], 0.8), + boxShadow: '0 0 0 1.5px hsla(210, 0%, 0%, 0.04) inset', + backgroundColor: alpha(gray[100], 0.4), + transition: 'border-color, background-color, 120ms ease-in', + '&:hover': { + borderColor: brand[300], + }, + '&.Mui-focusVisible': { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: '2px', + borderColor: brand[400], + }, + '&.Mui-checked': { + color: 'white', + backgroundColor: brand[500], + borderColor: brand[500], + boxShadow: `none`, + '&:hover': { + backgroundColor: brand[600], + }, + }, + ...theme.applyStyles('dark', { + borderColor: alpha(gray[700], 0.8), + boxShadow: '0 0 0 1.5px hsl(210, 0%, 0%) inset', + backgroundColor: alpha(gray[900], 0.8), + '&:hover': { + borderColor: brand[300], + }, + '&.Mui-focusVisible': { + borderColor: brand[400], + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: '2px', + }, + }), + }), + }, + }, + + MuiOutlinedInput: { + styleOverrides: { + input: { + padding: 0, + }, + root: ({ theme }) => ({ + padding: '8px 12px', + color: theme.palette.text.primary, + borderRadius: theme.shape.borderRadius, + border: `1px solid ${theme.palette.divider}`, + backgroundColor: theme.palette.background.default, + transition: 'border 120ms ease-in', + '&:hover': { + borderColor: gray[400], + }, + [`&.${outlinedInputClasses.focused}`]: { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + borderColor: brand[400], + }, + ...theme.applyStyles('dark', { + '&:hover': { + borderColor: gray[500], + }, + }), + variants: [ + { + props: { + size: 'small', + }, + style: { + height: '2.25rem', + }, + }, + { + props: { + size: 'medium', + }, + style: { + height: '2.5rem', + }, + }, + ], + }), + notchedOutline: { + border: 'none', + }, + }, + }, +}; diff --git a/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md b/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md index cdbc0bcfdc6..ffca59e7c61 100644 --- a/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md +++ b/docs/data/toolpad/core/components/sign-in-page/sign-in-page.md @@ -54,14 +54,12 @@ The `SignIn` page component supports magic links. To enable this, you have to se To render a magic link form, pass in a provider with `nodemailer` as the `id` property. -{{"demo": "MagicLinkSignInPage.js", "iframe": true, "height": 400}} - -### Alerts - +:::info The `SignInPage` component can display a success alert if the email is sent successfully. You can enable this by passing a `success` property in the response object of the `signIn` prop. +::: -{{"demo": "MagicLinkAlertSignInPage.js", "iframe": true, "height": 400}} +{{"demo": "MagicLinkAlertSignInPage.js", "iframe": true, "height": 450}} :::info Check out the complete [Next.js Auth.js Magic Link example](https://github.com/mui/mui-toolpad/tree/master/examples/core/auth-nextjs-email/) example for a working implementation of a magic link sign-in page with Auth.js, Nodemailer, Prisma and PostgreSQL. @@ -223,29 +221,31 @@ If you're using Vite with React Router, check out the [example with Vite and Rea You can add your own branding elements to the `SignInPage` through the `branding` prop in the [AppProvider](https://mui.com/toolpad/core/react-app-provider/): -{{"demo": "BrandingSignInPage.js", "iframe": true, "height": 360 }} +{{"demo": "BrandingSignInPage.js", "iframe": true, "height": 600 }} ### Theme Through the `theme` prop in the [AppProvider](https://mui.com/toolpad/core/react-app-provider/), the `SignInPage` can be deeply customized to match any theme: -{{"demo": "ThemeSignInPage.js", "height": 700 }} - -### Slot Props - -You can use the `slotProps` prop to customize the underlying components of the `SignInPage`: +{{"demo": "ThemeSignInPage.js", "iframe": true, "height": 700 }} -{{"demo": "SlotPropsSignIn.js", "height": 540 }} +:::info +Find a full-fledged example using the Next.js App router, Auth.js and this theme [here](https://codesandbox.io/s/github/mui/toolpad/tree/master/examples/core/auth-nextjs-themed). +::: ### Slots To enable deep customization beyond what is possible with custom props, the `SignInPage` component allows bringing your own custom granular components, such as inputs and buttons. -:::info -Make sure to use the `name` attribute on the custom components with values `email` and `password` to enable data capture by the form action. +:::warning +Make sure to pass `email` and `password` as the `name` attribute on custom email and password components, otherwise those values will not be available in the `formData` parameter of the `signIn` prop. ::: -{{"demo": "SlotsSignIn.js", "height": 540 }} +{{"demo": "SlotsSignIn.js", "iframe": true, "height": 540 }} + +You can use the `slotProps` prop to pass props to the underlying components of each slot: + +{{"demo": "SlotPropsSignIn.js", "iframe": true, "height": 540 }} ### 🚧 Layouts diff --git a/docs/public/static/toolpad/docs/core/auth-next-dark.png b/docs/public/static/toolpad/docs/core/auth-next-dark.png index a4b127c9b6c..527474a4a77 100644 Binary files a/docs/public/static/toolpad/docs/core/auth-next-dark.png and b/docs/public/static/toolpad/docs/core/auth-next-dark.png differ diff --git a/docs/public/static/toolpad/docs/core/auth-next.png b/docs/public/static/toolpad/docs/core/auth-next.png index 57238099e1b..fc266f89294 100644 Binary files a/docs/public/static/toolpad/docs/core/auth-next.png and b/docs/public/static/toolpad/docs/core/auth-next.png differ diff --git a/docs/src/modules/components/ExamplesGrid/core-examples.ts b/docs/src/modules/components/ExamplesGrid/core-examples.ts index 92e559394cd..de67bda126c 100644 --- a/docs/src/modules/components/ExamplesGrid/core-examples.ts +++ b/docs/src/modules/components/ExamplesGrid/core-examples.ts @@ -92,8 +92,6 @@ export default function examples() { source: 'https://github.com/mui/toolpad/tree/master/examples/core/auth-nextjs-themed', codesandbox: 'https://codesandbox.io/s/github/mui/toolpad/tree/master/examples/core/auth-nextjs-themed', - stackblitz: - 'https://stackblitz.com/github/mui/toolpad/tree/master/examples/core/auth-nextjs-themed', }, ]; } diff --git a/examples/core/auth-nextjs-themed/README.md b/examples/core/auth-nextjs-themed/README.md index 3086b505f85..17c9ac9fbec 100644 --- a/examples/core/auth-nextjs-themed/README.md +++ b/examples/core/auth-nextjs-themed/README.md @@ -14,6 +14,20 @@ First, run the development server: `npm run dev` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## Run on Code Sandbox + +Run this example on CodeSandbox [here](https://codesandbox.io/s/github/mui/toolpad/tree/master/examples/core/auth-nextjs-themed). + +## Clone using `create-toolpad-app` + +To copy this example and customize it for your needs, run + +```bash +npx create-toolpad-app@latest --example auth-nextjs-themed +``` + +and follow the instructions in the terminal. + ## Deploy on Vercel The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. diff --git a/examples/core/auth-nextjs-themed/theme/themePrimitives.ts b/examples/core/auth-nextjs-themed/theme/themePrimitives.ts index 177eb7cef78..bccf187d5f5 100644 --- a/examples/core/auth-nextjs-themed/theme/themePrimitives.ts +++ b/examples/core/auth-nextjs-themed/theme/themePrimitives.ts @@ -101,7 +101,7 @@ export const getDesignTokens = (mode: PaletteMode) => { ? 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px' : 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px'; - customShadows[10] = + customShadows[4] = '0px 5px 15px rgba(9, 11, 17, 0.05), 0px 15px 35px -5px rgba(19, 23, 32, 0.05)'; return { diff --git a/packages/toolpad-core/src/SignInPage/SignInPage.tsx b/packages/toolpad-core/src/SignInPage/SignInPage.tsx index 3510bd938c8..67eb612106f 100644 --- a/packages/toolpad-core/src/SignInPage/SignInPage.tsx +++ b/packages/toolpad-core/src/SignInPage/SignInPage.tsx @@ -268,7 +268,6 @@ function SignInPage(props: SignInPageProps) { {branding?.logo} @@ -289,7 +288,7 @@ function SignInPage(props: SignInPageProps) { variant="h5" color="textPrimary" sx={{ - mb: 1, + my: theme.spacing(1), fontWeight: 600, }} > @@ -303,7 +302,7 @@ function SignInPage(props: SignInPageProps) { Welcome, please sign in to continue )} - + {error && isOauthProvider(selectedProviderId) ? ( {error} @@ -507,7 +506,7 @@ function SignInPage(props: SignInPageProps) { type="submit" fullWidth size="large" - variant="contained" + variant="outlined" disableElevation id="submit-nodemailer" color="inherit"