diff --git a/docs/pages/_document.js b/docs/pages/_document.js index 64819f0645e771..228f76f33c168a 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -82,7 +82,7 @@ export default class MyDocument extends Document { diff --git a/docs/pages/branding/home.tsx b/docs/pages/branding/home.tsx index b3896cea0f00ae..5e642b6ba2677e 100644 --- a/docs/pages/branding/home.tsx +++ b/docs/pages/branding/home.tsx @@ -1,31 +1,33 @@ import * as React from 'react'; -import { ThemeProvider } from '@material-ui/core/styles'; +import ThemeProvider from 'docs/src/modules/ThemeContext'; import CssBaseline from '@material-ui/core/CssBaseline'; -import Typography from '@material-ui/core/Typography'; +import Divider from '@material-ui/core/Divider'; import AppHeader from 'docs/src/layouts/AppHeader'; -import Container from '@material-ui/core/Container'; import Hero from 'docs/src/components/home/Hero'; -import brandingTheme from 'docs/src/modules/brandingTheme'; -import References from 'docs/src/components/home/References'; +import ReferencesCore from 'docs/src/components/home/ReferencesCore'; +import ProductSuite from 'docs/src/components/home/ProductSuite'; +import ValueProposition from 'docs/src/components/home/ValueProposition'; +import DesignSystemComponents from 'docs/src/components/home/DesignSystemComponents'; +import Testimonials from 'docs/src/components/home/Testimonials'; +import Sponsors from 'docs/src/components/home/Sponsors'; +import HeroEnd from 'docs/src/components/home/HeroEnd'; +import AppFooter from 'docs/src/layouts/AppFooter'; export default function Home() { return ( - + - - - - From startups to Fortune 500s, the world's best teams leverage MUI to build their - UIs. - - + + + + + + + + + ); } diff --git a/docs/public/static/branding/pricing/amazon.svg b/docs/public/static/branding/companies/amazon.svg similarity index 97% rename from docs/public/static/branding/pricing/amazon.svg rename to docs/public/static/branding/companies/amazon.svg index e33866eefc11f8..07ac1b3f5dd8d1 100644 --- a/docs/public/static/branding/pricing/amazon.svg +++ b/docs/public/static/branding/companies/amazon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/pricing/coursera.svg b/docs/public/static/branding/companies/coursera.svg similarity index 98% rename from docs/public/static/branding/pricing/coursera.svg rename to docs/public/static/branding/companies/coursera.svg index f3d1ba98c65dc8..6a77eb85d428d4 100644 --- a/docs/public/static/branding/pricing/coursera.svg +++ b/docs/public/static/branding/companies/coursera.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/companies/docker-blue.svg b/docs/public/static/branding/companies/docker-blue.svg new file mode 100644 index 00000000000000..87169bf54f49e8 --- /dev/null +++ b/docs/public/static/branding/companies/docker-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/companies/loggi-blue.svg b/docs/public/static/branding/companies/loggi-blue.svg new file mode 100644 index 00000000000000..88bc1e7c517129 --- /dev/null +++ b/docs/public/static/branding/companies/loggi-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/pricing/nasa.svg b/docs/public/static/branding/companies/nasa.svg similarity index 98% rename from docs/public/static/branding/pricing/nasa.svg rename to docs/public/static/branding/companies/nasa.svg index e0008638894192..225542263bec90 100644 --- a/docs/public/static/branding/pricing/nasa.svg +++ b/docs/public/static/branding/companies/nasa.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/pricing/netflix.svg b/docs/public/static/branding/companies/netflix.svg similarity index 92% rename from docs/public/static/branding/pricing/netflix.svg rename to docs/public/static/branding/companies/netflix.svg index 66f2b29ad41d6d..a6441082e174d9 100644 --- a/docs/public/static/branding/pricing/netflix.svg +++ b/docs/public/static/branding/companies/netflix.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/pricing/shutterstock.svg b/docs/public/static/branding/companies/shutterstock.svg similarity index 97% rename from docs/public/static/branding/pricing/shutterstock.svg rename to docs/public/static/branding/companies/shutterstock.svg index 29888429b18d54..150cfecb28205e 100644 --- a/docs/public/static/branding/pricing/shutterstock.svg +++ b/docs/public/static/branding/companies/shutterstock.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/companies/unity-blue.svg b/docs/public/static/branding/companies/unity-blue.svg new file mode 100644 index 00000000000000..0465d2822be62d --- /dev/null +++ b/docs/public/static/branding/companies/unity-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/pricing/unity.svg b/docs/public/static/branding/companies/unity.svg similarity index 94% rename from docs/public/static/branding/pricing/unity.svg rename to docs/public/static/branding/companies/unity.svg index 7a096557938ad7..930a8b2eae4701 100644 --- a/docs/public/static/branding/pricing/unity.svg +++ b/docs/public/static/branding/companies/unity.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/design-kits/designkits-bg.png b/docs/public/static/branding/design-kits/designkits-bg.png new file mode 100644 index 00000000000000..1dc89cbae4fab9 Binary files /dev/null and b/docs/public/static/branding/design-kits/designkits-bg.png differ diff --git a/docs/public/static/branding/design-kits/designkits-figma.png b/docs/public/static/branding/design-kits/designkits-figma.png new file mode 100644 index 00000000000000..600bc564ba3849 Binary files /dev/null and b/docs/public/static/branding/design-kits/designkits-figma.png differ diff --git a/docs/public/static/branding/design-kits/designkits-sketch.png b/docs/public/static/branding/design-kits/designkits-sketch.png new file mode 100644 index 00000000000000..caa6b62ba03d10 Binary files /dev/null and b/docs/public/static/branding/design-kits/designkits-sketch.png differ diff --git a/docs/public/static/branding/design-kits/designkits-xd.png b/docs/public/static/branding/design-kits/designkits-xd.png new file mode 100644 index 00000000000000..85ed524355bac2 Binary files /dev/null and b/docs/public/static/branding/design-kits/designkits-xd.png differ diff --git a/docs/public/static/branding/mui-docs.svg b/docs/public/static/branding/mui-docs.svg new file mode 100644 index 00000000000000..89aeca7d365304 --- /dev/null +++ b/docs/public/static/branding/mui-docs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/mui-eye.svg b/docs/public/static/branding/mui-eye.svg new file mode 100644 index 00000000000000..4ee1ed091f338f --- /dev/null +++ b/docs/public/static/branding/mui-eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/mui-palette.svg b/docs/public/static/branding/mui-palette.svg new file mode 100644 index 00000000000000..35c0cc6f0a2b8d --- /dev/null +++ b/docs/public/static/branding/mui-palette.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/mui-pencil.svg b/docs/public/static/branding/mui-pencil.svg new file mode 100644 index 00000000000000..ceb2896090ba5a --- /dev/null +++ b/docs/public/static/branding/mui-pencil.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/static/branding/store-templates/store-template1.jpeg b/docs/public/static/branding/store-templates/store-template1.jpeg new file mode 100644 index 00000000000000..d66d0f3acdf580 Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template1.jpeg differ diff --git a/docs/public/static/branding/store-templates/store-template2.jpeg b/docs/public/static/branding/store-templates/store-template2.jpeg new file mode 100644 index 00000000000000..d27aee06d3e9b5 Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template2.jpeg differ diff --git a/docs/public/static/branding/store-templates/store-template3.jpeg b/docs/public/static/branding/store-templates/store-template3.jpeg new file mode 100644 index 00000000000000..a770d5cc6396dd Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template3.jpeg differ diff --git a/docs/public/static/branding/store-templates/store-template4.jpeg b/docs/public/static/branding/store-templates/store-template4.jpeg new file mode 100644 index 00000000000000..93420b6cf5ecf0 Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template4.jpeg differ diff --git a/docs/public/static/branding/store-templates/store-template5.jpeg b/docs/public/static/branding/store-templates/store-template5.jpeg new file mode 100644 index 00000000000000..0e000af604cf0c Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template5.jpeg differ diff --git a/docs/public/static/branding/store-templates/store-template6.jpeg b/docs/public/static/branding/store-templates/store-template6.jpeg new file mode 100644 index 00000000000000..aaf0e75d2dcf56 Binary files /dev/null and b/docs/public/static/branding/store-templates/store-template6.jpeg differ diff --git a/docs/src/components/HeaderNavBar.tsx b/docs/src/components/header/HeaderNavBar.tsx similarity index 84% rename from docs/src/components/HeaderNavBar.tsx rename to docs/src/components/header/HeaderNavBar.tsx index d4aa2e79e99ae0..7d8d6d1b9b4d73 100644 --- a/docs/src/components/HeaderNavBar.tsx +++ b/docs/src/components/header/HeaderNavBar.tsx @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/anchor-is-valid */ import * as React from 'react'; import NextLink, { LinkProps } from 'next/link'; -import { styled } from '@material-ui/core/styles'; +import { styled, alpha } from '@material-ui/core/styles'; import Box from '@material-ui/core/Box'; import Popper from '@material-ui/core/Popper'; import Paper from '@material-ui/core/Paper'; @@ -12,6 +12,7 @@ import SvgProductAdvanced from 'docs/src/icons/SvgProductAdvanced'; import SvgProductTemplates from 'docs/src/icons/SvgProductTemplates'; import SvgProductDesign from 'docs/src/icons/SvgProductDesign'; import SvgMuiX from 'docs/src/icons/SvgMuiX'; +import ROUTES from 'docs/src/route'; const Navigation = styled('nav')(({ theme }) => ({ '& ul': { @@ -23,7 +24,7 @@ const Navigation = styled('nav')(({ theme }) => ({ '& li': { color: theme.palette.text.secondary, ...theme.typography.body2, - fontWeight: 700, + fontWeight: 600, '& > a, & > div': { display: 'inline-block', color: 'inherit', @@ -31,7 +32,8 @@ const Navigation = styled('nav')(({ theme }) => ({ padding: theme.spacing(1), borderRadius: theme.shape.borderRadius, '&:hover, &:focus': { - backgroundColor: theme.palette.grey[50], + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : theme.palette.grey[50], // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { backgroundColor: 'initial', @@ -65,7 +67,8 @@ const ProductSubMenu = React.forwardRef( alignItems: 'center', py: 2, '&:hover, &:focus': { - backgroundColor: 'grey.50', + backgroundColor: (theme) => + theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.50', outline: 'none', '@media (hover: none)': { backgroundColor: 'initial', @@ -77,7 +80,7 @@ const ProductSubMenu = React.forwardRef( > {icon} - + {name} @@ -105,6 +108,7 @@ export default function HeaderNavBar() { return; } if (event.key === 'ArrowDown') { + event.preventDefault(); if (event.target === productsMenuRef.current) { setSubMenuOpen(true); } @@ -117,6 +121,7 @@ export default function HeaderNavBar() { }); } if (event.key === 'ArrowUp') { + event.preventDefault(); setSubMenuIndex((prevValue) => { if (prevValue === null) return 0; if (prevValue === 0) { @@ -165,7 +170,14 @@ export default function HeaderNavBar() { sx={{ minWidth: 498, overflow: 'hidden', - boxShadow: '0px 4px 20px rgba(170, 180, 190, 0.3)', + bgcolor: (theme) => + theme.palette.mode === 'dark' ? 'primaryDark.900' : 'background.paper', + boxShadow: (theme) => + `0px 4px 20px ${ + theme.palette.mode === 'dark' + ? alpha(theme.palette.background.paper, 0.72) + : 'rgba(170, 180, 190, 0.3)' + }`, '& ul': { margin: 0, padding: 0, @@ -173,7 +185,8 @@ export default function HeaderNavBar() { }, '& li:not(:last-of-type)': { borderBottom: '1px solid', - borderColor: 'grey.100', + borderColor: (theme) => + theme.palette.mode === 'dark' ? 'primaryDark.400' : 'grey.100', }, '& a': { textDecoration: 'none' }, }} @@ -183,7 +196,7 @@ export default function HeaderNavBar() { } name="Core" description="Ready to use, forever free, out-of-the-box, components." @@ -194,7 +207,7 @@ export default function HeaderNavBar() { } name={ @@ -209,7 +222,7 @@ export default function HeaderNavBar() { } name="Templates" description="Get a fully built template for you application." @@ -220,7 +233,7 @@ export default function HeaderNavBar() { } name="Design Kits" description="Pick your favorite design tool to enjoy." @@ -234,17 +247,17 @@ export default function HeaderNavBar() {
  • - + Docs
  • - + Pricing
  • - + About us
  • diff --git a/docs/src/components/HeaderNavDropdown.tsx b/docs/src/components/header/HeaderNavDropdown.tsx similarity index 71% rename from docs/src/components/HeaderNavDropdown.tsx rename to docs/src/components/header/HeaderNavDropdown.tsx index 5ec9e08bb89f75..303ab5f06604fb 100644 --- a/docs/src/components/HeaderNavDropdown.tsx +++ b/docs/src/components/header/HeaderNavDropdown.tsx @@ -8,12 +8,13 @@ import IconButton from '@material-ui/core/IconButton'; import Typography from '@material-ui/core/Typography'; import KeyboardArrowDownRounded from '@material-ui/icons/KeyboardArrowDownRounded'; import SvgHambugerMenu from 'docs/src/icons/SvgHamburgerMenu'; +import ROUTES from 'docs/src/route'; const Anchor = styled('a')<{ component?: React.ElementType }>(({ theme }) => ({ ...theme.typography.body2, fontWeight: 700, textDecoration: 'none', - color: theme.palette.text.secondary, + color: theme.palette.mode === 'dark' ? '#fff' : theme.palette.text.secondary, cursor: 'pointer', display: 'flex', alignItems: 'center', @@ -21,7 +22,8 @@ const Anchor = styled('a')<{ component?: React.ElementType }>(({ theme }) => ({ borderRadius: theme.spacing(1), transition: theme.transitions.create('background'), '&:hover, &:focus': { - backgroundColor: theme.palette.grey[100], + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : theme.palette.grey[100], // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { backgroundColor: 'transparent', @@ -36,13 +38,26 @@ const UList = styled('ul')({ }); const PRODUCTS = [ - { name: 'Core', description: 'Ready to use, forever free, foundational components.' }, - { name: 'Advanced', description: 'Powerful and robust components for your complex apps.' }, + { + name: 'Core', + description: 'Ready to use, forever free, foundational components.', + href: ROUTES.productCore, + }, + { + name: 'Advanced', + description: 'Powerful and robust components for your complex apps.', + href: ROUTES.productAdvanced, + }, { name: 'Templates', description: 'Fully built, out-of-the-box, templates for your application.', + href: ROUTES.productTemplates, + }, + { + name: 'Design Kits', + description: 'Our components available in your favorite design tool.', + href: ROUTES.productDesignKits, }, - { name: 'Design Kits', description: 'Our components available in your favorite design tool.' }, ]; export default function HeaderNavDropdown() { @@ -58,7 +73,14 @@ export default function HeaderNavDropdown() { sx={{ position: 'relative', borderRadius: 1, - '&:focus': { boxShadow: `0 0 0 1px #e5e8ec` }, + '&:focus': { + boxShadow: (theme) => + `0 0 0 1px ${ + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[600] + : theme.palette.grey[200] + }`, + }, '& rect': { transformOrigin: 'center', transition: '0.2s', @@ -115,28 +137,32 @@ export default function HeaderNavDropdown() { sx={{ borderLeft: '1px solid', borderColor: 'grey.100', pl: 1, pb: 1, ml: 1 }} > {PRODUCTS.map((item) => ( - - -
    {item.name}
    - {item.description} -
    -
    +
  • + + +
    {item.name}
    + + {item.description} + +
    +
    +
  • ))}
  • - + Docs
  • - + Pricing
  • - + About us
  • diff --git a/docs/src/components/header/ThemeModeToggle.tsx b/docs/src/components/header/ThemeModeToggle.tsx new file mode 100644 index 00000000000000..bf7e256f6a9eac --- /dev/null +++ b/docs/src/components/header/ThemeModeToggle.tsx @@ -0,0 +1,95 @@ +import * as React from 'react'; +import { styled, alpha } from '@material-ui/core/styles'; +import SwitchUnstyled, { + switchUnstyledClasses, + SwitchUnstyledProps, +} from '@material-ui/unstyled/SwitchUnstyled'; +import DarkModeOutlined from '@material-ui/icons/DarkModeOutlined'; +import LightModeOutlined from '@material-ui/icons/LightModeOutlined'; + +const Root = styled('span')(({ theme }) => ({ + fontSize: 0, + color: '#fff', + position: 'relative', + display: 'inline-block', + width: 40, + height: 17, + backgroundColor: theme.palette.grey[100], + borderRadius: 10, + margin: 10, + cursor: 'pointer', + transition: theme.transitions.create('background-color'), + [`& .${switchUnstyledClasses.thumb}`]: { + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + position: 'absolute', + padding: 2, + width: 24, + height: 24, + top: -3, + left: 0, + borderRadius: 24, + backgroundColor: theme.palette.primary.main, + transform: 'rotate(-90deg)', + transition: theme.transitions.create(['transform', 'left']), + '& > svg': { + width: 18, + height: 18, + }, + '&:before': { + content: '""', + display: 'block', + position: 'absolute', + borderRadius: '50%', + zIndex: -1, + top: 0, + left: 0, + right: 0, + bottom: 0, + transform: 'scale(0)', + transition: theme.transitions.create('transform'), + backgroundColor: alpha(theme.palette.primary.main, 0.4), + }, + }, + [`&.${switchUnstyledClasses.checked} .${switchUnstyledClasses.thumb}`]: { + left: 16, + transform: 'rotate(0deg)', + }, + [`&.${switchUnstyledClasses.focusVisible} .${switchUnstyledClasses.thumb}`]: { + '&:before': { + transform: 'scale(1.3)', + }, + }, + [`& .${switchUnstyledClasses.input}`]: { + cursor: 'inherit', + position: 'absolute', + width: '100%', + height: '100%', + top: 0, + left: 0, + opacity: 0, + zIndex: 1, + margin: 0, + }, + [`&.${switchUnstyledClasses.checked}`]: { + background: theme.palette.primary[200], + }, +})); + +const ThemeModeToggle = (props: SwitchUnstyledProps) => { + return ( + : , + }, + input: { 'aria-label': 'Theme mode toggle' }, + }} + /> + ); +}; + +export default ThemeModeToggle; diff --git a/docs/src/components/home/CompaniesGrid.tsx b/docs/src/components/home/CompaniesGrid.tsx new file mode 100644 index 00000000000000..138c26cda68d29 --- /dev/null +++ b/docs/src/components/home/CompaniesGrid.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import Grid from '@material-ui/core/Grid'; + +export const CORE_COMPANIES = [ + { + src: '/static/branding/companies/coursera.svg', + alt: 'Coursera logo', + width: 102, + height: 16, + }, + { + src: '/static/branding/companies/amazon.svg', + alt: 'Amazon logo', + width: 92, + height: 28, + }, + { + src: '/static/branding/companies/nasa.svg', + alt: 'Nasa logo', + width: 64, + height: 53, + }, + { + src: '/static/branding/companies/netflix.svg', + alt: 'Netflix logo', + width: 88, + height: 24, + }, + { + src: '/static/branding/companies/unity.svg', + alt: 'Unity logo', + width: 110, + height: 40, + }, + { + src: '/static/branding/companies/shutterstock.svg', + alt: 'Shutterstock logo', + width: 138, + height: 21, + }, +]; + +export default function CompaniesGrid({ data }: { data: Array }) { + return ( + + {data.map((imgProps) => ( + + {imgProps.alt} + + ))} + + ); +} diff --git a/docs/src/components/home/CoreShowcase.tsx b/docs/src/components/home/CoreShowcase.tsx new file mode 100644 index 00000000000000..6e35fa791859de --- /dev/null +++ b/docs/src/components/home/CoreShowcase.tsx @@ -0,0 +1,358 @@ +import * as React from 'react'; +import { ThemeProvider, createTheme, useTheme } from '@material-ui/core/styles'; +import LinearProgress from '@material-ui/core/LinearProgress'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; +import ReplayRounded from '@material-ui/icons/ReplayRounded'; +import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { getDesignTokens, getThemedComponents } from 'docs/src/modules/brandingTheme'; +import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import MaterialDesignDemo, { demoCode as materialDemoCode } from './MaterialDesignDemo'; +import ShowcaseContainer from './ShowcaseContainer'; +import { getMaterialThemeFrames, produceThemeOptions } from './showcaseUtils'; + +const defaultTheme = createTheme(); +const darkDesignTokens = getDesignTokens('dark'); + +let darkBrandingTheme = createTheme(darkDesignTokens); + +darkBrandingTheme = createTheme(darkBrandingTheme, { + components: { + ...getThemedComponents(darkBrandingTheme).components, + MuiButtonBase: { + defaultProps: { + disableTouchRipple: true, + }, + }, + MuiButton: { + defaultProps: { + disableElevation: true, + }, + styleOverrides: { + root: { + borderRadius: 40, + padding: darkBrandingTheme.spacing(0.5, 1), + }, + sizeSmall: { + fontSize: darkBrandingTheme.typography.pxToRem(12), + lineHeight: 18 / 12, + }, + text: { + color: darkBrandingTheme.palette.grey[400], + }, + outlined: { + color: '#fff', + backgroundColor: darkBrandingTheme.palette.primary[700], + borderColor: darkBrandingTheme.palette.primary[500], + '&:hover': { + backgroundColor: darkBrandingTheme.palette.primary[700], + }, + }, + }, + }, + }, +}); + +const CODES = [ + `const theme = createTheme({ + shape: { + borderRadius: 12, + },`, + ` + spacing: 10,`, + ` + shadows: [ + 'none', + '0px 4px 20px 0px hsla(210, 14%, 28%, 0.2)', + ],`, + ` + typography: { + fontFamily: '"IBM Plex Sans", sans-serif', + fontWeightBold: 500, + },`, + ` + palette: { + background: { + default: '#F3F6F9', + },`, + ` + divider: '#E5E8EC',`, + ` + primary: { + main: '#007FFF', + },`, + ` + text: { + primary: '#3D4752', + secondary: '#5A6978', + },`, + ` + success: { + main: '#1AA251', + light: '#6AE79C', + }, + },`, + ` + components: { + MuiAvatar: { + styleOverrides: { + root: { + width: 64, + height: 64, + }, + }, + },`, + ` + MuiCard: { + styleOverrides: { + root: { + border: '1px solid', + borderColor: '#D7DCE1', + }, + }, + },`, + ` + MuiIconButton: { + styleOverrides: { + root: { + border: '1px solid', + borderColor: '#E5E8EC', + color: '#5A6978', + '&:hover, &.Mui-focusVisible': { + borderColor: '#007FFF', + color: '#007FFF', + }, + }, + }, + },`, + ` + MuiSwitch: { + styleOverrides: { + root: { width: 32, height: 20, padding: 0 }, + switchBase: { height: 20, width: 20, padding: 0, + '&.Mui-checked + .MuiSwitch-track': { + opacity: 1, + }, + '&.Mui-checked': { + transform: 'translateX(11px)', + color: '#fff', + }, + }, + track: { + opacity: 1, + borderRadius: 32, + backgroundColor: '#BFC7CF' + }, + thumb: { width: 14, height: 14 }, + }, + }, + }, +});`, +]; + +const noop = () => {}; + +function TypeWriter({ + step = 0, + codes = CODES, + onStepComplete = noop, +}: { + step: number; + codes: Array; + onStepComplete: (step: number) => void; +}) { + const [result, setResult] = React.useState(``); + const index = React.useRef(0); + React.useEffect(() => { + index.current = 0; + if (step > 0) { + // by line + // const code = codes[step - 1].split('\n').map((text, i, array) => { + // if (i === array.length - 1) return text; + // return `${text}\n`; + // }); + + // by character + let code = codes[step - 1].split(''); + code = code.reduce((final, curr) => { + if ( + curr.match(/^\s*$/) && + final[final.length - 1] && + final[final.length - 1].match(/^\s*$/) + ) { + return [...final.slice(0, final.length - 1), `${final[final.length - 1]} `]; + } + return [...final, curr]; + }, [] as Array); + + const time = setInterval(() => { + if (index.current <= code.length - 1) { + setResult((current) => `${current}${code[index.current]}`); + } + index.current += 1; + if (index.current >= code.length) { + onStepComplete(step); + clearInterval(time); + } + }, 32); + return () => { + clearInterval(time); + }; + } + setResult(''); + return () => {}; + }, [codes, step, onStepComplete]); + return ; +} + +export default function CoreShowcase() { + const totalStep = CODES.length; + const theme = useTheme(); + const codeContainer = React.useRef(null); + const [step, setStep] = React.useState(0); + const [running, setRunning] = React.useState(false); + const [customized, setCustomized] = React.useState(false); + const codeImports = materialDemoCode.imports(customized); + const cursor = React.useRef(0); + // eslint-disable-next-line react-hooks/exhaustive-deps + const themeFrames = React.useMemo(() => getMaterialThemeFrames(theme), []); + const [customTheme, setCustomTheme] = React.useState(defaultTheme); + const updateTheme = React.useMemo( + () => + function handleUpdateTheme(latestStep: number) { + if (latestStep === totalStep) { + setRunning(false); + } + cursor.current += CODES[latestStep - 1].split('\n').length - 1; + const themeOptions = produceThemeOptions(themeFrames, latestStep); + setCustomTheme(createTheme(themeOptions)); + setTimeout(() => { + setStep((current) => (current < totalStep ? current + 1 : current)); + }, 1500); + }, + [themeFrames, totalStep], + ); + React.useEffect(() => { + if (customized && codeContainer.current) { + codeContainer.current.scrollTop = (cursor.current + codeImports.split('\n').length - 1) * 20; + } + if (step === 0 && customized) { + cursor.current = 0; + setRunning(true); + setCustomTheme(createTheme()); + const time = setTimeout(() => { + setStep(1); + }, 200); + return () => { + clearTimeout(time); + }; + } + return () => {}; + }, [step, customized, codeImports]); + React.useEffect(() => { + if (customized) { + setStep(0); + setRunning(true); + setCustomTheme(createTheme()); + const time = setTimeout(() => { + setStep(1); + }, 200); + return () => { + clearTimeout(time); + }; + } + setCustomTheme(createTheme()); + return () => {}; + }, [customized]); + return ( + + + + +
    + } + code={ + + {running && ( + + )} + + {!running && ( + + + + {customized && !running && ( + + )} + + )} + {customized && running && ( + + Animation is playing... + + )} + + + + {customized && } + {customized && } + + + + + } + /> + ); +} diff --git a/docs/src/components/home/DesignKits.tsx b/docs/src/components/home/DesignKits.tsx new file mode 100644 index 00000000000000..2226523f126b8e --- /dev/null +++ b/docs/src/components/home/DesignKits.tsx @@ -0,0 +1,98 @@ +import * as React from 'react'; +import { styled } from '@material-ui/core/styles'; +import Avatar from '@material-ui/core/Avatar'; +import Fade from '@material-ui/core/Fade'; +import Box from '@material-ui/core/Box'; + +const Image = styled('img')({ + display: 'block', + position: 'absolute', + top: 0, + right: 0, + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'top left', +}); + +export default function DesignKits() { + const [appearIndexes, setAppearIndexes] = React.useState>([0]); + React.useEffect(() => { + const time = setTimeout(() => { + if (appearIndexes.length < 3) { + setAppearIndexes((current) => [...current, current.length]); + } + }, 200); + return () => { + clearTimeout(time); + }; + }, [appearIndexes]); + return ( + + + + + (theme.palette.mode === 'dark' ? 'primaryDark.900' : 'grey.50'), + }} + /> + + + + `drop-shadow(0px 3.57436px 44.6795px ${ + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[900] + : 'rgba(90, 105, 120, 0.25)' + })`, + }, + }} + > + + + + + + + + + + + + ); +} diff --git a/docs/src/components/home/DesignSystemComponents.tsx b/docs/src/components/home/DesignSystemComponents.tsx new file mode 100644 index 00000000000000..4e4e23bf31f0a0 --- /dev/null +++ b/docs/src/components/home/DesignSystemComponents.tsx @@ -0,0 +1,537 @@ +import * as React from 'react'; +import NextLink from 'next/link'; +import { + styled, + createTheme, + ThemeProvider, + useTheme, + Theme, + ThemeOptions, +} from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Alert from '@material-ui/core/Alert'; +import Container from '@material-ui/core/Container'; +import Chip from '@material-ui/core/Chip'; +import Tabs from '@material-ui/core/Tabs'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import Paper from '@material-ui/core/Paper'; +import Tab from '@material-ui/core/Tab'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableContainer from '@material-ui/core/TableContainer'; +import TableHead from '@material-ui/core/TableHead'; +import TableRow from '@material-ui/core/TableRow'; +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import ShoppingCartRounded from '@material-ui/icons/ShoppingCartRounded'; +import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; +import GradientText from 'docs/src/components/typography/GradientText'; +import CheckCircleRounded from '@material-ui/icons/CheckCircleRounded'; +import MailRounded from '@material-ui/icons/MailRounded'; +import VerifiedUserRounded from '@material-ui/icons/VerifiedUserRounded'; +import HelpCenterRounded from '@material-ui/icons/HelpCenterRounded'; +import ROUTES from 'docs/src/route'; + +const Grid = styled('div')(({ theme }) => ({ + borderRadius: theme.shape.borderRadius, + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.background.paper : theme.palette.grey[50], + // borderColor: theme.palette.divider, + display: 'grid', + gridTemplateColumns: '1fr', + gridAutoRows: '240px', + [theme.breakpoints.up('sm')]: { + paddingTop: 1, + gridTemplateColumns: '1fr 1fr', + }, + [theme.breakpoints.up('md')]: { + gridTemplateColumns: '1fr 1fr 1fr', + }, + '& > div': { + padding: theme.spacing(2), + alignSelf: 'stretch', + border: '1px solid', + borderColor: theme.palette.divider, + '&:last-of-type': { + backgroundColor: theme.palette.background.default, + }, + [theme.breakpoints.only('xs')]: { + '&:first-of-type': { + borderTopLeftRadius: theme.shape.borderRadius, + borderTopRightRadius: theme.shape.borderRadius, + }, + '&:last-of-type': { + borderBottomLeftRadius: theme.shape.borderRadius, + borderBottomRightRadius: theme.shape.borderRadius, + borderStyle: 'dashed', + }, + '&:not(:first-of-type)': { + marginTop: -1, + }, + }, + [theme.breakpoints.only('sm')]: { + marginTop: -1, + '&:first-of-type': { + borderTopLeftRadius: theme.shape.borderRadius, + }, + '&:last-of-type': { + borderBottomRightRadius: theme.shape.borderRadius, + borderStyle: 'dashed', + }, + '&:nth-of-type(even)': { + marginLeft: -1, + }, + '&:nth-last-of-type(2)': { + borderBottomLeftRadius: theme.shape.borderRadius, + }, + '&:nth-of-type(2)': { + borderTopRightRadius: theme.shape.borderRadius, + }, + }, + [theme.breakpoints.up('md')]: { + marginTop: -1, + '&:not(:nth-of-type(3n + 1))': { + marginLeft: -1, + }, + '&:first-of-type': { + borderTopLeftRadius: theme.shape.borderRadius, + }, + '&:last-of-type': { + borderBottomRightRadius: theme.shape.borderRadius, + borderStyle: 'dashed', + }, + '&:nth-last-of-type(3)': { + borderBottomLeftRadius: theme.shape.borderRadius, + }, + '&:nth-of-type(3)': { + borderTopRightRadius: theme.shape.borderRadius, + }, + }, + }, +})); + +function Demo({ + name, + children, + control, + ...props +}: { + name: string; + theme: Theme; + children: React.ReactElement; + control?: { prop: string; values: Array; defaultValue?: string }; +}) { + const [propValue, setPropValue] = React.useState( + control ? control.defaultValue || control.values[0] : '', + ); + return ( + + {control ? ( + + setPropValue(value)} + sx={{ + minHeight: 'initial', + '& .MuiTabs-indicator': { + bgcolor: 'transparent', + '&:before': { + height: '100%', + content: '""', + display: 'block', + width: (theme) => `calc(100% - ${theme.spacing(2)})`, + bgcolor: 'primary.main', + position: 'absolute', + top: 0, + left: (theme) => theme.spacing(1), + }, + }, + '& .MuiTab-root': { + px: 1, + pt: 0.5, + minWidth: 'initial', + minHeight: 'initial', + fontWeight: 'medium', + }, + }} + > + {control.values.map((value) => ( + + ))} + + + ) : null} + + + {React.cloneElement(children, { + ...(control && { + [control.prop]: propValue, + }), + })} + + + + {name} + + + ); +} + +const StyledChip = styled(Chip)(({ theme }) => ({ + fontWeight: 600, + transition: 'none', + '&.MuiChip-outlined': { + border: 'none', + color: theme.palette.text.secondary, + }, + '&.MuiChip-clickable:active': { + boxShadow: 'none', + }, + '&.MuiChip-filled': { + border: '1px solid', + borderColor: theme.palette.primary[300], + }, +})); + +function buildTheme(theme: Theme): ThemeOptions { + return { + palette: { + ...theme.palette, + primary: { + ...theme.palette.primaryDark, + main: theme.palette.primaryDark[800], + }, + grey: theme.palette.grey, + info: { + main: theme.palette.primaryDark[600], + }, + }, + shape: { + borderRadius: 10, + }, + spacing: 10, + typography: { + ...theme.typography, + button: { + ...theme.typography.button, + fontSize: '1rem', + lineHeight: 24 / 16, + }, + }, + components: { + MuiButtonBase: { + defaultProps: { + disableTouchRipple: true, + }, + }, + MuiButton: { + defaultProps: { + disableElevation: true, + }, + styleOverrides: { + text: { + color: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[100] + : theme.palette.primaryDark[800], + }, + sizeMedium: { + padding: theme.spacing(1, 2), + }, + sizeLarge: { + padding: theme.spacing(1.5, 2.5), + fontSize: '1rem', + lineHeight: 24 / 16, + }, + iconSizeSmall: { + '& > *:nth-of-type(1)': { + fontSize: 16, + }, + }, + iconSizeMedium: { + '& > *:nth-of-type(1)': { + fontSize: 16, + }, + }, + }, + }, + MuiAlert: { + styleOverrides: { + root: { + padding: theme.spacing(2), + }, + message: { + padding: 0, + fontWeight: 600, + }, + standardInfo: { + backgroundColor: theme.palette.primaryDark[100], + color: theme.palette.primaryDark[600], + '& .MuiAlert-icon': { + color: theme.palette.primaryDark[600], + }, + }, + icon: { + paddingTop: 1, + paddingBottom: 0, + '& > *': { + fontSize: 18, + }, + }, + }, + }, + MuiTextField: { + styleOverrides: { + root: { + '& .MuiInputLabel-outlined.Mui-focused': { + color: + theme.palette.mode === 'dark' ? theme.palette.grey[500] : theme.palette.grey[800], + }, + '& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': { + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primary[500] + : theme.palette.primaryDark[800], + }, + '& .MuiOutlinedInput-input': { + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : '#fff', + borderRadius: theme.spacing(1), + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[400] + : theme.palette.grey[300], + }, + '& .MuiInputBase-input': { + fontWeight: 600, + }, + '& .MuiFilledInput-root': { + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : '#fff', + '&:after': { + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primary[500] + : theme.palette.primaryDark[800], + }, + '&:hover': { + backgroundColor: + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : '#fff', + }, + }, + '& .MuiInputLabel-filled.Mui-focused': { + color: + theme.palette.mode === 'dark' ? theme.palette.grey[500] : theme.palette.grey[800], + }, + '& .MuiInput-root.Mui-focused': { + '&:after': { + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primary[500] + : theme.palette.primaryDark[800], + }, + }, + '& .MuiInputLabel-root.Mui-focused': { + color: + theme.palette.mode === 'dark' ? theme.palette.grey[500] : theme.palette.grey[800], + }, + }, + }, + }, + MuiTableCell: theme.components?.MuiTableCell, + MuiPopover: { + styleOverrides: { + paper: { + boxShadow: '0px 4px 20px rgba(170, 180, 190, 0.1)', + }, + }, + }, + MuiMenu: { + styleOverrides: { + list: { + padding: theme.spacing(1, 0), + }, + }, + }, + MuiMenuItem: { + styleOverrides: { + root: { + padding: theme.spacing(1, 2), + '& svg': { + fontSize: 18, + color: theme.palette.primaryDark[400], + }, + }, + }, + }, + }, + }; +} + +const DesignSystemComponents = () => { + const [anchor, setAnchor] = React.useState(null); + const [customized, setCustomized] = React.useState(false); + const globalTheme = useTheme(); + const mode = globalTheme.palette.mode; + const [theme, setTheme] = React.useState(createTheme({ palette: { mode } })); + React.useEffect(() => { + setTheme(createTheme(customized ? buildTheme(globalTheme) : { palette: { mode } })); + }, [mode, customized, globalTheme]); + return ( + + + What do you get? + + + Simple, accessible, declarative components. + + + setCustomized(true)} + /> + setCustomized(false)} + sx={{ ml: 1 }} + /> + + +
    + + + +
    +
    + + }> + Check out this alert! + + +
    +
    + + + +
    +
    + + + + setAnchor(null)} + PaperProps={{ variant: 'outlined' }} + > + + + + + Contact + + + + + + Security + + + + + + About us + + + + +
    +
    + + .MuiTableRow-root:last-of-type > .MuiTableCell-root': { + borderBottomWidth: 0, + }, + }} + > + + + + Dessert + Calories + + + + + Frozen yoghurt + 109 + + + Cupcake + 305 + + +
    +
    +
    +
    + + + Want more components? + + + Check the documentation to see the detais of every component! + + + + + +
    +
    + ); +}; + +export default DesignSystemComponents; diff --git a/docs/src/components/home/GetStartedButtons.tsx b/docs/src/components/home/GetStartedButtons.tsx new file mode 100644 index 00000000000000..f31e125c947e98 --- /dev/null +++ b/docs/src/components/home/GetStartedButtons.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import copy from 'clipboard-copy'; +import NextLink from 'next/link'; +import Box, { BoxProps } from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; +import ContentCopyRounded from '@material-ui/icons/ContentCopyRounded'; +import CheckRounded from '@material-ui/icons/CheckRounded'; +import ROUTES from 'docs/src/route'; + +export default function GetStartedButtons(props: BoxProps) { + const [copied, setCopied] = React.useState(false); + const installation = 'npm install @mui/core'; + const handleCopy = () => { + setCopied(true); + copy(installation).then(() => { + setTimeout(() => setCopied(false), 2000); + }); + }; + return ( + *': { minWidth: 'clamp(0px, (449px - 100%) * 999 ,100%)' }, + ...props.sx, + }} + > + + + + + + + ); +} diff --git a/docs/src/components/home/Hero.tsx b/docs/src/components/home/Hero.tsx index 4822d032fcdaa5..f2bb3f4fe813a9 100644 --- a/docs/src/components/home/Hero.tsx +++ b/docs/src/components/home/Hero.tsx @@ -1,12 +1,104 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; -import Button from '@material-ui/core/Button'; import Container from '@material-ui/core/Container'; import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; -import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; -import ContentCopyRounded from '@material-ui/icons/ContentCopyRounded'; -import GradientText from 'docs/src/components/GradientText'; +import GradientText from 'docs/src/components/typography/GradientText'; +import PlayerCard from 'docs/src/pages/components/cards/PlayerCard'; +import TaskCard from 'docs/src/pages/components/cards/TaskCard'; +import NotificationCard from 'docs/src/pages/components/cards/NotificationCard'; +import ThemeChip from 'docs/src/pages/components/chips/ThemeChip'; +import ThemeDatePicker from 'docs/src/pages/components/date-picker/ThemeDatePicker'; +import ThemeSlider from 'docs/src/pages/components/slider/ThemeSlider'; +import FolderTable from 'docs/src/pages/components/tables/FolderTable'; +import ThemeTabs from 'docs/src/pages/components/tabs/ThemeTabs'; +import ThemeTimeline from 'docs/src/pages/components/timeline/ThemeTimeline'; +import ViewToggleButton from 'docs/src/pages/components/toggle-button/ViewToggleButton'; +import GetStartedButtons from 'docs/src/components/home/GetStartedButtons'; + +const MAX_WIDTH = 1000; +const SPAN_SIZE = 10; +const GAP = 0; +const GUTTER = 30; +const grid = [ + { + ui: , + width: 330, + height: 280, + sx: { + '& > .MuiCard-root': { + height: '100%', + width: '100%', + maxWidth: '100%', + }, + }, + }, + { + ui: , + width: 320, + height: 380, + }, + { + width: MAX_WIDTH - (320 + GUTTER) - (320 + GUTTER), + height: 388, + }, + { + ui: , + width: 70, + height: 180, + }, + { + ui: , + width: 180, + height: 70, + sx: { alignSelf: 'flex-end' }, + }, + { + width: MAX_WIDTH - (320 + GUTTER) - (320 + GUTTER), + height: 135, + }, + { + ui: , + width: 220, + height: 32, + sx: { alignSelf: 'center' }, + }, + { + ui: , + width: 313, + height: 119, + }, + { + ui: ( + + + + ), + width: 310, + height: 50, + }, + { + ui: , + width: 379, + height: 100, + }, + { + ui: , + width: 260, + height: 188, + }, + { + ui: , + width: 270, + height: 160, + }, +]; + +function getSpan(value: number) { + // x * SPAN_SIZE + (x - 1) * GAP = width + // x * (SPAN_SIZE + GAP) = width + GAP + return Math.ceil((value + GAP) / (SPAN_SIZE + GAP)); +} export default function Hero() { return ( @@ -16,6 +108,7 @@ export default function Hero() { minHeight: 500, height: 'calc(100vh - 120px)', maxHeight: { xs: 500, sm: 700, xl: 1000 }, + transition: '0.3s', }} > - + The ultimate solution for your UI. - MUI provides robust, customizable, and accessible components, enabling you to build - React applications faster. With a trusted open-source community and beautiful - designs, developing UIs have never been easier. + MUI provides a robust, customizible and accessible library of foundational and + advanced components, enabling you to build your own design system and develop React + applications faster. - *': { minWidth: 'clamp(0px, (449px - 100%) * 999 ,100%)' }, - }} - > - - - - + diff --git a/docs/src/components/home/HeroEnd.tsx b/docs/src/components/home/HeroEnd.tsx new file mode 100644 index 00000000000000..414feeb463bfdd --- /dev/null +++ b/docs/src/components/home/HeroEnd.tsx @@ -0,0 +1,87 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; +import Grid from '@material-ui/core/Grid'; +import Typography from '@material-ui/core/Typography'; +import Paper from '@material-ui/core/Paper'; +import Link from 'docs/src/modules/components/Link'; +import GradientText from 'docs/src/components/typography/GradientText'; +import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; +import ROUTES from 'docs/src/route'; +import GetStartedButtons from 'docs/src/components/home/GetStartedButtons'; + +const HeroEnd = () => { + return ( + + theme.palette.mode === 'dark' + ? `linear-gradient(180deg, ${theme.palette.primaryDark[900]} 0%, #001E3C 100%)` + : `linear-gradient(180deg, ${theme.palette.grey[50]} 0%, #FFFFFF 100%)`, + }} + > + + + + + Go live! + + + Start building with MUI today! + + + Check it for yourself, give it a try and share with us what you've built! + + *': { minWidth: 'clamp(0px, (426px - 100%) * 999 ,100%)' } }} + /> + + + + + + Showcases + + + See more projects and companies out there relying on MUI. + + + Learn more{' '} + + + + + + + + Blog + + + Check behind the scenes and news from the company. + + + Learn more{' '} + + + + + + + + + ); +}; + +export default HeroEnd; diff --git a/docs/src/components/home/MaterialDesignDemo.tsx b/docs/src/components/home/MaterialDesignDemo.tsx new file mode 100644 index 00000000000000..54613d57544322 --- /dev/null +++ b/docs/src/components/home/MaterialDesignDemo.tsx @@ -0,0 +1,145 @@ +import * as React from 'react'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import IconButton from '@material-ui/core/IconButton'; +import Card from '@material-ui/core/Card'; +import Switch from '@material-ui/core/Switch'; +import Typography from '@material-ui/core/Typography'; +import Edit from '@material-ui/icons/Edit'; +import LocationOn from '@material-ui/icons/LocationOn'; +import BusinessRounded from '@material-ui/icons/BusinessRounded'; + +export const demoCode = { + imports: (themed = false) => `import * as React from 'react'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import IconButton from '@material-ui/core/IconButton'; +import Card from '@material-ui/core/Card'; +import Switch from '@material-ui/core/Switch'; +import Typography from '@material-ui/core/Typography'; +import Edit from '@material-ui/icons/Edit'; +import LocationOn from '@material-ui/icons/LocationOn'; +import BusinessRounded from '@material-ui/icons/BusinessRounded'; +${themed ? `import { ThemeProvider, createTheme } from '@material-ui/core/styles';\n` : ``}`, + component: (themed = false) => { + const jsx = ` + + + + Michael Scott + + + Scranton, PA + + + + Michael Scott + + + + + + + + + + + {active ? 'Active' : 'Inactive'} account + + setActive(event.target.checked)} + sx={{ ml: 'auto' }} + /> + + `; + return `export default function MaterialDesignDemo() { + const [active, setActive] = React.useState(true); + return ( + ${ + themed + ? ` + ${jsx + .split('\n') + .map((line) => line.padStart(line.length + 2, ' ')) + .join('\n')} + ` + : jsx + } + ); +}`; + }, +}; + +export default function MaterialDesignDemo() { + const [active, setActive] = React.useState(true); + return ( + + + + + Michael Scott + + + Scranton, PA + + + + Michael Scott + + + + + + + + + + + {active ? 'Active' : 'Inactive'} account + + setActive(event.target.checked)} + sx={{ ml: 'auto' }} + /> + + + ); +} diff --git a/docs/src/components/home/ProductSuite.tsx b/docs/src/components/home/ProductSuite.tsx new file mode 100644 index 00000000000000..83d9c763884a76 --- /dev/null +++ b/docs/src/components/home/ProductSuite.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import Grid from '@material-ui/core/Grid'; +import Container from '@material-ui/core/Container'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; +import GradientText from 'docs/src/components/typography/GradientText'; +import ProductsSwitcher from 'docs/src/components/home/ProductsSwitcher'; +import CoreShowcase from 'docs/src/components/home/CoreShowcase'; +import ShowcaseContainer from 'docs/src/components/home/ShowcaseContainer'; +import StoreTemplatesBanner from 'docs/src/components/home/StoreTemplatesBanner'; +import DesignKits from 'docs/src/components/home/DesignKits'; + +const ProductSuite = () => { + const [productIndex, setProductIndex] = React.useState(0); + return ( + (theme.palette.mode === 'dark' ? 'primaryDark.900' : 'grey.50'), + py: { xs: 4, sm: 6, md: 8 }, + overflow: 'hidden', + }} + > + + + + + + Products + + + Extensive library of components, ready for production. + + + We bring together a suite of products integrated to make your life easier when it + comes to setting up design systems. + + + + + + {productIndex === 0 && } + {productIndex === 1 && } + {productIndex === 2 && } + {productIndex === 3 && } + + + + + ); +}; + +export default ProductSuite; diff --git a/docs/src/components/home/ProductsSwitcher.tsx b/docs/src/components/home/ProductsSwitcher.tsx new file mode 100644 index 00000000000000..1c83d393c576a1 --- /dev/null +++ b/docs/src/components/home/ProductsSwitcher.tsx @@ -0,0 +1,235 @@ +import * as React from 'react'; +import NextLink from 'next/link'; +import SwipeableViews from 'react-swipeable-views'; +import Box, { BoxProps } from '@material-ui/core/Box'; +import Link from '@material-ui/core/Link'; +import Tabs from '@material-ui/core/Tabs'; +import Tab from '@material-ui/core/Tab'; +import Typography from '@material-ui/core/Typography'; +import SvgProductCore from 'docs/src/icons/SvgProductCore'; +import SvgProductAdvanced from 'docs/src/icons/SvgProductAdvanced'; +import SvgProductTemplates from 'docs/src/icons/SvgProductTemplates'; +import SvgProductDesign from 'docs/src/icons/SvgProductDesign'; +import SvgMuiX from 'docs/src/icons/SvgMuiX'; + +import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; +import ROUTES from 'docs/src/route'; + +function ProductItem({ + icon, + name, + description, + href, +}: { + icon: React.ReactNode; + name: React.ReactNode; + description: React.ReactNode; + href: string; +}) { + return ( + + {icon} + + + {name} + + + {description} + + + svg': { transition: '0.2s' }, + '&:hover > svg': { transform: 'translateX(4px)' }, + }} + onClick={(event: React.MouseEvent) => { + event.stopPropagation(); + }} + > + Learn more{' '} + + + + + + ); +} + +function Highlight({ + children, + selected = false, + onClick, + sx, +}: { + children: React.ReactNode; + selected?: boolean; + onClick?: BoxProps['onClick']; + sx?: BoxProps['sx']; +}) { + return ( + + theme.palette.mode === 'dark' ? 'primaryDark.700' : 'background.paper', + borderColor: (theme) => (theme.palette.mode === 'dark' ? 'primaryDark.400' : 'grey.200'), + }), + ...(!selected && { + '&:hover': { + bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'primaryDark.800' : 'grey.100'), + '@media (hover: none)': { + bgcolor: 'transparent', + }, + }, + borderColor: 'transparent', + }), + ...sx, + }} + > + {children} + + ); +} + +const ProductsSwitcher = ({ + productIndex, + setProductIndex, +}: { + productIndex: number; + setProductIndex: React.Dispatch>; +}) => { + const productElements = [ + } + name="Core" + description="Ready to use, forever free, foundational components." + href={ROUTES.productCore} + />, + } + name={ + + Advanced  + + } + description="Powerful and robust components for your complex apps." + href={ROUTES.productAdvanced} + />, + } + name="Templates" + description="Fully built, out-of-the-box, templates for your application." + href={ROUTES.productTemplates} + />, + } + name="Design Kits" + description="Our components available in your favorite design tool." + href={ROUTES.productDesignKits} + />, + ]; + return ( + + div': { pr: '32%' }, + }} + > + setProductIndex(index)} + > + {productElements.map((elm, index) => ( + setProductIndex(index)} + selected={productIndex === index} + sx={{ transform: productIndex !== index ? 'scale(0.9)' : 'scale(1)' }} + > + {elm} + + ))} + + + setProductIndex(value)} + sx={{ + display: { xs: 'none', md: 'flex' }, + mt: 4, + maxWidth: 470, + overflow: 'initial', + '& .MuiTabs-scroller': { overflow: 'initial !important' }, + '& .MuiTabs-flexContainer': { position: 'relative', zIndex: 1 }, + '& .MuiTab-root': { + maxWidth: 'initial', + textAlign: 'left', + padding: 0, + alignItems: 'flex-start', + borderRadius: 1, + transition: '0.3s', + '&.Mui-selected:hover': { + boxShadow: 'inset 0 0 0 1px, 1px 1px 20px 0 rgb(90 105 120 / 20%)', + }, + '&:hover:not(.Mui-selected)': { + bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'primaryDark.800' : 'grey.100'), + '@media (hover: none)': { + bgcolor: 'transparent', + }, + }, + '&:not(:first-of-type)': { + mt: 1, + }, + }, + '& .MuiTabs-indicator': { + width: '100%', + bgcolor: (theme) => + theme.palette.mode === 'dark' ? 'primaryDark.700' : 'background.paper', + borderRadius: 1, + border: '1px solid', + borderColor: (theme) => + theme.palette.mode === 'dark' ? 'primaryDark.400' : 'grey.200', + }, + '& svg > circle': { + fill: (theme) => + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[700] + : theme.palette.grey[100], + }, + }} + > + {productElements.map((elm, index) => ( + + ))} + + + ); +}; + +export default ProductsSwitcher; diff --git a/docs/src/components/home/References.tsx b/docs/src/components/home/References.tsx deleted file mode 100644 index 8d53c4ab64ad12..00000000000000 --- a/docs/src/components/home/References.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as React from 'react'; -import Grid from '@material-ui/core/Grid'; - -const References = () => { - return ( - - - Coursera logo - - - Amazon logo - - - Nasa logo - - - Netflix logo - - - Unity logo - - - Shutterstock logo - - - ); -}; - -export default References; diff --git a/docs/src/components/home/ReferencesCore.tsx b/docs/src/components/home/ReferencesCore.tsx new file mode 100644 index 00000000000000..331fd20c756299 --- /dev/null +++ b/docs/src/components/home/ReferencesCore.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import Container from '@material-ui/core/Container'; +import Typography from '@material-ui/core/Typography'; +import CompaniesGrid, { CORE_COMPANIES } from 'docs/src/components/home/CompaniesGrid'; + +const ReferencesCore = () => { + return ( + + + (theme.palette.mode === 'dark' ? 'grey.500' : 'grey.800')} + maxWidth={450} + textAlign="center" + mx="auto" + mt={4} + variant="body2" + > + From startups to Fortune 500s, the world's best product teams leverage MUI to build + their UIs. + + + ); +}; + +export default ReferencesCore; diff --git a/docs/src/components/home/ShowcaseContainer.tsx b/docs/src/components/home/ShowcaseContainer.tsx new file mode 100644 index 00000000000000..ad364c47efe163 --- /dev/null +++ b/docs/src/components/home/ShowcaseContainer.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Paper from '@material-ui/core/Paper'; + +export default function ShowcaseContainer({ + preview, + code, +}: { + preview?: React.ReactNode; + code?: React.ReactNode; +}) { + return ( + + (theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.100'), + borderColor: (theme) => (theme.palette.mode === 'dark' ? 'primaryDark.400' : 'grey.300'), + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, + '&& *:not([class*="MuiSwitch"])': { + transition: '0.7s', + }, + '&& [class*="MuiSwitch"]': { + transition: '0.3s', + }, + }} + > + {preview} + + + theme.palette.mode === 'dark' ? 'primaryDark.700' : 'primaryDark.900', + bgcolor: 'primaryDark.800', + borderBottomLeftRadius: 10, + borderBottomRightRadius: 10, + }} + > + {code} + + + ); +} diff --git a/docs/src/components/home/Sponsors.tsx b/docs/src/components/home/Sponsors.tsx new file mode 100644 index 00000000000000..0126ad011ea509 --- /dev/null +++ b/docs/src/components/home/Sponsors.tsx @@ -0,0 +1,226 @@ +import * as React from 'react'; +import Avatar from '@material-ui/core/Avatar'; +import Box, { BoxProps } from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import Link from 'docs/src/modules/components/Link'; +import IconButton from '@material-ui/core/IconButton'; +import AddRounded from '@material-ui/icons/AddRounded'; + +const DIAMONDs = [ + { + logo: 'https://avatars3.githubusercontent.com/u/1287123?s=256', + name: 'Octopus Deploy', + description: 'Repetable relayable deployments.', + href: 'https://octopus.com/', + }, + { + logo: 'https://avatars3.githubusercontent.com/u/8424863?s=256', + name: 'Doit International', + description: 'Management platform for Google Clound and AWS.', + href: 'https://www.doit-intl.com/', + }, +]; +const GOLDs = [ + { + logo: 'https://github.com/tidelift.png?size=96', + name: 'Tidelift', + description: 'Enterprise-ready open source software.', + href: 'https://tidelift.com/', + }, + { + logo: 'https://github.com/teambit.png?size=96', + name: 'Bit', + description: 'The fastest way to share code.', + href: 'https://bit.dev/', + }, + { + logo: 'https://images.opencollective.com/callemall/a6946da/logo/96.png', + name: 'Text-em-all', + description: 'The easy way to message your group.', + href: 'https://www.text-em-all.com/', + }, + { + logo: 'https://images.opencollective.com/canadacasino/5b19004/logo/96.png', + name: 'Canada Casino', + description: 'Safe and rewarding online casino experience', + href: 'https://casinocanada.com/', + }, +]; + +function Label({ + color, + children, + sx, + darker = false, +}: { + color: 'primary' | 'warning'; + children: React.ReactNode; + sx?: BoxProps['sx']; + darker?: boolean; +}) { + return ( + + theme.palette.mode === 'dark' ? `${color}.${darker ? '900' : '800'}` : `${color}.50`, + color: (theme) => + theme.palette.mode === 'dark' ? `${color}.100` : `${color}.${darker ? '800' : '500'}`, + display: 'flex', + alignItems: 'center', + typography: 'body2', + fontWeight: 600, + p: 1, + ...sx, + }} + > + + theme.palette.mode === 'dark' + ? `${color}.${darker ? '800' : '300'}` + : `${color}.${darker ? '800' : '500'}`, + border: '3px solid', + borderColor: (theme) => + theme.palette.mode === 'dark' + ? `${color}.${darker ? '300' : '500'}` + : `${color}.${darker ? '300' : '100'}`, + }} + /> + {children} + + ); +} + +const Sponsors = () => { + return ( + + + Our sponsors + + + The continued development and maintenance of Material-UI is greatly helped by our generous + sponsors. + + + {DIAMONDs.map((item) => ( + + + + + + + {item.name} + + + {item.description} + + + + + + + ))} + + + theme.palette.mode === 'dark' ? 'primaryDark.400' : 'grey.300', + }} + > + + + + + + Become our sponsor! + + + To join us, contact us at{' '} + + diamond@material-ui.com + {' '} + for pre-approval. + + + + + + + {GOLDs.map((item) => ( + + + + + + + {item.name} + + + {item.description} + + + + + + + ))} + + + ); +}; + +export default Sponsors; diff --git a/docs/src/components/home/StoreTemplatesBanner.tsx b/docs/src/components/home/StoreTemplatesBanner.tsx new file mode 100644 index 00000000000000..f364a912553cb7 --- /dev/null +++ b/docs/src/components/home/StoreTemplatesBanner.tsx @@ -0,0 +1,166 @@ +import * as React from 'react'; +import { styled } from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; +import Fade from '@material-ui/core/Fade'; + +const ratio = 1367 / 939; + +const Image = styled('img')(({ theme }) => ({ + display: 'block', + width: 200, + height: 200 / ratio, + [theme.breakpoints.up('sm')]: { + width: 300, + height: 300 / ratio, + }, + [theme.breakpoints.up('md')]: { + width: 450, + height: 450 / ratio, + }, + border: '6px solid', + borderColor: theme.palette.mode === 'dark' ? theme.palette.grey[800] : theme.palette.grey[400], + borderRadius: theme.shape.borderRadius, + objectFit: 'cover', + filter: 'drop-shadow(0px 4px 20px rgba(61, 71, 82, 0.25))', +})); + +export default function StoreTemplatesBanner() { + const [appearIndexes, setAppearIndexes] = React.useState>([0]); + React.useEffect(() => { + const time = setTimeout(() => { + if (appearIndexes.length < 6) { + setAppearIndexes((current) => [...current, current.length]); + } + }, 200); + return () => { + clearTimeout(time); + }; + }, [appearIndexes]); + return ( + + (theme.palette.mode === 'dark' ? 'primaryDark.900' : 'grey.50'), + opacity: (theme) => (theme.palette.mode === 'dark' ? 0.6 : 0), + zIndex: 1, + }} + /> + + `linear-gradient(to bottom, ${ + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[900] + : theme.palette.grey[50] + } 0%, transparent 30%, transparent 70%, ${ + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[900] + : theme.palette.grey[50] + } 100%)`, + zIndex: 2, + }} + /> + + `linear-gradient(to right, ${ + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[900] + : theme.palette.grey[50] + }, transparent)`, + zIndex: 2, + }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/src/components/home/Testimonials.tsx b/docs/src/components/home/Testimonials.tsx new file mode 100644 index 00000000000000..d4fa7287ca37c3 --- /dev/null +++ b/docs/src/components/home/Testimonials.tsx @@ -0,0 +1,223 @@ +import * as React from 'react'; +import SwipeableViews from 'react-swipeable-views'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; +import Grid from '@material-ui/core/Grid'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import KeyboardArrowLeftRounded from '@material-ui/icons/KeyboardArrowLeftRounded'; +import KeyboardArrowRightRounded from '@material-ui/icons/KeyboardArrowRightRounded'; + +const data = [ + { title: '2M', metadata: 'Weekly downloads on npm' }, + { title: '70k', metadata: 'Stars on GitHub' }, + { title: '2k', metadata: 'Open-source contributors' }, + { title: '13k', metadata: 'Followers on Twitter' }, +]; + +const UserFeedback = ({ + quote, + profile, +}: { + quote: string; + profile: { + avatarSrc: string; + avatarSrcSet: string; + name: string; + role: string; + company?: React.ReactElement; + }; +}) => { + return ( +
    + + {quote} + + + + + + {profile.name},{' '} + + {profile.role} + + + {profile.company} + + +
    + ); +}; + +const TESTIMONIALS = [ + { + quote: + "“Material-UI offers a wide variety of high quality components that have allowed us to ship features faster. Material-UI has been used by more than a hundred engineers in our organization. What’s more, Material-UI's well architected customization system has allowed us to differentiate ourselves in the marketplace.”", + profile: { + avatarSrc: 'https://avatars.githubusercontent.com/u/28296253?s=58', + avatarSrcSet: 'https://avatars.githubusercontent.com/u/28296253?s=116 2x', + name: 'Joona Rahko', + role: 'Staff Software Engineer', + company: ( + Unity logo + ), + }, + }, + { + quote: + "“Material UI looks great and lets us deliver fast, thanks to their solid API design and documentation - it's refreshing to use a component library where you get everything you need from their site rather than Stack Overflow. We think the upcoming version, with extra themes and customizability, will make Material UI even more of a game changer. We're extremely grateful to the team for the time and effort spent maintaining the project.”", + profile: { + avatarSrc: 'https://avatars.githubusercontent.com/u/197016?s=58', + avatarSrcSet: 'https://avatars.githubusercontent.com/u/197016?s=116 2x', + name: 'Jean-Laurent de Morlhon', + role: 'VP of Engineering', + company: ( + Docker logo + ), + }, + }, + { + quote: + '“After much research on React component libraries, we decided to ditch our in-house library for Material UI, using its powerful customization system to implement our Design System. This simple move did a rare thing in engineering: it lowered our maintenance costs while enhancing both developer and customer experience. All of this was done without sacrificing the organization’s branding and visual identity.”', + profile: { + avatarSrc: 'https://avatars.githubusercontent.com/u/732422?s=58', + avatarSrcSet: 'https://avatars.githubusercontent.com/u/732422?s=116 2x', + name: 'Gustavo de Paula', + role: 'Specialist Software Engineer', + company: ( + Loggi logo + ), + }, + }, +]; + +const Testimonials = () => { + const [slideIndex, setSlideIndex] = React.useState(0); + + return ( + + + + + + + + setSlideIndex((i) => i - 1)} + > + + + setSlideIndex((i) => i + 1)} + > + + + + + {TESTIMONIALS.map((item, index) => ( + setSlideIndex(index)} + sx={{ + cursor: 'pointer', + display: 'inline-block', + width: 16, + height: 16, + p: '4px', + ml: index !== 0 ? '2px' : 0, + }} + > + + + ))} + + + setSlideIndex(index)}> + {TESTIMONIALS.map((item) => ( + + ))} + + + + + {data.map((item) => ( + + + + {item.title} + + {item.metadata} + + + ))} + + + + + ); +}; + +export default Testimonials; diff --git a/docs/src/components/home/ValueProposition.tsx b/docs/src/components/home/ValueProposition.tsx new file mode 100644 index 00000000000000..fc3cc8bacf5129 --- /dev/null +++ b/docs/src/components/home/ValueProposition.tsx @@ -0,0 +1,73 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import GradientText from 'docs/src/components/typography/GradientText'; + +const content = [ + { + icon: '/static/branding/mui-palette.svg', + title: 'Beautifully designed', + description: + "You can start your projects with Google's Material Design or leverage our carefully designed theming capabilities.", + }, + { + icon: '/static/branding/mui-pencil.svg', + title: 'Easy customizability', + description: + 'Enjoy the power of our components without sacrificing the styles you want. Tweak how your components render down to the very last class.', + }, + { + icon: '/static/branding/mui-docs.svg', + title: 'Superb documentation', + description: + "Our docs were shaped throughout the years with the help and experience of our trusted 2k people open-source community. It's all there!", + }, + { + icon: '/static/branding/mui-eye.svg', + title: 'Accessible by design', + description: + 'We care about making it good for everyone. All of our components have built-in support for a11y, making sure you reach the largest audience possible!', + }, +]; + +const ValueProposition = () => { + return ( + + + Why go with us? + + + Used by the world's best teams, supporting design systems of{' '} + all types. + + + {content.map(({ icon, title, description }) => ( + + + + + + {title} + + + + {description} + + + + ))} + + + ); +}; + +export default ValueProposition; diff --git a/docs/src/components/home/showcaseUtils.ts b/docs/src/components/home/showcaseUtils.ts new file mode 100644 index 00000000000000..3fde4ee77be397 --- /dev/null +++ b/docs/src/components/home/showcaseUtils.ts @@ -0,0 +1,142 @@ +import { deepmerge } from '@material-ui/utils'; +import { Theme, ThemeOptions } from '@material-ui/core/styles'; + +export const getMaterialThemeFrames = (theme: Theme) => { + const frames: Array = [ + { + shape: { + borderRadius: 12, + }, + }, + { + spacing: 10, + }, + { + shadows: [ + 'none', + '0px 4px 20px 0px hsla(210, 14%, 28%, 0.2)', + ] as unknown as ThemeOptions['shadows'], + }, + { + typography: { + fontFamily: '"IBM Plex Sans", sans-serif', + fontWeightBold: 500, + }, + }, + { + palette: { + background: { + default: theme.palette.grey[50], + }, + }, + }, + { + palette: { + divider: theme.palette.divider, + }, + }, + { + palette: { + primary: { + main: theme.palette.primary.main, + }, + }, + }, + { + palette: { + text: { + primary: theme.palette.grey[900], + secondary: theme.palette.grey[700], + }, + }, + }, + { + palette: { + success: { + main: '#1AA251', + light: '#6AE79C', + }, + }, + }, + { + components: { + MuiAvatar: { + styleOverrides: { + root: { + width: 64, + height: 64, + }, + }, + }, + }, + }, + { + components: { + MuiCard: { + styleOverrides: { + root: { + border: '1px solid', + borderColor: theme.palette.grey[300], + }, + }, + }, + }, + }, + { + components: { + MuiIconButton: { + styleOverrides: { + root: { + border: '1px solid', + borderColor: theme.palette.grey[200], + color: theme.palette.grey[800], + '&:hover, &.Mui-focusVisible': { + borderColor: theme.palette.primary.main, + color: theme.palette.primary.main, + }, + }, + }, + }, + }, + }, + { + components: { + MuiSwitch: { + styleOverrides: { + root: { + width: 32, + height: 20, + padding: 0, + }, + switchBase: { + height: 20, + width: 20, + padding: 0, + '&.Mui-checked + .MuiSwitch-track': { + opacity: 1, + }, + '&.Mui-checked': { + transform: 'translateX(11px)', + color: '#fff', + }, + }, + track: { + opacity: 1, + borderRadius: 32, + backgroundColor: 'rgb(179, 195, 211)', + }, + thumb: { + width: 14, + height: 14, + }, + }, + }, + }, + }, + ]; + return frames; +}; + +export const produceThemeOptions = (themeFrames: Array, frame: number) => { + return themeFrames.slice(0, frame).reduce((result, current) => deepmerge(result, current), {}); +}; diff --git a/docs/src/components/markdown/MarkdownElement.tsx b/docs/src/components/markdown/MarkdownElement.tsx new file mode 100644 index 00000000000000..e8f477b2939cc7 --- /dev/null +++ b/docs/src/components/markdown/MarkdownElement.tsx @@ -0,0 +1,242 @@ +import * as React from 'react'; +import clsx from 'clsx'; +import { + // alpha, + // darken, + styled, +} from '@material-ui/core/styles'; + +const Root = styled('div')(({ theme }) => ({ + ...theme.typography.body2, + color: theme.palette.text.primary, + // wordBreak: 'break-word', + // '& .anchor-link': { + // marginTop: -96, // Offset for the anchor. + // position: 'absolute', + // }, + '& pre': { + backgroundColor: theme.palette.primaryDark[800], + direction: 'ltr', + overflow: 'auto', + margin: 0, + lineHeight: '20px', + WebkitOverflowScrolling: 'touch', // iOS momentum scrolling. + maxWidth: 'calc(100vw - 32px)', + [theme.breakpoints.up('md')]: { + maxWidth: 'calc(100vw - 32px - 16px)', + }, + }, + // // inline code + // '& code': { + // direction: 'ltr', + // lineHeight: 1.4, + // display: 'inline-block', + // fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', + // WebkitFontSmoothing: 'subpixel-antialiased', + // padding: '0 3px', + // color: theme.palette.text.primary, + // backgroundColor: + // theme.palette.mode === 'light' + // ? 'rgba(255, 229, 100, 0.2)' + // : alpha(theme.palette.primary.main, 0.08), + // fontSize: '.85em', + // borderRadius: 2, + // }, + '& code[class*="language-"]': { + // Avoid layout jump after hydration (style injected by prism) + ...theme.typography.body2, + lineHeight: '20px', + fontFamily: theme.typography.fontFamilyCode, + WebkitFontSmoothing: 'subpixel-antialiased', + }, + // // code blocks + // '& pre code': { + // fontSize: '.9em', + // }, + // '& .token.operator': { + // background: 'transparent', + // }, + // '& h1': { + // ...theme.typography.h3, + // fontSize: 40, + // margin: '16px 0', + // }, + // '& .description': { + // ...theme.typography.h5, + // margin: '0 0 40px', + // }, + // '& h2': { + // ...theme.typography.h4, + // fontSize: 30, + // margin: '40px 0 16px', + // }, + // '& h3': { + // ...theme.typography.h5, + // margin: '40px 0 16px', + // }, + // '& h4': { + // ...theme.typography.h6, + // margin: '32px 0 16px', + // }, + // '& h5': { + // ...theme.typography.subtitle2, + // margin: '32px 0 16px', + // }, + // '& p, & ul, & ol': { + // marginTop: 0, + // marginBottom: 16, + // }, + // '& ul': { + // paddingLeft: 30, + // }, + // '& h1, & h2, & h3, & h4': { + // '& code': { + // fontSize: 'inherit', + // lineHeight: 'inherit', + // // Remove scroll on small screens. + // wordBreak: 'break-all', + // }, + // '& .anchor-link-style': { + // // To prevent the link to get the focus. + // display: 'none', + // }, + // '& a:not(.anchor-link-style):hover': { + // color: 'currentColor', + // borderBottom: '1px solid currentColor', + // textDecoration: 'none', + // }, + // '&:hover .anchor-link-style': { + // display: 'inline-block', + // padding: '0 8px', + // color: theme.palette.text.secondary, + // '&:hover': { + // color: theme.palette.text.primary, + // }, + // '& svg': { + // width: '0.7em', + // height: '0.7em', + // fill: 'currentColor', + // }, + // }, + // }, + // '& table': { + // // Trade display table for scroll overflow + // display: 'block', + // wordBreak: 'normal', + // width: '100%', + // overflowX: 'auto', + // WebkitOverflowScrolling: 'touch', // iOS momentum scrolling. + // borderCollapse: 'collapse', + // marginBottom: '16px', + // borderSpacing: 0, + // overflow: 'hidden', + // '& .prop-name': { + // fontFamily: 'Consolas, "Liberation Mono", Menlo, monospace', + // }, + // '& .required': { + // color: theme.palette.mode === 'light' ? '#006500' : '#a5ffa5', + // }, + // '& .optional': { + // color: theme.palette.type === 'light' ? '#080065' : '#a5b3ff', + // }, + // '& .prop-type': { + // fontFamily: 'Consolas, "Liberation Mono", Menlo, monospace', + // color: theme.palette.mode === 'light' ? '#932981' : '#ffb6ec', + // }, + // '& .prop-default': { + // fontFamily: 'Consolas, "Liberation Mono", Menlo, monospace', + // borderBottom: `1px dotted ${theme.palette.divider}`, + // }, + // }, + // '& td': { + // ...theme.typography.body2, + // borderBottom: `1px solid ${theme.palette.divider}`, + // padding: 16, + // color: theme.palette.text.primary, + // }, + // '& td code': { + // lineHeight: 1.6, + // }, + // '& th': { + // lineHeight: theme.typography.pxToRem(24), + // fontWeight: theme.typography.fontWeightMedium, + // color: theme.palette.text.primary, + // whiteSpace: 'pre', + // borderBottom: `1px solid ${theme.palette.divider}`, + // padding: 16, + // }, + // '& blockquote': { + // borderLeft: '5px solid #ffe564', + // backgroundColor: 'rgba(255,229,100,0.2)', + // padding: '4px 24px', + // margin: '24px 0', + // '& p': { + // marginTop: '16px', + // }, + // }, + // '& a, & a code': { + // // Style taken from the Link component + // color: theme.palette.primary.main, + // textDecoration: 'underline', + // textDecorationColor: alpha(theme.palette.primary.main, 0.4), + // '&:hover': { + // textDecorationColor: 'inherit', + // }, + // }, + // '& a code': { + // color: + // theme.palette.mode === 'dark' + // ? theme.palette.primary.main + // : darken(theme.palette.primary.main, 0.04), + // }, + // '& img, video': { + // maxWidth: '100%', + // }, + // '& img': { + // // Avoid layout jump + // display: 'inline-block', + // }, + // '& hr': { + // height: 1, + // margin: theme.spacing(6, 0), + // border: 0, + // flexShrink: 0, + // backgroundColor: theme.palette.divider, + // }, + // '& kbd.key': { + // // Style taken from GitHub + // padding: '4px 5px', + // display: 'inline-block', + // whiteSpace: 'nowrap', + // margin: '0 1px', + // font: '11px SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace', + // lineHeight: '10px', + // color: theme.palette.text.primary, + // verticalAlign: 'middle', + // backgroundColor: theme.palette.mode === 'dark' ? 'transparent' : '#fafbfc', + // border: `1px solid ${theme.palette.mode === 'dark' ? '#6e7681' : '#d1d5da'}`, + // borderRadius: 6, + // boxShadow: `inset 0 -1px 0 ${theme.palette.mode === 'dark' ? '#6e7681' : '#d1d5da'}`, + // }, +})); + +type MarkdownElementProps = { + renderedMarkdown: string; +} & Omit; + +const MarkdownElement = React.forwardRef( + function MarkdownElement(props, ref) { + const { className, renderedMarkdown, ...other } = props; + const more: Record = {}; + + if (typeof renderedMarkdown === 'string') { + // workaround for https://github.com/facebook/react/issues/17170 + // otherwise we could just set `dangerouslySetInnerHTML={undefined}` + more.dangerouslySetInnerHTML = { __html: renderedMarkdown }; + } + + return ; + }, +); + +export default MarkdownElement; diff --git a/docs/src/components/GradientText.tsx b/docs/src/components/typography/GradientText.tsx similarity index 61% rename from docs/src/components/GradientText.tsx rename to docs/src/components/typography/GradientText.tsx index f90f4df6d1ec1b..60f2d9e9b378e1 100644 --- a/docs/src/components/GradientText.tsx +++ b/docs/src/components/typography/GradientText.tsx @@ -3,7 +3,10 @@ import { styled } from '@material-ui/core/styles'; const GradientText = styled('span')<{ color?: 'primary' | 'error' | 'success' | 'warning'; }>(({ theme, color = 'primary' }) => ({ - background: `linear-gradient(to right, ${theme.palette[color].main}, ${theme.palette[color][700]})`, + background: + theme.palette.mode === 'dark' + ? theme.palette.primary.main + : `linear-gradient(to right, ${theme.palette[color].main}, ${theme.palette[color][700]})`, backgroundClip: 'text', WebkitTextFillColor: 'transparent', })); diff --git a/docs/src/icons/SvgHamburgerMenu.tsx b/docs/src/icons/SvgHamburgerMenu.tsx index 598ace122a5092..1136e456c2453f 100644 --- a/docs/src/icons/SvgHamburgerMenu.tsx +++ b/docs/src/icons/SvgHamburgerMenu.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgHamburgerMenu(props: React.SVGProps) { return ( ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgMuiLogo.tsx b/docs/src/icons/SvgMuiLogo.tsx index 115e3d4ca6f5d5..65872e42eac282 100644 --- a/docs/src/icons/SvgMuiLogo.tsx +++ b/docs/src/icons/SvgMuiLogo.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgMuiLogo(props: React.SVGProps) { return ( ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgMuiX.tsx b/docs/src/icons/SvgMuiX.tsx index 120abc5a178071..8d560284acbd71 100644 --- a/docs/src/icons/SvgMuiX.tsx +++ b/docs/src/icons/SvgMuiX.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgMuiX(props: React.SVGProps) { return ( ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgProductAdvanced.tsx b/docs/src/icons/SvgProductAdvanced.tsx index 808b99a5bbcf9f..3c7573faaae63f 100644 --- a/docs/src/icons/SvgProductAdvanced.tsx +++ b/docs/src/icons/SvgProductAdvanced.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgProductAdvanced(props: React.SVGProps) { return ( ) { ) { ) { ) { ) { ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgProductCore.tsx b/docs/src/icons/SvgProductCore.tsx index e7aabe94d9badb..395892f6ff84ce 100644 --- a/docs/src/icons/SvgProductCore.tsx +++ b/docs/src/icons/SvgProductCore.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgProductCore(props: React.SVGProps) { return ( ) { {...props} > - + ) { fill="#0059B3" /> - + ) { - + ) { - + ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgProductDesign.tsx b/docs/src/icons/SvgProductDesign.tsx index f2c1c7ed546844..d907506c8b216e 100644 --- a/docs/src/icons/SvgProductDesign.tsx +++ b/docs/src/icons/SvgProductDesign.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgProductDesign(props: React.SVGProps) { return ( ) { ); } - -export default SvgComponent; diff --git a/docs/src/icons/SvgProductTemplates.tsx b/docs/src/icons/SvgProductTemplates.tsx index d0d22ef4a47a26..c17ab35f98c477 100644 --- a/docs/src/icons/SvgProductTemplates.tsx +++ b/docs/src/icons/SvgProductTemplates.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -function SvgComponent(props: React.SVGProps) { +export default function SvgProductTemplates(props: React.SVGProps) { return ( ) { ) { ) { ) { ); } - -export default SvgComponent; diff --git a/docs/src/layouts/AppFooter.tsx b/docs/src/layouts/AppFooter.tsx new file mode 100644 index 00000000000000..6ab68eaaa3aaf4 --- /dev/null +++ b/docs/src/layouts/AppFooter.tsx @@ -0,0 +1,185 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import * as React from 'react'; +import NextLink from 'next/link'; +import Box from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; +import Divider from '@material-ui/core/Divider'; +import Typography from '@material-ui/core/Typography'; +import InputBase from '@material-ui/core/InputBase'; +import Button from '@material-ui/core/Button'; +import Link from '@material-ui/core/Link'; +import SvgMuiLogo from 'docs/src/icons/SvgMuiLogo'; +import ROUTES from '../route'; + +export default function AppFooter() { + return ( + + theme.spacing(4, 2), + gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr', md: '1fr 1.75fr', lg: '1fr 1fr' }, + gridTemplateRows: 'auto', + '& a': { + mt: 1, + color: 'text.secondary', + typography: 'body2', + '&:hover': { + color: 'primary.main', + textDecoration: 'underline', + }, + }, + }} + > +
    + + + Join our newsletter! + + + No spam, guaranteed. + + + + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[900] + : theme.palette.grey[100], + px: 1, + py: 0.5, + typography: 'body2', + flexGrow: 1, + minWidth: 200, + }} + /> + + +
    + + + + Products + + + Core + + + Advanced X + + + Templates + + + Design Kits + + + + + Resources + + + Material Icons + + + Free templates + + + Components + + + Customization + + + Styling + + + + + Explore + + + Documentation + + + Blog + + + Showcase + + + Roadmap + + + Languages + + + + + Company + + + About + + + Vision + + + Careers + + + Support + + + Contact us + + + +
    + + + + Currently v4.11.0. Released under the MIT License. Copyright © 2020 Material-UI. + + +
    + ); +} diff --git a/docs/src/layouts/AppHeader.tsx b/docs/src/layouts/AppHeader.tsx index d0d63a7de56eac..a1d3c95ce09231 100644 --- a/docs/src/layouts/AppHeader.tsx +++ b/docs/src/layouts/AppHeader.tsx @@ -1,24 +1,59 @@ import * as React from 'react'; import NextLink from 'next/link'; -import { styled } from '@material-ui/core/styles'; +import { styled, alpha } from '@material-ui/core/styles'; +import useMediaQuery from '@material-ui/core/useMediaQuery'; +import NoSsr from '@material-ui/core/NoSsr'; import Box from '@material-ui/core/Box'; import Container from '@material-ui/core/Container'; import SvgMuiLogo from 'docs/src/icons/SvgMuiLogo'; -import HeaderNavBar from 'docs/src/components/HeaderNavBar'; -import HeaderNavDropdown from 'docs/src/components/HeaderNavDropdown'; +import HeaderNavBar from 'docs/src/components/header/HeaderNavBar'; +import HeaderNavDropdown from 'docs/src/components/header/HeaderNavDropdown'; +import ThemeModeToggle from 'docs/src/components/header/ThemeModeToggle'; +import { getCookie } from 'docs/src/modules/utils/helpers'; +import { useChangeTheme } from '../modules/ThemeContext'; -const Header = styled('div')(({ theme }) => ({ +const Header = styled('div', { + shouldForwardProp: (prop) => prop !== 'trigger', +})<{ trigger: boolean }>(({ theme, trigger }) => ({ position: 'sticky', - top: 0, + top: trigger ? -80 : 0, + transition: theme.transitions.create('top'), zIndex: theme.zIndex.appBar, backdropFilter: 'blur(20px)', - boxShadow: 'inset 0px -1px 1px #EAEEF3', - backgroundColor: theme.palette.mode === 'dark' ? 'rgba(0,0,0,0.72)' : 'rgba(255,255,255,0.72)', + boxShadow: `inset 0px -1px 1px ${ + theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : theme.palette.grey[100] + }`, + backgroundColor: + theme.palette.mode === 'dark' + ? alpha(theme.palette.primaryDark[900], 0.72) + : 'rgba(255,255,255,0.72)', })); export default function AppHeader() { + const changeTheme = useChangeTheme(); + const [mode, setMode] = React.useState(getCookie('paletteMode') || 'system'); + const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); + const preferredMode = prefersDarkMode ? 'dark' : 'light'; + + const handleChangeThemeMode = (event: React.ChangeEvent) => { + let paletteMode = 'system'; + paletteMode = event.target.checked ? 'dark' : 'light'; + if (paletteMode === null) { + return; + } + + setMode(paletteMode); + + if (paletteMode === 'system') { + document.cookie = `paletteMode=;path=/;max-age=31536000`; + changeTheme({ paletteMode: preferredMode }); + } else { + document.cookie = `paletteMode=${paletteMode};path=/;max-age=31536000`; + changeTheme({ paletteMode }); + } + }; return ( -
    +
    @@ -32,6 +67,12 @@ export default function AppHeader() { + + +
    ); diff --git a/docs/src/modules/ThemeContext.tsx b/docs/src/modules/ThemeContext.tsx new file mode 100644 index 00000000000000..a862046181254d --- /dev/null +++ b/docs/src/modules/ThemeContext.tsx @@ -0,0 +1,90 @@ +import * as React from 'react'; +import { ThemeProvider as MuiThemeProvider, createTheme } from '@material-ui/core/styles'; +import GlobalStyles from '@material-ui/core/GlobalStyles'; +import useMediaQuery from '@material-ui/core/useMediaQuery'; +import { getCookie } from 'docs/src/modules/utils/helpers'; +import { getDesignTokens, getThemedComponents } from './brandingTheme'; + +const themeInitialOptions = { + paletteMode: 'light', +} as const; + +type Action = { + type: 'CHANGE'; + payload: { + paletteMode: 'light' | 'dark'; + }; +}; +type State = { + paletteMode: 'light' | 'dark'; +}; +type Reducer = (state: State, action: Action) => State; + +const DispatchContext = React.createContext | null>(null); + +const ThemeProvider = ({ children }: React.PropsWithChildren<{}>) => { + const [themeOptions, dispatch] = React.useReducer((state, action) => { + switch (action.type) { + case 'CHANGE': + return { + ...state, + paletteMode: action.payload.paletteMode || state.paletteMode, + }; + default: + throw new Error(`Unrecognized type ${action.type}`); + } + }, themeInitialOptions); + const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); + const preferredMode = prefersDarkMode ? 'dark' : 'light'; + const { paletteMode = preferredMode } = themeOptions; + React.useEffect(() => { + if (process.browser) { + const nextPaletteMode = (getCookie('paletteMode') || preferredMode) as State['paletteMode']; + + dispatch({ + type: 'CHANGE', + payload: { paletteMode: nextPaletteMode }, + }); + } + }, [preferredMode]); + const theme = React.useMemo(() => { + const brandingDesignTokens = getDesignTokens(paletteMode); + let nextTheme = createTheme({ + ...brandingDesignTokens, + palette: { + ...brandingDesignTokens.palette, + mode: paletteMode, + }, + }); + + nextTheme = createTheme(nextTheme, { + ...getThemedComponents(nextTheme), + }); + + return nextTheme; + }, [paletteMode]); + return ( + + + {children} + + ); +}; + +export const useChangeTheme = () => { + const dispatch = React.useContext(DispatchContext); + if (!dispatch) { + throw new Error('Forgot to wrap component in `ThemeProvider`'); + } + return React.useCallback((options) => dispatch({ type: 'CHANGE', payload: options }), [dispatch]); +}; + +export default ThemeProvider; diff --git a/docs/src/modules/branding/BrandingCustomerIcons.tsx b/docs/src/modules/branding/BrandingCustomerIcons.tsx index 2031e7bef254fa..a2cf02e454adfd 100644 --- a/docs/src/modules/branding/BrandingCustomerIcons.tsx +++ b/docs/src/modules/branding/BrandingCustomerIcons.tsx @@ -4,13 +4,13 @@ import Typography from '@material-ui/core/Typography'; import Grid from '@material-ui/core/Grid'; const customerIconsData = [ - { image: '/static/branding/pricing/coursera.svg', width: 102, height: 16, alt: 'Coursera' }, - { image: '/static/branding/pricing/amazon.svg', width: 92, height: 28, alt: 'Amazon' }, - { image: '/static/branding/pricing/nasa.svg', width: 64, height: 53, alt: 'NASA' }, - { image: '/static/branding/pricing/netflix.svg', width: 88, height: 24, alt: 'Netflix' }, - { image: '/static/branding/pricing/unity.svg', width: 110, height: 40, alt: 'Unity' }, + { image: '/static/branding/companies/coursera.svg', width: 102, height: 16, alt: 'Coursera' }, + { image: '/static/branding/companies/amazon.svg', width: 92, height: 28, alt: 'Amazon' }, + { image: '/static/branding/companies/nasa.svg', width: 64, height: 53, alt: 'NASA' }, + { image: '/static/branding/companies/netflix.svg', width: 88, height: 24, alt: 'Netflix' }, + { image: '/static/branding/companies/unity.svg', width: 110, height: 40, alt: 'Unity' }, { - image: '/static/branding/pricing/shutterstock.svg', + image: '/static/branding/companies/shutterstock.svg', width: 138, height: 21, alt: 'Shutterstock', diff --git a/docs/src/modules/brandingTheme.ts b/docs/src/modules/brandingTheme.ts index 253b4de673ce32..bdc7046bd28681 100644 --- a/docs/src/modules/brandingTheme.ts +++ b/docs/src/modules/brandingTheme.ts @@ -1,4 +1,4 @@ -import { createTheme } from '@material-ui/core/styles'; +import { createTheme, ThemeOptions, Theme } from '@material-ui/core/styles'; declare module '@material-ui/core/styles/createPalette' { interface ColorRange { @@ -15,6 +15,10 @@ declare module '@material-ui/core/styles/createPalette' { } interface PaletteColor extends ColorRange {} + + interface Palette { + primaryDark: PaletteColor; + } } declare module '@material-ui/core/styles/createTypography' { @@ -36,11 +40,27 @@ declare module '@material-ui/core/styles/createTypography' { // } // } +const defaultTheme = createTheme(); + +const blue = { + 50: '#F0F7FF', + 100: '#C2E0FF', + 200: '#80BFFF', + 300: '#66B2FF', + 400: '#3399FF', + main: '#007FFF', // contrast 3.83:1 + 500: '#007FFF', + 600: '#0072E5', + 700: '#0059B2', + 800: '#004C99', + 900: '#003A75', +}; const blueDark = { 50: '#E2EDF8', 100: '#CEE0F3', 200: '#91B9E3', 300: '#5090D3', + main: '#5090D3', 400: '#265D97', 500: '#1E4976', 600: '#173A5E', @@ -74,158 +94,290 @@ const systemFont = [ '"Segoe UI Symbol"', ]; -const theme = createTheme({ - palette: { - primary: { - 50: '#F0F7FF', - 100: '#C2E0FF', - 200: '#80BFFF', - 300: '#66B2FF', - 400: '#3399FF', - main: '#007FFF', // contrast 3.83:1 - 500: '#007FFF', - 600: '#0072E5', - 700: '#0059B2', - 800: '#004C99', - 900: '#003A75', - }, - common: { - black: '#1D1D1D', - }, - text: { - primary: blueDark[900], - secondary: grey[800], - }, - grey, - error: { - 50: '#FFF0F1', - 100: '#FFDBDE', - 200: '#FFBDC2', - 300: '#FF99A2', - 400: '#FF7A86', - 500: '#FF505F', - main: '#EB0014', // contrast 4.62:1 - 600: '#EB0014', - 700: '#C70011', - 800: '#94000D', - 900: '#570007', - }, - success: { - 50: '#E9FBF0', - 100: '#C6F6D9', - 200: '#9AEFBC', - 300: '#6AE79C', - 400: '#3EE07F', - 500: '#21CC66', - 600: '#1DB45A', - main: '#1AA251', // contrast 3.31:1 - 700: '#1AA251', - 800: '#178D46', - 900: '#0F5C2E', +export const getDesignTokens = (mode: 'light' | 'dark') => + ({ + palette: { + primary: blue, + divider: mode === 'dark' ? blueDark[400] : grey[200], + primaryDark: blueDark, + ...(mode === 'dark' && { + background: { + default: blueDark[800], + paper: blueDark[900], + }, + }), + common: { + black: '#1D1D1D', + }, + ...(mode === 'light' && { + text: { + primary: grey[900], + secondary: grey[800], + }, + }), + ...(mode === 'dark' && { + text: { + primary: '#fff', + secondary: grey[500], + }, + }), + grey, + error: { + 50: '#FFF0F1', + 100: '#FFDBDE', + 200: '#FFBDC2', + 300: '#FF99A2', + 400: '#FF7A86', + 500: '#FF505F', + main: '#EB0014', // contrast 4.62:1 + 600: '#EB0014', + 700: '#C70011', + 800: '#94000D', + 900: '#570007', + }, + success: { + 50: '#E9FBF0', + 100: '#C6F6D9', + 200: '#9AEFBC', + 300: '#6AE79C', + 400: '#3EE07F', + 500: '#21CC66', + 600: '#1DB45A', + main: '#1AA251', // contrast 3.31:1 + 700: '#1AA251', + 800: '#178D46', + 900: '#0F5C2E', + }, + warning: { + 50: '#FFF9EB', + 100: '#FFF4DB', + 200: '#FFF0CC', + 300: '#FFE4A3', + 400: '#FFD980', + 500: '#FFC846', + 600: '#FFBC1F', + main: '#F5AC00', // does not pass constrast ratio + 700: '#F5AC00', + 800: '#DB9A00', + 900: '#8F6400', + }, }, - warning: { - 50: '#FFF9EB', - 100: '#FFF4DB', - 200: '#FFF0CC', - 300: '#FFE4A3', - 400: '#FFD980', - 500: '#FFC846', - 600: '#FFBC1F', - main: '#F5AC00', // does not pass constrast ratio - 700: '#F5AC00', - 800: '#DB9A00', - 900: '#8F6400', + shape: { + borderRadius: 10, }, - }, - shape: { - borderRadius: 10, - }, - spacing: 10, - typography: { - fontFamily: ['"PlusJakartaSans"', ...systemFont].join(','), - fontFamilyCode: ['"IBM Plex Mono"', ...systemFont].join(','), - fontWeightExtraBold: 800, - button: { - textTransform: 'initial', - fontWeight: 700, + spacing: 10, + typography: { + fontFamily: ['"IBM Plex Sans"', ...systemFont].join(','), + fontFamilyCode: ['"IBM Plex Mono"', ...systemFont].join(','), + fontFamilyTagline: ['"PlusJakartaSans"', ...systemFont].join(','), + fontWeightExtraBold: 800, + h1: { + fontFamily: ['"PlusJakartaSans"', ...systemFont].join(','), + fontSize: 'clamp(2.625rem, 1.2857rem + 3.5714vw, 4.5rem)', + fontWeight: 800, + lineHeight: 80 / 72, + ...(mode === 'light' && { + color: blueDark[900], + }), + }, + h2: { + fontFamily: ['"PlusJakartaSans"', ...systemFont].join(','), + fontSize: 'clamp(1.5rem, 0.9643rem + 1.4286vw, 2.25rem)', + fontWeight: 800, + lineHeight: 44 / 36, + color: mode === 'dark' ? grey[300] : blue[900], + }, + h3: { + fontSize: defaultTheme.typography.pxToRem(36), + lineHeight: 44 / 36, + letterSpacing: 0, + }, + h4: { + fontSize: defaultTheme.typography.pxToRem(28), + lineHeight: 42 / 28, + letterSpacing: 0, + }, + h5: { + fontSize: defaultTheme.typography.pxToRem(24), + lineHeight: 36 / 24, + letterSpacing: 0, + }, + h6: { + fontSize: defaultTheme.typography.pxToRem(20), + lineHeight: 30 / 20, + letterSpacing: 0, + }, + 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: 600, + }, }, - }, -}); + } as ThemeOptions); -const brandingTheme = createTheme(theme, { - typography: { - subtitle1: { - fontSize: theme.typography.pxToRem(18), // 18px - lineHeight: 22 / 18, - }, - body1: { - fontSize: theme.typography.pxToRem(16), // 16px - lineHeight: 24 / 16, - fontWeight: 500, - }, - body2: { - fontSize: theme.typography.pxToRem(14), // 14px - lineHeight: 20 / 14, - }, - }, - components: { - MuiButton: { - defaultProps: { - disableElevation: true, - disableTouchRipple: true, - }, - styleOverrides: { - sizeLarge: { - padding: '1rem 1.25rem', - ...theme.typography.body1, - fontWeight: 700, +export function getThemedComponents(theme: Theme) { + return { + components: { + MuiButton: { + defaultProps: { + disableElevation: true, + disableTouchRipple: true, }, - }, - variants: [ - { - props: { variant: 'code' }, - style: { - color: grey[800], - border: '1px solid', - borderColor: grey[200], - backgroundColor: grey[50], - fontFamily: theme.typography.fontFamilyCode, - '&:hover, &.Mui-focusVisible': { - borderColor: theme.palette.primary.main, - backgroundColor: theme.palette.primary[50], + styleOverrides: { + sizeLarge: { + padding: '1rem 1.25rem', + ...theme.typography.body1, + lineHeight: 21 / 16, + fontWeight: 700, + }, + }, + variants: [ + { + props: { variant: 'code' }, + style: { + color: + theme.palette.mode === 'dark' ? theme.palette.grey[400] : theme.palette.grey[800], + border: '1px solid', + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[400] + : theme.palette.grey[200], + backgroundColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[700] + : theme.palette.grey[50], + fontFamily: theme.typography.fontFamilyCode, + '&:hover, &.Mui-focusVisible': { + borderColor: theme.palette.primary.main, + backgroundColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[500] + : theme.palette.primary[50], + '& .MuiButton-endIcon': { + color: + theme.palette.mode === 'dark' + ? theme.palette.primary[300] + : theme.palette.primary.main, + }, + }, + '& .MuiButton-startIcon': { + color: theme.palette.grey[400], + }, '& .MuiButton-endIcon': { - color: theme.palette.primary.main, + color: + theme.palette.mode === 'dark' ? theme.palette.grey[400] : theme.palette.grey[700], }, }, - '& .MuiButton-startIcon': { - color: theme.palette.grey[400], + }, + { + props: { variant: 'code', size: 'large' }, + style: { + ...theme.typography.body2, + fontFamily: theme.typography.fontFamilyCode, + fontWeight: theme.typography.fontWeightBold, }, - '& .MuiButton-endIcon': { - color: theme.palette.grey[700], + }, + ], + }, + MuiContainer: { + styleOverrides: { + root: { + [theme.breakpoints.up('md')]: { + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), }, }, }, - { - props: { variant: 'code', size: 'large' }, - style: { - ...theme.typography.body2, - fontFamily: theme.typography.fontFamilyCode, - fontWeight: theme.typography.fontWeightBold, + }, + MuiDivider: { + styleOverrides: { + root: { + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[700] + : theme.palette.grey[100], }, }, - ], - }, - MuiContainer: { - styleOverrides: { - root: { - [theme.breakpoints.up('md')]: { - paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(2), + }, + MuiLink: { + defaultProps: { + underline: 'none', + }, + styleOverrides: { + root: { + fontWeight: 'bold', + display: 'inline-flex', + alignItems: 'center', + '&.MuiTypography-body1 > svg': { + marginTop: 2, + }, + '& svg:last-child': { + marginLeft: 2, + }, + }, + }, + }, + MuiTab: { + defaultProps: { + disableTouchRipple: true, + }, + }, + MuiPaper: { + styleOverrides: { + outlined: { + display: 'block', + borderColor: + theme.palette.mode === 'dark' + ? theme.palette.primaryDark[400] + : theme.palette.grey[100], + ...(theme.palette.mode === 'dark' && { + backgroundColor: theme.palette.primaryDark[700], + }), + 'a&, button&': { + '&:hover': { + boxShadow: '1px 1px 20px 0 rgb(90 105 120 / 20%)', + }, + }, + }, + }, + }, + MuiTableCell: { + styleOverrides: { + root: { + padding: theme.spacing(1, 2), + borderColor: theme.palette.divider, + }, + head: { + color: theme.palette.text.primary, + fontWeight: 600, + }, + body: { + color: theme.palette.text.secondary, }, }, }, }, - }, -}); - -export default brandingTheme; + }; +} diff --git a/docs/src/modules/components/HighlightedCode.js b/docs/src/modules/components/HighlightedCode.js index 91ebf3aa044f1e..56c3bcd0461a09 100644 --- a/docs/src/modules/components/HighlightedCode.js +++ b/docs/src/modules/components/HighlightedCode.js @@ -4,13 +4,13 @@ import prism from '@material-ui/markdown/prism'; import MarkdownElement from './MarkdownElement'; const HighlightedCode = React.forwardRef(function HighlightedCode(props, ref) { - const { code, language, ...other } = props; + const { code, language, component: Component = MarkdownElement, ...other } = props; const renderedCode = React.useMemo(() => { return prism(code.trim(), language); }, [code, language]); return ( - +
             
           
    -
    + ); }); HighlightedCode.propTypes = { code: PropTypes.string.isRequired, + component: PropTypes.elementType, language: PropTypes.string.isRequired, }; diff --git a/docs/src/pages/components/cards/NotificationCard.js b/docs/src/pages/components/cards/NotificationCard.js index 7d6584bdddf493..2bc241829093a4 100644 --- a/docs/src/pages/components/cards/NotificationCard.js +++ b/docs/src/pages/components/cards/NotificationCard.js @@ -6,19 +6,6 @@ import Card from '@material-ui/core/Card'; import Chip from '@material-ui/core/Chip'; import Typography from '@material-ui/core/Typography'; -const grey = { - 50: '#F3F6F9', - 100: '#EAEEF3', - 200: '#E5E8EC', - 300: '#D7DCE1', - 400: '#BFC7CF', - 500: '#AAB4BE', - 600: '#96A3B0', - 700: '#8796A5', - 800: '#5A6978', - 900: '#3D4752', -}; - const primary = { 50: '#F0F7FF', 100: '#C2E0FF', @@ -34,6 +21,32 @@ const primary = { 1000: '#132F4C', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + +const grey = { + 50: '#F3F6F9', + 100: '#EAEEF3', + 200: '#E5E8EC', + 300: '#D7DCE1', + 400: '#BFC7CF', + 500: '#AAB4BE', + 600: '#96A3B0', + 700: '#8796A5', + 800: '#5A6978', + 900: '#3D4752', +}; + export default function NotificationCard() { /* * Note: this demo use `theme.palette.mode` from `useTheme` to make dark mode works in the documentation only. @@ -56,12 +69,12 @@ export default function NotificationCard() { }, }), grey, - divider: mode === 'dark' ? primary[1000] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], success: { main: '#1DB45A', }, background: { - paper: mode === 'dark' ? primary[900] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { diff --git a/docs/src/pages/components/cards/NotificationCard.tsx b/docs/src/pages/components/cards/NotificationCard.tsx index 4044cd35644c54..81c7ef5bab9c75 100644 --- a/docs/src/pages/components/cards/NotificationCard.tsx +++ b/docs/src/pages/components/cards/NotificationCard.tsx @@ -12,18 +12,6 @@ declare module '@material-ui/core/Chip' { } } -const grey = { - 50: '#F3F6F9', - 100: '#EAEEF3', - 200: '#E5E8EC', - 300: '#D7DCE1', - 400: '#BFC7CF', - 500: '#AAB4BE', - 600: '#96A3B0', - 700: '#8796A5', - 800: '#5A6978', - 900: '#3D4752', -}; const primary = { 50: '#F0F7FF', 100: '#C2E0FF', @@ -38,6 +26,30 @@ const primary = { 900: '#003A75', 1000: '#132F4C', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; +const grey = { + 50: '#F3F6F9', + 100: '#EAEEF3', + 200: '#E5E8EC', + 300: '#D7DCE1', + 400: '#BFC7CF', + 500: '#AAB4BE', + 600: '#96A3B0', + 700: '#8796A5', + 800: '#5A6978', + 900: '#3D4752', +}; export default function NotificationCard() { /* @@ -61,12 +73,12 @@ export default function NotificationCard() { }, }), grey, - divider: mode === 'dark' ? primary[1000] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], success: { main: '#1DB45A', }, background: { - paper: mode === 'dark' ? primary[900] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { diff --git a/docs/src/pages/components/cards/PlayerCard.js b/docs/src/pages/components/cards/PlayerCard.js index 8b23fb7a4d21fb..7e733afc3dbce1 100644 --- a/docs/src/pages/components/cards/PlayerCard.js +++ b/docs/src/pages/components/cards/PlayerCard.js @@ -10,6 +10,19 @@ import FastRewindRounded from '@material-ui/icons/FastRewindRounded'; import PlayArrowRounded from '@material-ui/icons/PlayArrowRounded'; import PauseRounded from '@material-ui/icons/PauseRounded'; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -39,9 +52,9 @@ export default function PlayerCard() { palette: { mode, background: { - paper: mode === 'dark' ? '#003A75' : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, - divider: mode === 'dark' ? '#132F4C' : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], ...(mode === 'light' && { text: { primary: grey[900], @@ -69,7 +82,7 @@ export default function PlayerCard() { styleOverrides: { root: { border: '1px solid', - borderColor: mode === 'dark' ? '#132F4C' : '#fff', + borderColor: mode === 'dark' ? primaryDark[400] : '#fff', }, }, }, @@ -80,7 +93,7 @@ export default function PlayerCard() { styleOverrides: { root: { border: '1px solid', - borderColor: mode === 'dark' ? '#132F4C' : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], }, }, }, diff --git a/docs/src/pages/components/cards/PlayerCard.tsx b/docs/src/pages/components/cards/PlayerCard.tsx index 6e89a89633bded..e54b35f1f2a857 100644 --- a/docs/src/pages/components/cards/PlayerCard.tsx +++ b/docs/src/pages/components/cards/PlayerCard.tsx @@ -10,6 +10,18 @@ import FastRewindRounded from '@material-ui/icons/FastRewindRounded'; import PlayArrowRounded from '@material-ui/icons/PlayArrowRounded'; import PauseRounded from '@material-ui/icons/PauseRounded'; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -39,9 +51,9 @@ export default function PlayerCard() { palette: { mode, background: { - paper: mode === 'dark' ? '#003A75' : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, - divider: mode === 'dark' ? '#132F4C' : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], ...(mode === 'light' && { text: { primary: grey[900], @@ -69,7 +81,7 @@ export default function PlayerCard() { styleOverrides: { root: { border: '1px solid', - borderColor: mode === 'dark' ? '#132F4C' : '#fff', + borderColor: mode === 'dark' ? primaryDark[400] : '#fff', }, }, }, @@ -80,7 +92,7 @@ export default function PlayerCard() { styleOverrides: { root: { border: '1px solid', - borderColor: mode === 'dark' ? '#132F4C' : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], }, }, }, diff --git a/docs/src/pages/components/cards/cards.md b/docs/src/pages/components/cards/cards.md index fbe0429a175a77..62492ab2156dc4 100644 --- a/docs/src/pages/components/cards/cards.md +++ b/docs/src/pages/components/cards/cards.md @@ -63,6 +63,20 @@ Here's an example of a media control card. {{"demo": "pages/components/cards/MediaControlCard.js", "bg": true}} -## Customization +## Theming + +Here is an example of theming the component. You can learn more about this in the [theming page](/customization/theming) and [theme components page](/customization/theme-components) + +### Task Card + +{{"demo": "pages/components/cards/TaskCard.js", "bg": true}} + +### Player Card + +{{"demo": "pages/components/cards/PlayerCard.js", "bg": true}} + +### Notification Card + +{{"demo": "pages/components/cards/NotificationCard.js", "bg": true}} 🎨 If you are looking for inspiration, you can check [MUI Treasury's customization examples](https://mui-treasury.com/components/card). diff --git a/docs/src/pages/components/chips/CustomizedChip.js b/docs/src/pages/components/chips/ThemeChip.js similarity index 87% rename from docs/src/pages/components/chips/CustomizedChip.js rename to docs/src/pages/components/chips/ThemeChip.js index f24137819f940a..a4e5711378a5ab 100644 --- a/docs/src/pages/components/chips/CustomizedChip.js +++ b/docs/src/pages/components/chips/ThemeChip.js @@ -29,7 +29,7 @@ const grey = { 900: '#3D4752', }; -export default function CustomizedChip() { +export default function ThemeChip() { /* * Note: this demo use `theme.palette.mode` from `useTheme` to make dark mode works in the documentation only. * @@ -60,14 +60,14 @@ export default function CustomizedChip() { marginBottom: '1px', fontSize: 14, lineHeight: 1.5, - fontWeight: 500, + fontWeight: 600, }, filled: { color: mode === 'dark' ? '#fff' : grey[800], backgroundColor: mode === 'dark' ? grey[900] : grey[200], '&.MuiChip-colorPrimary': { - backgroundColor: mode === 'dark' ? primary[900] : primary[100], - color: mode === 'dark' ? primary[200] : primary[500], + backgroundColor: primary[100], + color: primary[500], }, }, deleteIcon: { @@ -77,9 +77,9 @@ export default function CustomizedChip() { }, }, deleteIconColorPrimary: { - color: mode === 'dark' ? primary[300] : primary[500], + color: primary[500], '&:hover': { - color: mode === 'dark' ? primary[100] : primary[700], + color: primary[700], }, }, }, diff --git a/docs/src/pages/components/chips/CustomizedChip.tsx b/docs/src/pages/components/chips/ThemeChip.tsx similarity index 87% rename from docs/src/pages/components/chips/CustomizedChip.tsx rename to docs/src/pages/components/chips/ThemeChip.tsx index 4b5ce728faf53c..53f1e72721d435 100644 --- a/docs/src/pages/components/chips/CustomizedChip.tsx +++ b/docs/src/pages/components/chips/ThemeChip.tsx @@ -28,7 +28,7 @@ const grey = { 900: '#3D4752', }; -export default function CustomizedChip() { +export default function ThemeChip() { /* * Note: this demo use `theme.palette.mode` from `useTheme` to make dark mode works in the documentation only. * @@ -59,14 +59,14 @@ export default function CustomizedChip() { marginBottom: '1px', fontSize: 14, lineHeight: 1.5, - fontWeight: 500, + fontWeight: 600, }, filled: { color: mode === 'dark' ? '#fff' : grey[800], backgroundColor: mode === 'dark' ? grey[900] : grey[200], '&.MuiChip-colorPrimary': { - backgroundColor: mode === 'dark' ? primary[900] : primary[100], - color: mode === 'dark' ? primary[200] : primary[500], + backgroundColor: primary[100], + color: primary[500], }, }, deleteIcon: { @@ -76,9 +76,9 @@ export default function CustomizedChip() { }, }, deleteIconColorPrimary: { - color: mode === 'dark' ? primary[300] : primary[500], + color: primary[500], '&:hover': { - color: mode === 'dark' ? primary[100] : primary[700], + color: primary[700], }, }, }, diff --git a/docs/src/pages/components/date-picker/ThemeDatePicker.js b/docs/src/pages/components/date-picker/ThemeDatePicker.js index d40df170936c1b..70ed8c3de054a3 100644 --- a/docs/src/pages/components/date-picker/ThemeDatePicker.js +++ b/docs/src/pages/components/date-picker/ThemeDatePicker.js @@ -17,7 +17,19 @@ const primary = { 700: '#0059B2', 800: '#004C99', 900: '#003A75', - 1000: '#132F4C', +}; + +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', }; const grey = { @@ -49,7 +61,7 @@ export default function ThemeDatePicker() { mode, primary, background: { - paper: mode === 'dark' ? primary[800] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { @@ -116,7 +128,7 @@ export default function ThemeDatePicker() { sx={{ '& > div': { border: '1px solid', - borderColor: mode === 'dark' ? primary[1000] : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], borderRadius: 1, }, }} diff --git a/docs/src/pages/components/date-picker/ThemeDatePicker.tsx b/docs/src/pages/components/date-picker/ThemeDatePicker.tsx index 55e1ea8852eba6..93bd4806ac5d70 100644 --- a/docs/src/pages/components/date-picker/ThemeDatePicker.tsx +++ b/docs/src/pages/components/date-picker/ThemeDatePicker.tsx @@ -17,7 +17,18 @@ const primary = { 700: '#0059B2', 800: '#004C99', 900: '#003A75', - 1000: '#132F4C', +}; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', }; const grey = { 50: '#F3F6F9', @@ -48,7 +59,7 @@ export default function ThemeDatePicker() { mode, primary, background: { - paper: mode === 'dark' ? primary[800] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { @@ -114,7 +125,7 @@ export default function ThemeDatePicker() { sx={{ '& > div': { border: '1px solid', - borderColor: mode === 'dark' ? primary[1000] : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], borderRadius: 1, }, }} diff --git a/docs/src/pages/components/slider/ThemeSlider.js b/docs/src/pages/components/slider/ThemeSlider.js index 82486341dd6b09..c40bbc2aa37be7 100644 --- a/docs/src/pages/components/slider/ThemeSlider.js +++ b/docs/src/pages/components/slider/ThemeSlider.js @@ -16,6 +16,19 @@ const primary = { 900: '#003A75', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -60,10 +73,11 @@ export default function ThemeSlider() { MuiSlider: { styleOverrides: { root: { - color: mode === 'dark' ? primary[300] : primary[500], + color: primary[500], }, rail: { - backgroundColor: grey[300], + opacity: 1, + backgroundColor: mode === 'dark' ? primaryDark[900] : grey[200], }, track: { border: 'none', @@ -84,7 +98,7 @@ export default function ThemeSlider() { }, '& .MuiSlider-valueLabel': { backgroundColor: 'transparent', - color: mode === 'dark' ? grey[50] : grey[800], + color: mode === 'dark' ? grey[50] : grey[500], fontWeight: 700, padding: 0, left: '1rem', @@ -106,7 +120,15 @@ export default function ThemeSlider() { return ( - + 'Temperature'} orientation="vertical" diff --git a/docs/src/pages/components/slider/ThemeSlider.tsx b/docs/src/pages/components/slider/ThemeSlider.tsx index e7a1f4934101b2..cba84366116b9e 100644 --- a/docs/src/pages/components/slider/ThemeSlider.tsx +++ b/docs/src/pages/components/slider/ThemeSlider.tsx @@ -15,6 +15,18 @@ const primary = { 800: '#004C99', 900: '#003A75', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -59,10 +71,11 @@ export default function ThemeSlider() { MuiSlider: { styleOverrides: { root: { - color: mode === 'dark' ? primary[300] : primary[500], + color: primary[500], }, rail: { - backgroundColor: grey[300], + opacity: 1, + backgroundColor: mode === 'dark' ? primaryDark[900] : grey[200], }, track: { border: 'none', @@ -83,7 +96,7 @@ export default function ThemeSlider() { }, '& .MuiSlider-valueLabel': { backgroundColor: 'transparent', - color: mode === 'dark' ? grey[50] : grey[800], + color: mode === 'dark' ? grey[50] : grey[500], fontWeight: 700, padding: 0, left: '1rem', @@ -104,7 +117,15 @@ export default function ThemeSlider() { ); return ( - + 'Temperature'} orientation="vertical" diff --git a/docs/src/pages/components/tables/FolderTable.js b/docs/src/pages/components/tables/FolderTable.js index 855140574e8cea..0f19c7705b25ec 100644 --- a/docs/src/pages/components/tables/FolderTable.js +++ b/docs/src/pages/components/tables/FolderTable.js @@ -53,19 +53,6 @@ function formatSize(size) { return `${(kb / 1000).toFixed(0)} MB`; } -const grey = { - 50: '#F3F6F9', - 100: '#EAEEF3', - 200: '#E5E8EC', - 300: '#D7DCE1', - 400: '#BFC7CF', - 500: '#AAB4BE', - 600: '#96A3B0', - 700: '#8796A5', - 800: '#5A6978', - 900: '#3D4752', -}; - const primary = { 50: '#F0F7FF', 100: '#C2E0FF', @@ -78,7 +65,32 @@ const primary = { 700: '#0059B2', 800: '#004C99', 900: '#003A75', - 1000: '#132F4C', +}; + +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + +const grey = { + 50: '#F3F6F9', + 100: '#EAEEF3', + 200: '#E5E8EC', + 300: '#D7DCE1', + 400: '#BFC7CF', + 500: '#AAB4BE', + 600: '#96A3B0', + 700: '#8796A5', + 800: '#5A6978', + 900: '#3D4752', }; export default function BasicTable() { @@ -103,12 +115,12 @@ export default function BasicTable() { secondary: grey[600], }, }), - divider: mode === 'dark' ? primary[1000] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], success: { main: mode === 'dark' ? '#21CC66' : '#1AA251', }, background: { - paper: mode === 'dark' ? primary[900] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, typography: { @@ -123,7 +135,7 @@ export default function BasicTable() { MuiTableCell: { styleOverrides: { root: { - borderColor: mode === 'dark' ? primary[1000] : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], }, sizeSmall: { padding: '0.625rem 1rem', diff --git a/docs/src/pages/components/tables/FolderTable.tsx b/docs/src/pages/components/tables/FolderTable.tsx index d40c0062a64e30..ce63cb484aeaa3 100644 --- a/docs/src/pages/components/tables/FolderTable.tsx +++ b/docs/src/pages/components/tables/FolderTable.tsx @@ -63,18 +63,6 @@ function formatSize(size: number) { return `${(kb / 1000).toFixed(0)} MB`; } -const grey = { - 50: '#F3F6F9', - 100: '#EAEEF3', - 200: '#E5E8EC', - 300: '#D7DCE1', - 400: '#BFC7CF', - 500: '#AAB4BE', - 600: '#96A3B0', - 700: '#8796A5', - 800: '#5A6978', - 900: '#3D4752', -}; const primary = { 50: '#F0F7FF', 100: '#C2E0FF', @@ -87,7 +75,30 @@ const primary = { 700: '#0059B2', 800: '#004C99', 900: '#003A75', - 1000: '#132F4C', +}; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; +const grey = { + 50: '#F3F6F9', + 100: '#EAEEF3', + 200: '#E5E8EC', + 300: '#D7DCE1', + 400: '#BFC7CF', + 500: '#AAB4BE', + 600: '#96A3B0', + 700: '#8796A5', + 800: '#5A6978', + 900: '#3D4752', }; export default function BasicTable() { @@ -112,12 +123,12 @@ export default function BasicTable() { secondary: grey[600], }, }), - divider: mode === 'dark' ? primary[1000] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], success: { main: mode === 'dark' ? '#21CC66' : '#1AA251', }, background: { - paper: mode === 'dark' ? primary[900] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, typography: { @@ -132,7 +143,7 @@ export default function BasicTable() { MuiTableCell: { styleOverrides: { root: { - borderColor: mode === 'dark' ? primary[1000] : grey[200], + borderColor: mode === 'dark' ? primaryDark[400] : grey[200], }, sizeSmall: { padding: '0.625rem 1rem', diff --git a/docs/src/pages/components/tables/tables.md b/docs/src/pages/components/tables/tables.md index d4ab6810bd59b3..39f0e5984f0f15 100644 --- a/docs/src/pages/components/tables/tables.md +++ b/docs/src/pages/components/tables/tables.md @@ -78,6 +78,12 @@ The `ActionsComponent` prop of the `TablePagination` component allows the implem {{"demo": "pages/components/tables/CustomPaginationActionsTable.js", "bg": true}} +## Theming + +Here is an example of theming the component. You can learn more about this in the [theming page](/customization/theming) and [theme components page](/customization/theme-components) + +{{"demo": "pages/components/tables/FolderTable.js", "bg": true}} + ## Sticky header Here is an example of a table with scrollable rows and fixed column headers. diff --git a/docs/src/pages/components/tabs/tabs.md b/docs/src/pages/components/tabs/tabs.md index 2d91e8c8b20a7a..1e65a68d4332c7 100644 --- a/docs/src/pages/components/tabs/tabs.md +++ b/docs/src/pages/components/tabs/tabs.md @@ -99,6 +99,12 @@ Here is an example of customizing the component. You can learn more about this i {{"demo": "pages/components/tabs/CustomizedTabs.js"}} +## Theming + +Here is an example of theming the component. You can learn more about this in the [theming page](/customization/theming) and [theme components page](/customization/theme-components) + +{{"demo": "pages/components/tabs/ThemeTabs.js"}} + 🎨 If you are looking for inspiration, you can check [MUI Treasury's customization examples](https://mui-treasury.com/styles/tabs/). ## Vertical tabs diff --git a/docs/src/pages/components/timeline/ThemeTimeline.js b/docs/src/pages/components/timeline/ThemeTimeline.js index 263dfe2b255f7d..deb3ea11ef5713 100644 --- a/docs/src/pages/components/timeline/ThemeTimeline.js +++ b/docs/src/pages/components/timeline/ThemeTimeline.js @@ -24,6 +24,19 @@ const primary = { 1000: '#132F4C', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -56,8 +69,9 @@ export default function BasicTimeline() { primary: grey[900], secondary: grey[800], }, + divider: mode === 'dark' ? primaryDark[400] : grey[200], background: { - paper: mode === 'dark' ? primary[800] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { @@ -75,7 +89,6 @@ export default function BasicTimeline() { styleOverrides: { outlined: { boxShadow: '0px 20px 25px rgba(0, 0, 0, 0.1)', - borderColor: mode === 'dark' ? primary[1000] : grey[200], }, }, }, diff --git a/docs/src/pages/components/timeline/ThemeTimeline.tsx b/docs/src/pages/components/timeline/ThemeTimeline.tsx index afbe8db1452484..384a0882546834 100644 --- a/docs/src/pages/components/timeline/ThemeTimeline.tsx +++ b/docs/src/pages/components/timeline/ThemeTimeline.tsx @@ -23,6 +23,18 @@ const primary = { 900: '#003A75', 1000: '#132F4C', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -55,8 +67,9 @@ export default function BasicTimeline() { primary: grey[900], secondary: grey[800], }, + divider: mode === 'dark' ? primaryDark[400] : grey[200], background: { - paper: mode === 'dark' ? primary[800] : '#fff', + paper: mode === 'dark' ? primaryDark[700] : '#fff', }, }, shape: { @@ -74,7 +87,6 @@ export default function BasicTimeline() { styleOverrides: { outlined: { boxShadow: '0px 20px 25px rgba(0, 0, 0, 0.1)', - borderColor: mode === 'dark' ? primary[1000] : grey[200], }, }, }, diff --git a/docs/src/pages/components/timeline/timeline.md b/docs/src/pages/components/timeline/timeline.md index 53342117c139b4..d859c0c2116192 100644 --- a/docs/src/pages/components/timeline/timeline.md +++ b/docs/src/pages/components/timeline/timeline.md @@ -53,3 +53,9 @@ Here is an example of customizing the component. You can learn more about this i [overrides documentation page](/customization/how-to-customize/). {{"demo": "pages/components/timeline/CustomizedTimeline.js"}} + +## Theming + +Here is an example of theming the component. You can learn more about this in the [theming page](/customization/theming) and [theme components page](/customization/theme-components) + +{{"demo": "pages/components/timeline/ThemeTimeline.js", "bg": true}} diff --git a/docs/src/pages/components/toggle-button/ViewToggleButton.js b/docs/src/pages/components/toggle-button/ViewToggleButton.js index 1145a8a3352804..4bb863b6b8817c 100644 --- a/docs/src/pages/components/toggle-button/ViewToggleButton.js +++ b/docs/src/pages/components/toggle-button/ViewToggleButton.js @@ -22,6 +22,19 @@ const primary = { 900: '#003A75', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; + const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -62,7 +75,7 @@ export default function ViewToggleButton() { palette: { mode, primary, - divider: mode === 'dark' ? primary[900] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], grey, }, typography: { @@ -82,7 +95,7 @@ export default function ViewToggleButton() { MuiToggleButtonGroup: { styleOverrides: { root: { - backgroundColor: mode === 'dark' ? primary[800] : '#fff', + backgroundColor: mode === 'dark' ? primaryDark[700] : '#fff', }, }, }, @@ -112,7 +125,7 @@ export default function ViewToggleButton() { aria-label="view" > {views.map((item) => ( - + {viewIcons[item]} ))} diff --git a/docs/src/pages/components/toggle-button/ViewToggleButton.tsx b/docs/src/pages/components/toggle-button/ViewToggleButton.tsx index 737de5c29fd8a5..0a2b7199bcaa94 100644 --- a/docs/src/pages/components/toggle-button/ViewToggleButton.tsx +++ b/docs/src/pages/components/toggle-button/ViewToggleButton.tsx @@ -21,6 +21,18 @@ const primary = { 800: '#004C99', 900: '#003A75', }; +const primaryDark = { + 50: '#E2EDF8', + 100: '#CEE0F3', + 200: '#91B9E3', + 300: '#5090D3', + 400: '#265D97', + 500: '#1E4976', + 600: '#173A5E', + 700: '#132F4C', + 800: '#001E3C', + 900: '#0A1929', +}; const grey = { 50: '#F3F6F9', 100: '#EAEEF3', @@ -63,7 +75,7 @@ export default function ViewToggleButton() { palette: { mode, primary, - divider: mode === 'dark' ? primary[900] : grey[200], + divider: mode === 'dark' ? primaryDark[400] : grey[200], grey, }, typography: { @@ -83,7 +95,7 @@ export default function ViewToggleButton() { MuiToggleButtonGroup: { styleOverrides: { root: { - backgroundColor: mode === 'dark' ? primary[800] : '#fff', + backgroundColor: mode === 'dark' ? primaryDark[700] : '#fff', }, }, }, @@ -113,7 +125,7 @@ export default function ViewToggleButton() { aria-label="view" > {views.map((item) => ( - + {viewIcons[item]} ))} diff --git a/docs/src/pages/components/toggle-button/toggle-button.md b/docs/src/pages/components/toggle-button/toggle-button.md index b8be6520a7fa42..c1dc0b32a2c98b 100644 --- a/docs/src/pages/components/toggle-button/toggle-button.md +++ b/docs/src/pages/components/toggle-button/toggle-button.md @@ -76,6 +76,12 @@ Here is an example of customizing the component. You can learn more about this i {{"demo": "pages/components/toggle-button/CustomizedDividers.js", "bg": true}} +## Theming + +Here is an example of theming the component. You can learn more about this in the [theming page](/customization/theming) and [theme components page](/customization/theme-components) + +{{"demo": "pages/components/toggle-button/ViewToggleButton.js", "bg": true}} + ## Accessibility ### ARIA diff --git a/docs/src/route.ts b/docs/src/route.ts new file mode 100644 index 00000000000000..2282ce98ceb352 --- /dev/null +++ b/docs/src/route.ts @@ -0,0 +1,25 @@ +const ROUTES = { + home: '/branding/', + productCore: '/branding/products/core/', + productAdvanced: '/branding/products/advanced/', + productTemplates: '/branding/products/templates/', + productDesignKits: '/branding/products/design-kits/', + materialIcons: '/components/material-icons/', + freeTemplates: '/getting-started/templates/', + components: '/branding/resources/components/', + customization: '/branding/resources/customization/', + styling: '/branding/resources/styling/', + documentation: '/branding/documentation/', + pricing: '/branding/pricing/', + blog: '/blog/', + showcase: '/discover-more/showcase', + roadmap: '/discover-more/roadmap', + languages: '/discover-more/languages', + about: '/branding/about/', + vision: '/branding/vision/', + careers: '/branding/careers/', + support: '/branding/support/', + contactUs: '/branding/contact-us/', +}; + +export default ROUTES; diff --git a/docs/types/docs.d.ts b/docs/types/docs.d.ts index 7e2fff2b86e3f2..c7c672d2bc10f0 100644 --- a/docs/types/docs.d.ts +++ b/docs/types/docs.d.ts @@ -14,6 +14,11 @@ declare module 'docs/src/modules/components/HighlightedCode' { * see @material-ui/markdown/prism for possible languages */ language: string; + /** + * The component used for the root node. + * @default MarkdownElement + */ + component?: React.ElementType; } export default function HighlightedCode(props: Props): React.ReactElement; }