theme.tsx
1 import { 2 CheckCircleIcon, 3 ChevronDownIcon, 4 ExclamationCircleIcon, 5 ExclamationIcon, 6 InformationCircleIcon, 7 } from '@heroicons/react/outline'; 8 import { SvgIcon, Theme, ThemeOptions } from '@mui/material'; 9 import { createTheme } from '@mui/material/styles'; 10 // eslint-disable-next-line @typescript-eslint/ban-ts-comment 11 // @ts-ignore 12 import { ColorPartial } from '@mui/material/styles/createPalette'; 13 import React from 'react'; 14 15 const theme = createTheme(); 16 const { 17 typography: { pxToRem }, 18 } = theme; 19 20 const FONT = 'Inter, Arial'; 21 22 declare module '@mui/material/styles/createPalette' { 23 interface PaletteColor extends ColorPartial {} 24 25 interface TypeText { 26 muted: string; 27 } 28 29 interface TypeBackground { 30 default: string; 31 paper: string; 32 surface: string; 33 surface2: string; 34 header: string; 35 disabled: string; 36 } 37 38 interface Palette { 39 gradients: { 40 aaveGradient: string; 41 newGradient: string; 42 }; 43 other: { 44 standardInputLine: string; 45 }; 46 } 47 48 interface PaletteOptions { 49 gradients: { 50 aaveGradient: string; 51 newGradient: string; 52 }; 53 } 54 } 55 56 interface TypographyCustomVariants { 57 display1: React.CSSProperties; 58 subheader1: React.CSSProperties; 59 subheader2: React.CSSProperties; 60 description: React.CSSProperties; 61 buttonL: React.CSSProperties; 62 buttonM: React.CSSProperties; 63 buttonS: React.CSSProperties; 64 helperText: React.CSSProperties; 65 tooltip: React.CSSProperties; 66 main21: React.CSSProperties; 67 secondary21: React.CSSProperties; 68 main16: React.CSSProperties; 69 secondary16: React.CSSProperties; 70 main14: React.CSSProperties; 71 secondary14: React.CSSProperties; 72 main12: React.CSSProperties; 73 secondary12: React.CSSProperties; 74 } 75 76 declare module '@mui/material/styles' { 77 interface TypographyVariants extends TypographyCustomVariants {} 78 79 // allow configuration using `createTheme` 80 interface TypographyVariantsOptions extends TypographyCustomVariants {} 81 82 interface BreakpointOverrides { 83 xsm: true; 84 xxl: true; 85 mdlg: true; 86 } 87 } 88 89 // Update the Typography's variant prop options 90 declare module '@mui/material/Typography' { 91 interface TypographyPropsVariantOverrides { 92 display1: true; 93 subheader1: true; 94 subheader2: true; 95 description: true; 96 buttonL: true; 97 buttonM: true; 98 buttonS: true; 99 helperText: true; 100 tooltip: true; 101 main21: true; 102 secondary21: true; 103 main16: true; 104 secondary16: true; 105 main14: true; 106 secondary14: true; 107 main12: true; 108 secondary12: true; 109 h5: false; 110 h6: false; 111 subtitle1: false; 112 subtitle2: false; 113 body1: false; 114 body2: false; 115 button: false; 116 overline: false; 117 } 118 } 119 120 declare module '@mui/material/Button' { 121 interface ButtonPropsVariantOverrides { 122 surface: true; 123 gradient: true; 124 } 125 } 126 127 export const getDesignTokens = (mode: 'light' | 'dark') => { 128 const getColor = (lightColor: string, darkColor: string) => 129 mode === 'dark' ? darkColor : lightColor; 130 131 return { 132 breakpoints: { 133 keys: ['xs', 'xsm', 'sm', 'md', 'lg', 'xl', 'xxl'], 134 values: { xs: 0, xsm: 640, sm: 760, md: 960, mdlg: 1125, lg: 1280, xl: 1575, xxl: 1800 }, 135 }, 136 palette: { 137 mode, 138 primary: { 139 main: getColor('#383D51', '#EAEBEF'), 140 light: getColor('#62677B', '#F1F1F3'), 141 dark: getColor('#292E41', '#D2D4DC'), 142 contrast: getColor('#FFFFFF', '#0F121D'), 143 }, 144 secondary: { 145 main: getColor('#FF607B', '#F48FB1'), 146 light: getColor('#FF607B', '#F6A5C0'), 147 dark: getColor('#B34356', '#AA647B'), 148 }, 149 error: { 150 main: getColor('#BC0000B8', '#F44336'), 151 light: getColor('#D26666', '#E57373'), 152 dark: getColor('#BC0000', '#D32F2F'), 153 '100': getColor('#4F1919', '#FBB4AF'), // for alert text 154 '200': getColor('#F9EBEB', '#2E0C0A'), // for alert background 155 }, 156 warning: { 157 main: getColor('#F89F1A', '#FFA726'), 158 light: getColor('#FFCE00', '#FFB74D'), 159 dark: getColor('#C67F15', '#F57C00'), 160 '100': getColor('#63400A', '#FFDCA8'), // for alert text 161 '200': getColor('#FEF5E8', '#301E04'), // for alert background 162 }, 163 info: { 164 main: getColor('#0062D2', '#29B6F6'), 165 light: getColor('#0062D2', '#4FC3F7'), 166 dark: getColor('#002754', '#0288D1'), 167 '100': getColor('#002754', '#A9E2FB'), // for alert text 168 '200': getColor('#E5EFFB', '#071F2E'), // for alert background 169 }, 170 success: { 171 main: getColor('#4CAF50', '#66BB6A'), 172 light: getColor('#90FF95', '#90FF95'), 173 dark: getColor('#318435', '#388E3C'), 174 '100': getColor('#1C4B1E', '#C2E4C3'), // for alert text 175 '200': getColor('#ECF8ED', '#0A130B'), // for alert background 176 }, 177 text: { 178 primary: getColor('#303549', '#F1F1F3'), 179 secondary: getColor('#62677B', '#A5A8B6'), 180 disabled: getColor('#D2D4DC', '#62677B'), 181 muted: getColor('#A5A8B6', '#8E92A3'), 182 highlight: getColor('#383D51', '#C9B3F9'), 183 }, 184 background: { 185 default: getColor('#F1F1F3', '#1B2030'), 186 paper: getColor('#FFFFFF', '#292E41'), 187 surface: getColor('#F7F7F9', '#383D51'), 188 surface2: getColor('#F9F9FB', '#383D51'), 189 header: getColor('#2B2D3C', '#1B2030'), 190 disabled: getColor('#EAEBEF', '#EBEBEF14'), 191 }, 192 divider: getColor('#EAEBEF', '#EBEBEF14'), 193 action: { 194 active: getColor('#8E92A3', '#EBEBEF8F'), 195 hover: getColor('#F1F1F3', '#EBEBEF14'), 196 selected: getColor('#EAEBEF', '#EBEBEF29'), 197 disabled: getColor('#BBBECA', '#EBEBEF4D'), 198 disabledBackground: getColor('#EAEBEF', '#EBEBEF1F'), 199 focus: getColor('#F1F1F3', '#EBEBEF1F'), 200 }, 201 other: { 202 standardInputLine: getColor('#383D511F', '#EBEBEF6B'), 203 }, 204 gradients: { 205 aaveGradient: 'linear-gradient(248.86deg, #B6509E 10.51%, #2EBAC6 93.41%)', 206 newGradient: 'linear-gradient(79.67deg, #8C3EBC 0%, #007782 95.82%)', 207 }, 208 }, 209 spacing: 4, 210 typography: { 211 fontFamily: FONT, 212 h5: undefined, 213 h6: undefined, 214 subtitle1: undefined, 215 subtitle2: undefined, 216 body1: undefined, 217 body2: undefined, 218 button: undefined, 219 overline: undefined, 220 display1: { 221 fontFamily: FONT, 222 fontWeight: 700, 223 letterSpacing: pxToRem(0.25), 224 lineHeight: '123.5%', 225 fontSize: pxToRem(32), 226 }, 227 h1: { 228 fontFamily: FONT, 229 fontWeight: 700, 230 letterSpacing: pxToRem(0.25), 231 lineHeight: '123.5%', 232 fontSize: pxToRem(28), 233 }, 234 h2: { 235 fontFamily: FONT, 236 fontWeight: 600, 237 letterSpacing: 'unset', 238 lineHeight: '133.4%', 239 fontSize: pxToRem(21), 240 }, 241 h3: { 242 fontFamily: FONT, 243 fontWeight: 600, 244 letterSpacing: pxToRem(0.15), 245 lineHeight: '160%', 246 fontSize: pxToRem(18), 247 }, 248 h4: { 249 fontFamily: FONT, 250 fontWeight: 600, 251 letterSpacing: pxToRem(0.15), 252 lineHeight: pxToRem(24), 253 fontSize: pxToRem(16), 254 }, 255 subheader1: { 256 fontFamily: FONT, 257 fontWeight: 600, 258 letterSpacing: pxToRem(0.15), 259 lineHeight: pxToRem(20), 260 fontSize: pxToRem(14), 261 }, 262 subheader2: { 263 fontFamily: FONT, 264 fontWeight: 500, 265 letterSpacing: pxToRem(0.1), 266 lineHeight: pxToRem(16), 267 fontSize: pxToRem(12), 268 }, 269 description: { 270 fontFamily: FONT, 271 fontWeight: 400, 272 letterSpacing: pxToRem(0.15), 273 lineHeight: '143%', 274 fontSize: pxToRem(14), 275 }, 276 caption: { 277 fontFamily: FONT, 278 fontWeight: 400, 279 letterSpacing: pxToRem(0.15), 280 lineHeight: pxToRem(16), 281 fontSize: pxToRem(12), 282 }, 283 buttonL: { 284 fontFamily: FONT, 285 fontWeight: 500, 286 letterSpacing: pxToRem(0.46), 287 lineHeight: pxToRem(24), 288 fontSize: pxToRem(16), 289 }, 290 buttonM: { 291 fontFamily: FONT, 292 fontWeight: 500, 293 lineHeight: pxToRem(24), 294 fontSize: pxToRem(14), 295 }, 296 buttonS: { 297 fontFamily: FONT, 298 fontWeight: 600, 299 letterSpacing: pxToRem(0.46), 300 lineHeight: pxToRem(20), 301 textTransform: 'uppercase', 302 fontSize: pxToRem(10), 303 }, 304 helperText: { 305 fontFamily: FONT, 306 fontWeight: 400, 307 letterSpacing: pxToRem(0.4), 308 lineHeight: pxToRem(12), 309 fontSize: pxToRem(10), 310 }, 311 tooltip: { 312 fontFamily: FONT, 313 fontWeight: 400, 314 letterSpacing: pxToRem(0.15), 315 lineHeight: pxToRem(16), 316 fontSize: pxToRem(12), 317 }, 318 main21: { 319 fontFamily: FONT, 320 fontWeight: 800, 321 lineHeight: '133.4%', 322 fontSize: pxToRem(21), 323 }, 324 secondary21: { 325 fontFamily: FONT, 326 fontWeight: 500, 327 lineHeight: '133.4%', 328 fontSize: pxToRem(21), 329 }, 330 main16: { 331 fontFamily: FONT, 332 fontWeight: 600, 333 letterSpacing: pxToRem(0.15), 334 lineHeight: pxToRem(24), 335 fontSize: pxToRem(16), 336 }, 337 secondary16: { 338 fontFamily: FONT, 339 fontWeight: 500, 340 letterSpacing: pxToRem(0.15), 341 lineHeight: pxToRem(24), 342 fontSize: pxToRem(16), 343 }, 344 main14: { 345 fontFamily: FONT, 346 fontWeight: 600, 347 letterSpacing: pxToRem(0.15), 348 lineHeight: pxToRem(20), 349 fontSize: pxToRem(14), 350 }, 351 secondary14: { 352 fontFamily: FONT, 353 fontWeight: 500, 354 letterSpacing: pxToRem(0.15), 355 lineHeight: pxToRem(20), 356 fontSize: pxToRem(14), 357 }, 358 main12: { 359 fontFamily: FONT, 360 fontWeight: 600, 361 letterSpacing: pxToRem(0.1), 362 lineHeight: pxToRem(16), 363 fontSize: pxToRem(12), 364 }, 365 secondary12: { 366 fontFamily: FONT, 367 fontWeight: 500, 368 letterSpacing: pxToRem(0.1), 369 lineHeight: pxToRem(16), 370 fontSize: pxToRem(12), 371 }, 372 }, 373 } as ThemeOptions; 374 }; 375 376 export function getThemedComponents(theme: Theme) { 377 return { 378 components: { 379 MuiSkeleton: { 380 styleOverrides: { 381 root: { 382 transform: 'unset', 383 }, 384 }, 385 }, 386 MuiOutlinedInput: { 387 styleOverrides: { 388 root: { 389 borderRadius: '6px', 390 borderColor: theme.palette.divider, 391 '&:hover .MuiOutlinedInput-notchedOutline': { 392 borderColor: '#CBCDD8', 393 }, 394 '&.Mui-focused .MuiOutlinedInput-notchedOutline': { 395 borderColor: '#CBCDD8', 396 }, 397 }, 398 }, 399 }, 400 MuiSlider: { 401 styleOverrides: { 402 root: { 403 '& .MuiSlider-thumb': { 404 color: theme.palette.mode === 'light' ? '#62677B' : '#C9B3F9', 405 }, 406 '& .MuiSlider-track': { 407 color: theme.palette.mode === 'light' ? '#383D51' : '#9C93B3', 408 }, 409 }, 410 }, 411 }, 412 MuiButton: { 413 defaultProps: { 414 disableElevation: true, 415 }, 416 styleOverrides: { 417 root: { 418 borderRadius: '4px', 419 }, 420 sizeLarge: { 421 ...theme.typography.buttonL, 422 padding: '10px 24px', 423 }, 424 sizeMedium: { 425 ...theme.typography.buttonM, 426 padding: '6px 12px', 427 }, 428 sizeSmall: { 429 ...theme.typography.buttonS, 430 padding: '0 6px', 431 }, 432 }, 433 variants: [ 434 { 435 props: { variant: 'surface' }, 436 style: { 437 color: theme.palette.common.white, 438 border: '1px solid', 439 borderColor: '#EBEBED1F', 440 backgroundColor: '#383D51', 441 '&:hover, &.Mui-focusVisible': { 442 backgroundColor: theme.palette.background.header, 443 }, 444 }, 445 }, 446 { 447 props: { variant: 'gradient' }, 448 style: { 449 color: theme.palette.common.white, 450 background: theme.palette.gradients.aaveGradient, 451 transition: 'all 0.2s ease', 452 '&:hover, &.Mui-focusVisible': { 453 background: theme.palette.gradients.aaveGradient, 454 opacity: '0.9', 455 }, 456 }, 457 }, 458 { 459 props: { color: 'primary', variant: 'outlined' }, 460 style: { 461 background: theme.palette.background.surface, 462 borderColor: theme.palette.divider, 463 }, 464 }, 465 ], 466 }, 467 MuiTypography: { 468 defaultProps: { 469 variant: 'description', 470 variantMapping: { 471 display1: 'h1', 472 h1: 'h1', 473 h2: 'h2', 474 h3: 'h3', 475 h4: 'h4', 476 subheader1: 'p', 477 subheader2: 'p', 478 caption: 'p', 479 description: 'p', 480 buttonL: 'p', 481 buttonM: 'p', 482 buttonS: 'p', 483 main12: 'p', 484 main14: 'p', 485 main16: 'p', 486 main21: 'p', 487 secondary12: 'p', 488 secondary14: 'p', 489 secondary16: 'p', 490 secondary21: 'p', 491 helperText: 'span', 492 tooltip: 'span', 493 }, 494 }, 495 }, 496 MuiLink: { 497 defaultProps: { 498 variant: 'description', 499 }, 500 }, 501 MuiMenu: { 502 defaultProps: { 503 PaperProps: { 504 elevation: 0, 505 variant: 'outlined', 506 style: { 507 minWidth: 240, 508 marginTop: '4px', 509 }, 510 }, 511 }, 512 }, 513 MuiList: { 514 styleOverrides: { 515 root: { 516 '.MuiMenuItem-root+.MuiDivider-root, .MuiDivider-root': { 517 marginTop: '4px', 518 marginBottom: '4px', 519 }, 520 }, 521 padding: { 522 paddingTop: '4px', 523 paddingBottom: '4px', 524 }, 525 }, 526 }, 527 MuiMenuItem: { 528 styleOverrides: { 529 root: { 530 padding: '12px 16px', 531 }, 532 }, 533 }, 534 MuiListItemText: { 535 styleOverrides: { 536 root: { 537 ...theme.typography.subheader1, 538 }, 539 }, 540 }, 541 MuiListItemIcon: { 542 styleOverrides: { 543 root: { 544 color: theme.palette.primary.light, 545 minWidth: 'unset !important', 546 marginRight: '12px', 547 }, 548 }, 549 }, 550 MuiDivider: { 551 styleOverrides: { 552 root: { 553 marginTop: 0, 554 marginBottom: 0, 555 }, 556 }, 557 }, 558 MuiPaper: { 559 styleOverrides: { 560 root: { 561 borderRadius: '4px', 562 }, 563 }, 564 variants: [ 565 { 566 props: { variant: 'outlined' }, 567 style: { 568 border: `1px solid ${theme.palette.divider}`, 569 boxShadow: '0px 0px 2px rgba(0, 0, 0, 0.2), 0px 2px 10px rgba(0, 0, 0, 0.1)', 570 background: 571 theme.palette.mode === 'light' 572 ? theme.palette.background.paper 573 : theme.palette.background.surface, 574 }, 575 }, 576 { 577 props: { variant: 'elevation' }, 578 style: { 579 boxShadow: '0px 2px 1px rgba(0, 0, 0, 0.05), 0px 0px 1px rgba(0, 0, 0, 0.25)', 580 ...(theme.palette.mode === 'dark' ? { backgroundImage: 'none' } : {}), 581 }, 582 }, 583 ], 584 }, 585 MuiContainer: { 586 styleOverrides: { 587 root: { 588 display: 'flex', 589 flexDirection: 'column', 590 flex: 1, 591 paddingBottom: '39px', 592 [theme.breakpoints.up('xs')]: { 593 paddingLeft: '8px', 594 paddingRight: '8px', 595 }, 596 [theme.breakpoints.up('xsm')]: { 597 paddingLeft: '20px', 598 paddingRight: '20px', 599 }, 600 [theme.breakpoints.up('sm')]: { 601 paddingLeft: '48px', 602 paddingRight: '48px', 603 }, 604 [theme.breakpoints.up('md')]: { 605 paddingLeft: '96px', 606 paddingRight: '96px', 607 }, 608 [theme.breakpoints.up('lg')]: { 609 paddingLeft: '20px', 610 paddingRight: '20px', 611 }, 612 [theme.breakpoints.up('xl')]: { 613 maxWidth: 'unset', 614 paddingLeft: '96px', 615 paddingRight: '96px', 616 }, 617 [theme.breakpoints.up('xxl')]: { 618 paddingLeft: 0, 619 paddingRight: 0, 620 maxWidth: '1440px', 621 }, 622 }, 623 }, 624 }, 625 MuiSwitch: { 626 styleOverrides: { 627 root: { 628 height: 20 + 6 * 2, 629 width: 34 + 6 * 2, 630 padding: 6, 631 }, 632 switchBase: { 633 padding: 8, 634 '&.Mui-checked': { 635 transform: 'translateX(14px)', 636 '& + .MuiSwitch-track': { 637 backgroundColor: theme.palette.success.main, 638 opacity: 1, 639 }, 640 }, 641 '&.Mui-disabled': { 642 opacity: theme.palette.mode === 'dark' ? 0.3 : 0.7, 643 }, 644 }, 645 thumb: { 646 color: theme.palette.common.white, 647 borderRadius: '6px', 648 width: '16px', 649 height: '16px', 650 boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.12)', 651 }, 652 track: { 653 opacity: 1, 654 backgroundColor: theme.palette.action.active, 655 borderRadius: '8px', 656 }, 657 }, 658 }, 659 MuiIcon: { 660 variants: [ 661 { 662 props: { fontSize: 'large' }, 663 style: { 664 fontSize: pxToRem(32), 665 }, 666 }, 667 ], 668 }, 669 MuiTableCell: { 670 styleOverrides: { 671 root: { 672 borderColor: theme.palette.divider, 673 }, 674 }, 675 }, 676 MuiAlert: { 677 styleOverrides: { 678 root: { 679 boxShadow: 'none', 680 borderRadius: '4px', 681 padding: '8px 12px', 682 ...theme.typography.caption, 683 alignItems: 'flex-start', 684 '.MuiAlert-message': { 685 padding: 0, 686 paddingTop: '2px', 687 paddingBottom: '2px', 688 }, 689 '.MuiAlert-icon': { 690 padding: 0, 691 opacity: 1, 692 '.MuiSvgIcon-root': { 693 fontSize: pxToRem(20), 694 }, 695 }, 696 a: { 697 ...theme.typography.caption, 698 fontWeight: 500, 699 textDecoration: 'underline', 700 '&:hover': { 701 textDecoration: 'none', 702 }, 703 }, 704 '.MuiButton-text': { 705 ...theme.typography.caption, 706 fontWeight: 500, 707 textDecoration: 'underline', 708 padding: 0, 709 margin: 0, 710 minWidth: 'unset', 711 '&:hover': { 712 textDecoration: 'none', 713 background: 'transparent', 714 }, 715 }, 716 }, 717 }, 718 defaultProps: { 719 iconMapping: { 720 error: ( 721 <SvgIcon color="error"> 722 <ExclamationIcon /> 723 </SvgIcon> 724 ), 725 info: ( 726 <SvgIcon color="info"> 727 <InformationCircleIcon /> 728 </SvgIcon> 729 ), 730 success: ( 731 <SvgIcon color="success"> 732 <CheckCircleIcon /> 733 </SvgIcon> 734 ), 735 warning: ( 736 <SvgIcon color="warning"> 737 <ExclamationCircleIcon /> 738 </SvgIcon> 739 ), 740 }, 741 }, 742 variants: [ 743 { 744 props: { severity: 'error' }, 745 style: { 746 color: theme.palette.error['100'], 747 background: theme.palette.error['200'], 748 a: { 749 color: theme.palette.error['100'], 750 }, 751 '.MuiButton-text': { 752 color: theme.palette.error['100'], 753 }, 754 }, 755 }, 756 { 757 props: { severity: 'info' }, 758 style: { 759 color: theme.palette.info['100'], 760 background: theme.palette.info['200'], 761 a: { 762 color: theme.palette.info['100'], 763 }, 764 '.MuiButton-text': { 765 color: theme.palette.info['100'], 766 }, 767 }, 768 }, 769 { 770 props: { severity: 'success' }, 771 style: { 772 color: theme.palette.success['100'], 773 background: theme.palette.success['200'], 774 a: { 775 color: theme.palette.success['100'], 776 }, 777 '.MuiButton-text': { 778 color: theme.palette.success['100'], 779 }, 780 }, 781 }, 782 { 783 props: { severity: 'warning' }, 784 style: { 785 color: theme.palette.warning['100'], 786 background: theme.palette.warning['200'], 787 a: { 788 color: theme.palette.warning['100'], 789 }, 790 '.MuiButton-text': { 791 color: theme.palette.warning['100'], 792 }, 793 }, 794 }, 795 ], 796 }, 797 MuiCssBaseline: { 798 styleOverrides: { 799 body: { 800 fontFamily: FONT, 801 fontWeight: 400, 802 fontSize: pxToRem(14), 803 minWidth: '375px', 804 '> div:first-of-type': { 805 minHeight: '100vh', 806 display: 'flex', 807 flexDirection: 'column', 808 }, 809 }, 810 }, 811 }, 812 MuiSvgIcon: { 813 styleOverrides: { 814 colorPrimary: { 815 color: theme.palette.primary.light, 816 }, 817 }, 818 }, 819 MuiSelect: { 820 defaultProps: { 821 IconComponent: (props) => ( 822 <SvgIcon sx={{ fontSize: '16px' }} {...props}> 823 <ChevronDownIcon /> 824 </SvgIcon> 825 ), 826 }, 827 styleOverrides: { 828 outlined: { 829 backgroundColor: theme.palette.background.surface, 830 ...theme.typography.buttonM, 831 padding: '6px 12px', 832 color: theme.palette.primary.light, 833 }, 834 }, 835 }, 836 MuiLinearProgress: { 837 styleOverrides: { 838 bar1Indeterminate: { 839 background: theme.palette.gradients.aaveGradient, 840 }, 841 bar2Indeterminate: { 842 background: theme.palette.gradients.aaveGradient, 843 }, 844 }, 845 }, 846 }, 847 } as ThemeOptions; 848 }