build ok,

This commit is contained in:
louiscklaw
2025-04-14 09:26:24 +08:00
commit 6c931c1fe8
770 changed files with 63959 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
/* Remove if fonts are not used */
@import '~@fontsource/inter/100.css';
@import '~@fontsource/inter/200.css';
@import '~@fontsource/inter/300.css';
@import '~@fontsource/inter/400.css';
@import '~@fontsource/inter/500.css';
@import '~@fontsource/inter/600.css';
@import '~@fontsource/inter/700.css';
@import '~@fontsource/inter/800.css';
@import '~@fontsource/inter/900.css';
@import '~@fontsource/roboto-mono/300.css';
@import '~@fontsource/roboto-mono/400.css';
@import '~@fontsource/plus-jakarta-sans/600.css';
@import '~@fontsource/plus-jakarta-sans/700.css';
/* Remove if mapbox is not used */
@import '~mapbox-gl/dist/mapbox-gl.css';
/* Remove is recharts is not used */
.recharts-cartesian-axis-tick-value {
color: var(--mui-palette-text-secondary);
font-size: var(--fontSize-xs);
}
.recharts-cartesian-grid line {
stroke: var(--mui-palette-divider);
}
.recharts-pie path:focus {
outline: none;
}
/* Remove if react-simple-maps is not used */
.rsm-geographies path:focus {
outline: none;
}
/* Remove if fullcalendar is not used */
.fc {
--fc-bg-event-opacity: 1;
--fc-border-color: var(--mui-palette-divider);
--fc-daygrid-event-dot-width: 10px;
--fc-event-bg-color: var(--mui-palette-background-paper);
--fc-event-border-color: var(--mui-palette-divider);
--fc-event-text-color: var(--mui-palette-primary-contrastTex);
--fc-list-event-hover-bg-color: var(--mui-palette-background-default);
--fc-neutral-bg-color: var(--mui-palette-background-default);
--fc-page-bg-color: var(--mui-palette-background-default);
--fc-today-bg-color: var(--mui-palette-background-level1);
color: var(--mui-palette-text-primary);
}
.fc .fc-license-message {
display: none;
}
.fc .fc-list {
border-color: transparent;
}
.fc .fc-scrollgrid {
border-color: transparent;
}
.fc .fc-scrollgrid-section-header > th {
border-color: transparent;
}
.fc .fc-scrollgrid-section-body > td {
border-color: transparent;
}
.fc .fc-col-header-cell:first-of-type {
border-left-color: transparent;
}
.fc .fc-col-header-cell:last-of-type {
border-right-color: transparent;
}
.fc .fc-col-header-cell-cushion {
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.5px;
line-height: 2.5;
padding: 8px;
text-transform: uppercase;
}
.fc .fc-daygrid-day-frame {
padding: 12px;
}
.fc .fc-day-other .fc-daygrid-day-top {
color: var(--mui-palette-text-secondary);
}
.fc .fc-event {
background: transparent;
border: none;
padding: 0;
}
/* Variables */
:root {
--fontSize-xs: 0.75rem;
--fontSize-sm: 0.875rem;
--fontSize-md: 1rem;
--fontSize-lg: 1.125rem;
--fontSize-xl: 1.25rem;
--fontSize-2xl: 1.5rem;
--icon-fontSize-sm: 1rem;
--icon-fontSize-md: 1.25rem;
--icon-fontSize-lg: 1.5rem;
/* Remember to keep in sync with theme breakpoints */
--maxWidth-xs: 0;
--maxWidth-sm: 600px;
--maxWidth-md: 900px;
--maxWidth-lg: 1200px;
--maxWidth-xl: 1440px;
}
*:focus-visible {
outline: 2px solid var(--mui-palette-primary-main);
}
html {
height: 100%;
}
body {
height: 100%;
}

View File

@@ -0,0 +1,284 @@
import type { ColorSystemOptions, PaletteColorOptions } from '@mui/material/styles';
import { logger } from '@/lib/default-logger';
import {
california,
chateauGreen,
kepple,
neonBlue,
nevada,
redOrange,
royalBlue,
shakespeare,
stormGrey,
tomatoOrange,
} from './colors';
import type { ColorScheme, PrimaryColor } from './types';
const primarySchemes: Record<PrimaryColor, Record<ColorScheme, PaletteColorOptions>> = {
chateauGreen: {
dark: {
...chateauGreen,
light: chateauGreen[300],
main: chateauGreen[400],
dark: chateauGreen[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
light: {
...chateauGreen,
light: chateauGreen[400],
main: chateauGreen[500],
dark: chateauGreen[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
},
neonBlue: {
dark: {
...neonBlue,
light: neonBlue[300],
main: neonBlue[400],
dark: neonBlue[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
light: {
...neonBlue,
light: neonBlue[400],
main: neonBlue[500],
dark: neonBlue[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
},
royalBlue: {
dark: {
...royalBlue,
light: royalBlue[300],
main: royalBlue[400],
dark: royalBlue[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
light: {
...royalBlue,
light: royalBlue[400],
main: royalBlue[500],
dark: royalBlue[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
},
tomatoOrange: {
dark: {
...tomatoOrange,
light: tomatoOrange[300],
main: tomatoOrange[400],
dark: tomatoOrange[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
light: {
...tomatoOrange,
light: tomatoOrange[400],
main: tomatoOrange[500],
dark: tomatoOrange[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
},
};
interface Config {
primaryColor: PrimaryColor;
}
export function colorSchemes(config: Config): Partial<Record<ColorScheme, ColorSystemOptions>> {
let primary = primarySchemes[config.primaryColor];
if (!primary) {
logger.warn(`No primary color found for ${config.primaryColor}. Using neonBlue instead.`);
primary = primarySchemes.neonBlue;
}
return {
dark: {
palette: {
action: { disabledBackground: 'rgba(0, 0, 0, 0.12)' },
background: {
default: 'var(--mui-palette-neutral-950)',
defaultChannel: '9 10 11',
paper: 'var(--mui-palette-neutral-900)',
level1: 'var(--mui-palette-neutral-800)',
level2: 'var(--mui-palette-neutral-700)',
level3: 'var(--mui-palette-neutral-600)',
},
common: { black: '#000000', white: '#ffffff' },
divider: 'var(--mui-palette-neutral-700)',
dividerChannel: '50 56 62',
error: {
...redOrange,
light: redOrange[300],
main: redOrange[400],
dark: redOrange[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
info: {
...shakespeare,
light: shakespeare[300],
main: shakespeare[400],
dark: shakespeare[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
neutral: { ...nevada },
primary: primary.dark,
secondary: {
...nevada,
light: nevada[100],
main: nevada[200],
dark: nevada[300],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
success: {
...kepple,
light: kepple[300],
main: kepple[400],
dark: kepple[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
text: {
primary: 'var(--mui-palette-neutral-100)',
primaryChannel: '240 244 248',
secondary: 'var(--mui-palette-neutral-400)',
secondaryChannel: '159 166 173',
disabled: 'var(--mui-palette-neutral-600)',
},
warning: {
...california,
light: california[300],
main: california[400],
dark: california[500],
contrastText: 'var(--mui-palette-common-black)',
activated: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
Avatar: { defaultBg: 'var(--mui-palette-neutral-200)' },
Backdrop: { bg: 'rgba(0, 0, 0, 0.5)' },
OutlinedInput: { border: 'var(--mui-palette-neutral-700)' },
TableCell: { border: 'var(--mui-palette-divider)' },
Tooltip: { bg: 'rgba(10, 13, 20, 0.75)' },
},
},
light: {
palette: {
action: { disabledBackground: 'rgba(0, 0, 0, 0.06)' },
background: {
default: 'var(--mui-palette-common-white)',
defaultChannel: '255 255 255',
paper: 'var(--mui-palette-common-white)',
level1: 'var(--mui-palette-neutral-50)',
level2: 'var(--mui-palette-neutral-100)',
level3: 'var(--mui-palette-neutral-200)',
},
common: { black: '#000000', white: '#ffffff' },
divider: 'var(--mui-palette-neutral-200)',
dividerChannel: '220 223 228',
error: {
...redOrange,
light: redOrange[400],
main: redOrange[500],
dark: redOrange[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-error-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
info: {
...shakespeare,
light: shakespeare[400],
main: shakespeare[500],
dark: shakespeare[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-info-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
neutral: { ...stormGrey },
primary: primary.light,
secondary: {
...nevada,
light: nevada[600],
main: nevada[700],
dark: nevada[800],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-secondary-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
success: {
...kepple,
light: kepple[400],
main: kepple[500],
dark: kepple[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-success-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
text: {
primary: 'var(--mui-palette-neutral-900)',
primaryChannel: '33 38 54',
secondary: 'var(--mui-palette-neutral-500)',
secondaryChannel: '102 112 133',
disabled: 'var(--mui-palette-neutral-400)',
},
warning: {
...california,
light: california[400],
main: california[500],
dark: california[600],
contrastText: 'var(--mui-palette-common-white)',
activated: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-activatedOpacity))',
hovered: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-hoverOpacity))',
selected: 'rgba(var(--mui-palette-warning-mainChannel) / var(--mui-palette-action-selectedOpacity))',
},
Avatar: { defaultBg: 'var(--mui-palette-neutral-600)' },
Backdrop: { bg: 'rgb(18, 22, 33, 0.8)' },
OutlinedInput: { border: 'var(--mui-palette-neutral-200)' },
TableCell: { border: 'var(--mui-palette-divider)' },
Tooltip: { bg: 'rgba(10, 13, 20, 0.75)' },
},
},
};
}

View File

@@ -0,0 +1,141 @@
import type { PaletteRange } from '@mui/material/styles/createPalette';
export const california = {
50: '#fffaea',
100: '#fff3c6',
200: '#ffe587',
300: '#ffd049',
400: '#ffbb1f',
500: '#fb9c0c',
600: '#de7101',
700: '#b84d05',
800: '#953b0b',
900: '#7b310c',
950: '#471701',
} satisfies PaletteRange;
export const chateauGreen = {
50: '#edfcf2',
100: '#d2f9de',
200: '#aaf0c4',
300: '#72e3a3',
400: '#3acd7e',
500: '#16b364',
600: '#0a9150',
700: '#087442',
800: '#095c37',
900: '#094b2f',
950: '#032b1a',
} satisfies PaletteRange;
export const kepple = {
50: '#f0fdfa',
100: '#ccfbef',
200: '#9af5e1',
300: '#5fe9ce',
400: '#2ed3b8',
500: '#15b79f',
600: '#0e9382',
700: '#107569',
800: '#115e56',
900: '#134e48',
950: '#042f2c',
} satisfies PaletteRange;
export const neonBlue = {
50: '#ecf0ff',
100: '#dde3ff',
200: '#c2cbff',
300: '#9ca7ff',
400: '#7578ff',
500: '#635bff',
600: '#4e36f5',
700: '#432ad8',
800: '#3725ae',
900: '#302689',
950: '#1e1650',
} satisfies PaletteRange;
export const nevada = {
50: '#fbfcfe',
100: '#f0f4f8',
200: '#dde7ee',
300: '#cdd7e1',
400: '#9fa6ad',
500: '#636b74',
600: '#555e68',
700: '#32383e',
800: '#202427',
900: '#121517',
950: '#090a0b',
} satisfies PaletteRange;
export const redOrange = {
50: '#fef3f2',
100: '#fee4e2',
200: '#ffcdc9',
300: '#fdaaa4',
400: '#f97970',
500: '#f04438',
600: '#de3024',
700: '#bb241a',
800: '#9a221a',
900: '#80231c',
950: '#460d09',
} satisfies PaletteRange;
export const royalBlue = {
50: '#ecf3ff',
100: '#dce8ff',
200: '#c0d4ff',
300: '#9bb6ff',
400: '#738dff',
500: '#5265ff',
600: '#3339f8',
700: '#3739de',
800: '#2225b1',
900: '#24298b',
950: '#151651',
} satisfies PaletteRange;
export const shakespeare = {
50: '#ecfdff',
100: '#cff7fe',
200: '#a4eefd',
300: '#66e0fa',
400: '#10bee8',
500: '#04aad6',
600: '#0787b3',
700: '#0d6d91',
800: '#145876',
900: '#154964',
950: '#082f44',
} satisfies PaletteRange;
export const stormGrey = {
50: '#f9fafb',
100: '#f1f1f4',
200: '#dcdfe4',
300: '#b3b9c6',
400: '#8a94a6',
500: '#667085',
600: '#565e73',
700: '#434a60',
800: '#313749',
900: '#212636',
950: '#121621',
} satisfies PaletteRange;
export const tomatoOrange = {
50: '#fff3ed',
100: '#ffe2d4',
200: '#ffc1a8',
300: '#ffa280',
400: '#ff9771',
500: '#ff6c47',
600: '#fe4011',
700: '#ed3507',
800: '#9f2c0f',
900: '#7e1110',
950: '#440608',
} satisfies PaletteRange;

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiAlert = { styleOverrides: { message: { fontWeight: 500 } } } satisfies Components<Theme>['MuiAlert'];

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
import type { Components } from '@mui/material/styles';
import { User as UserIcon } from '@phosphor-icons/react/dist/ssr/User';
import type { Theme } from '../types';
export const MuiAvatar = {
defaultProps: { children: <UserIcon fontSize="var(--Icon-fontSize)" /> },
styleOverrides: {
root: {
'--Icon-fontSize': 'var(--icon-fontSize-md)',
fontSize: '0.875rem',
fontWeight: 500,
height: 'var(--Avatar-size, 40px)',
letterSpacing: 0,
width: 'var(--Avatar-size, 40px)',
},
},
} satisfies Components<Theme>['MuiAvatar'];

View File

@@ -0,0 +1,10 @@
import { backdropClasses } from '@mui/material/Backdrop';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiBackdrop = {
styleOverrides: {
root: { [`&:not(.${backdropClasses.invisible})`]: { backgroundColor: 'var(--mui-palette-Backdrop-bg)' } },
},
} satisfies Components<Theme>['MuiBackdrop'];

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiButtonBase = { defaultProps: { disableRipple: true } } satisfies Components<Theme>['MuiButtonBase'];

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiButtonGroup = { defaultProps: { disableRipple: true } } satisfies Components<Theme>['MuiButtonGroup'];

View File

@@ -0,0 +1,107 @@
import { buttonClasses } from '@mui/material/Button';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
function getContainedVars(color: string): Record<string, string> {
return {
'--Button-containedBg': `var(--mui-palette-${color}-dark)`,
'--Button-containedBgGradient': `linear-gradient(180deg, var(--mui-palette-${color}-main) 0%, var(--mui-palette-${color}-dark) 100%)`,
'--Button-containedStroke': `inset 0px 0px 0px 1px var(--mui-palette-${color}-dark), inset 0px 2px 0px 0px rgba(255, 255, 255, 0.16)`,
};
}
function getOutlinedVars(color: string, dark: boolean): Record<string, string> {
const vars = {
'--Button-outlinedBorder': `var(--mui-palette-${color}-main)`,
'--Button-outlinedHoverBg': `var(--mui-palette-${color}-hovered)`,
'--Button-outlinedActiveBg': `var(--mui-palette-${color}-activated)`,
};
// Custom case for secondary
if (color === 'secondary') {
if (dark) {
vars['--Button-outlinedBorder'] = 'var(--mui-palette-secondary-700)';
} else {
vars['--Button-outlinedBorder'] = 'var(--mui-palette-secondary-200)';
}
}
return vars;
}
function getTextVars(color: string): Record<string, string> {
return {
'--Button-textHoverBg': `var(--mui-palette-${color}-hovered)`,
'--Button-textActiveBg': `var(--mui-palette-${color}-activated)`,
};
}
export const MuiButton = {
defaultProps: { disableRipple: true },
styleOverrides: {
root: {
borderRadius: '8px',
minHeight: 'var(--Button-minHeight)',
minWidth: 'unset',
textTransform: 'none',
'&:focus-visible': { outline: '2px solid var(--mui-palette-primary-main)' },
},
text: {
'&:hover': { backgroundColor: 'var(--Button-textHoverBg)' },
'&:active': { backgroundColor: 'var(--Button-textActiveBg)' },
},
textPrimary: getTextVars('primary'),
textSecondary: getTextVars('secondary'),
textSuccess: getTextVars('success'),
textInfo: getTextVars('info'),
textWarning: getTextVars('warning'),
textError: getTextVars('error'),
outlined: {
boxShadow: 'var(--mui-shadows-1)',
borderColor: 'var(--Button-outlinedBorder)',
'&:hover': { borderColor: 'var(--Button-outlinedBorder)', backgroundColor: 'var(--Button-outlinedHoverBg)' },
'&:active': { backgroundColor: 'var(--Button-outlinedActiveBg)' },
},
outlinedPrimary: ({ theme }) => {
return getOutlinedVars('primary', theme.palette.mode === 'dark');
},
outlinedSecondary: ({ theme }) => {
return getOutlinedVars('secondary', theme.palette.mode === 'dark');
},
outlinedSuccess: ({ theme }) => {
return getOutlinedVars('success', theme.palette.mode === 'dark');
},
outlinedInfo: ({ theme }) => {
return getOutlinedVars('info', theme.palette.mode === 'dark');
},
outlinedWarning: ({ theme }) => {
return getOutlinedVars('warning', theme.palette.mode === 'dark');
},
outlinedError: ({ theme }) => {
return getOutlinedVars('error', theme.palette.mode === 'dark');
},
contained: {
backgroundColor: 'var(--Button-containedBg)',
backgroundImage: 'var(--Button-containedBgGradient)',
boxShadow: 'var(--mui-shadows-1), var(--Button-containedStroke)',
overflow: 'hidden',
'&:hover': {
boxShadow:
'var(--mui-shadows-8), var(--Button-containedStroke), inset 0px 6px 10px 0px rgba(255, 255, 255, 0.10)',
},
'&:active': { backgroundImage: 'var(--Button-containedBg)' },
'&:focus-visible': { boxShadow: 'var(--mui-shadows-8)', outlineOffset: '1px' },
[`&.${buttonClasses.disabled}`]: { backgroundImage: 'none', '&::before': { boxShadow: 'none' } },
},
containedPrimary: getContainedVars('primary'),
containedSecondary: getContainedVars('secondary'),
containedSuccess: getContainedVars('success'),
containedInfo: getContainedVars('info'),
containedWarning: getContainedVars('warning'),
containedError: getContainedVars('error'),
sizeSmall: { '--Button-minHeight': '32x', fontSize: '0.8125rem', lineHeight: '24px' },
sizeMedium: { '--Button-minHeight': '40x', fontSize: '0.875rem', lineHeight: '28px' },
sizeLarge: { '--Button-minHeight': '48x', fontSize: '0.9375rem', lineHeight: '32px' },
},
} satisfies Components<Theme>['MuiButton'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiCardActions = {
styleOverrides: { root: { padding: '8px 16px 16px' } },
} satisfies Components<Theme>['MuiCardActions'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiCardContent = {
styleOverrides: { root: { padding: '16px 24px 32px 24px', '&:last-child': { paddingBottom: '32px' } } },
} satisfies Components<Theme>['MuiCardContent'];

View File

@@ -0,0 +1,19 @@
import { avatarClasses } from '@mui/material/Avatar';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiCardHeader = {
defaultProps: { titleTypographyProps: { variant: 'h6' }, subheaderTypographyProps: { variant: 'body2' } },
styleOverrides: {
root: { padding: '32px 24px 16px' },
avatar: {
[`& .${avatarClasses.root}`]: {
'--Icon-fontSize': 'var(--icon-fontSize-lg)',
backgroundColor: 'var(--mui-palette-background-paper)',
boxShadow: 'var(--mui-shadows-8)',
color: 'var(--mui-palette-text-primary)',
},
},
},
} satisfies Components<Theme>['MuiCardHeader'];

View File

@@ -0,0 +1,20 @@
import { paperClasses } from '@mui/material/Paper';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiCard = {
styleOverrides: {
root: ({ theme }) => {
return {
borderRadius: '20px',
[`&.${paperClasses.elevation1}`]: {
boxShadow:
theme.palette.mode === 'dark'
? '0 5px 22px 0 rgba(0, 0, 0, 0.24), 0 0 0 1px rgba(255, 255, 255, 0.12)'
: '0 5px 22px 0 rgba(0, 0, 0, 0.04), 0 0 0 1px rgba(0, 0, 0, 0.06)',
},
};
},
},
} satisfies Components<Theme>['MuiCard'];

View File

@@ -0,0 +1,63 @@
import * as React from 'react';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
function Icon(): React.JSX.Element {
return (
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path
clipRule="evenodd"
d="M8 2C4.68629 2 2 4.68629 2 8V16C2 19.3137 4.68629 22 8 22H16C19.3137 22 22 19.3137 22 16V8C22 4.68629 19.3137 2 16 2H8ZM8 4C5.79086 4 4 5.79086 4 8V16C4 18.2091 5.79086 20 8 20H16C18.2091 20 20 18.2091 20 16V8C20 5.79086 18.2091 4 16 4H8Z"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
);
}
function CheckedIcon(): React.JSX.Element {
return (
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<rect fill="currentColor" height="20" rx="6" width="20" x="2" y="2" />
<path
d="M7.55566 11.7222L10.5186 14.7778L16.4446 8.66669"
stroke="white"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
</svg>
);
}
function IndeterminateIcon(): React.JSX.Element {
return (
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path
clipRule="evenodd"
d="M8 2C4.68629 2 2 4.68629 2 8V16C2 19.3137 4.68629 22 8 22H16C19.3137 22 22 19.3137 22 16V8C22 4.68629 19.3137 2 16 2H8ZM8 4C5.79086 4 4 5.79086 4 8V16C4 18.2091 5.79086 20 8 20H16C18.2091 20 20 18.2091 20 16V8C20 5.79086 18.2091 4 16 4H8Z"
fill="currentColor"
fillRule="evenodd"
/>
<path d="M8 12H16" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" />
</svg>
);
}
export const MuiCheckbox = {
defaultProps: {
checkedIcon: <CheckedIcon />,
color: 'primary',
disableRipple: true,
icon: <Icon />,
indeterminateIcon: <IndeterminateIcon />,
},
styleOverrides: {
root: {
borderRadius: '8px',
padding: 0,
'&.Mui-focusVisible': { outline: '2px solid var(--mui-palette-primary-main)' },
},
},
} satisfies Components<Theme>['MuiCheckbox'];

View File

@@ -0,0 +1,85 @@
import * as React from 'react';
import { chipClasses } from '@mui/material/Chip';
import type { Components } from '@mui/material/styles';
import { XCircle as XCircleIcon } from '@phosphor-icons/react/dist/ssr/XCircle';
import type { Theme } from '../types';
function getSoftVars(color: string, dark: boolean): Record<string, string> {
if (dark) {
return {
'--Chip-softBg': `var(--mui-palette-${color}-800)`,
'--Chip-softColor': `var(--mui-palette-${color}-200)`,
'--Chip-softDisabledBg': `var(--mui-palette-${color}-800)`,
'--Chip-softDisabledColor': `var(--mui-palette-${color}-500)`,
'--Chip-softHoverBg': `var(--mui-palette-${color}-700)`,
'--Chip-softDeleteIconColor': `var(--mui-palette-${color}-200)`,
'--Chip-softDeleteIconHoverColor': `var(--mui-palette-${color}-50)`,
};
}
return {
'--Chip-softBg': `var(--mui-palette-${color}-100)`,
'--Chip-softColor': `var(--mui-palette-${color}-700)`,
'--Chip-softDisabledBg': `var(--mui-palette-${color}-50)`,
'--Chip-softDisabledColor': `var(--mui-palette-${color}-400)`,
'--Chip-softHoverBg': `var(--mui-palette-${color}-200)`,
'--Chip-softDeleteIconColor': `var(--mui-palette-${color}-700)`,
'--Chip-softDeleteIconHoverColor': `var(--mui-palette-${color}-800)`,
};
}
export const MuiChip = {
defaultProps: {
color: 'secondary', // default will be removed in material v6
deleteIcon: <XCircleIcon />,
},
styleOverrides: {
root: { borderRadius: '12px', fontWeight: 500 },
outlinedSecondary: ({ theme }) => {
// Custom case for secondary, the rest is handled by the theme
if (theme.palette.mode === 'dark') {
return { borderColor: 'var(--mui-palette-secondary-700)', color: 'var(--mui-palette-secondary-50)' };
}
return { borderColor: 'var(--mui-palette-secondary-200)', color: 'var(--mui-palette-secondary-900)' };
},
soft: ({ ownerState }) => {
return {
backgroundColor: 'var(--Chip-softBg)',
color: 'var(--Chip-softColor)',
...(ownerState.disabled && {
backgroundColor: 'var(--Chip-softDisabledBg)',
color: 'var(--Chip-softDisabledColor)',
}),
...(ownerState.clickable && { '&:hover': { backgroundColor: 'var(--Chip-softHoverBg)' } }),
[`& .${chipClasses.deleteIcon}`]: {
color: 'var(--Chip-softDeleteIconColor)',
'&:hover': { color: 'var(--Chip-softDeleteIconHoverColor)' },
},
'&.Mui-focusVisible': { backgroundColor: 'var(--Chip-softHoverBg)' },
};
},
softPrimary: ({ theme }) => {
return getSoftVars('primary', theme.palette.mode === 'dark');
},
softSecondary: ({ theme }) => {
return getSoftVars('secondary', theme.palette.mode === 'dark');
},
softSuccess: ({ theme }) => {
return getSoftVars('success', theme.palette.mode === 'dark');
},
softInfo: ({ theme }) => {
return getSoftVars('info', theme.palette.mode === 'dark');
},
softWarning: ({ theme }) => {
return getSoftVars('warning', theme.palette.mode === 'dark');
},
softError: ({ theme }) => {
return getSoftVars('error', theme.palette.mode === 'dark');
},
iconSmall: { fontSize: 'var(--icon-fontSize-sm)' },
iconMedium: { fontSize: 'var(--icon-fontSize-md)' },
},
} satisfies Components<Theme>['MuiChip'];

View File

@@ -0,0 +1,100 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
import { MuiAlert } from './alert';
import { MuiAvatar } from './avatar';
import { MuiBackdrop } from './backdrop';
import { MuiButton } from './button';
import { MuiButtonBase } from './button-base';
import { MuiButtonGroup } from './button-group';
import { MuiCard } from './card';
import { MuiCardActions } from './card-actions';
import { MuiCardContent } from './card-content';
import { MuiCardHeader } from './card-header';
import { MuiCheckbox } from './checkbox';
import { MuiChip } from './chip';
import { MuiFilledInput } from './filled-input';
import { MuiFormControlLabel } from './form-control-label';
import { MuiFormGroup } from './form-group';
import { MuiFormLabel } from './form-label';
import { MuiIconButton } from './icon-button';
import { MuiInput } from './input';
import { MuiInputBase } from './input-base';
import { MuiInputLabel } from './input-label';
import { MuiLinearProgress } from './linear-progress';
import { MuiLink } from './link';
import { MuiList } from './list';
import { MuiListItem } from './list-item';
import { MuiListItemAvatar } from './list-item-avatar';
import { MuiListItemButton } from './list-item-button';
import { MuiListItemIcon } from './list-item-icon';
import { MuiListItemText } from './list-item-text';
import { MuiMenu } from './menu';
import { MuiMenuItem } from './menu-item';
import { MuiOutlinedInput } from './outlined-input';
import { MuiPaper } from './paper';
import { MuiPopover } from './popover';
import { MuiRadio } from './radio';
import { MuiSelect } from './select';
import { MuiStack } from './stack';
import { MuiSwitch } from './switch';
import { MuiTab } from './tab';
import { MuiTableBody } from './table-body';
import { MuiTableCell } from './table-cell';
import { MuiTableHead } from './table-head';
import { MuiTablePagination } from './table-pagination';
import { MuiTabs } from './tabs';
import { MuiTimelineConnector } from './timeline-connector';
import { MuiToggleButton } from './toggle-button';
import { MuiToggleButtonGroup } from './toggle-button-group';
import { MuiTooltip } from './tooltip';
export const components = {
MuiAlert,
MuiAvatar,
MuiBackdrop,
MuiButton,
MuiButtonBase,
MuiButtonGroup,
MuiCard,
MuiCardActions,
MuiCardContent,
MuiCardHeader,
MuiCheckbox,
MuiChip,
MuiFilledInput,
MuiFormControlLabel,
MuiFormGroup,
MuiFormLabel,
MuiIconButton,
MuiInput,
MuiInputBase,
MuiInputLabel,
MuiLinearProgress,
MuiLink,
MuiList,
MuiListItem,
MuiListItemAvatar,
MuiListItemButton,
MuiListItemIcon,
MuiListItemText,
MuiMenu,
MuiMenuItem,
MuiOutlinedInput,
MuiPaper,
MuiPopover,
MuiRadio,
MuiSelect,
MuiStack,
MuiSwitch,
MuiTab,
MuiTableBody,
MuiTableCell,
MuiTableHead,
MuiTablePagination,
MuiTabs,
MuiTimelineConnector,
MuiToggleButton,
MuiToggleButtonGroup,
MuiTooltip,
} satisfies Components<Theme>;

View File

@@ -0,0 +1,22 @@
import { inputBaseClasses } from '@mui/material/InputBase';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiFilledInput = {
defaultProps: { disableUnderline: true },
styleOverrides: {
root: { 'label + &': { marginTop: '8px' } },
input: {
height: 'auto',
padding: 0,
[`label[data-shrink=false]+.${inputBaseClasses.formControl} &`]: {
'&::placeholder': { opacity: '1 !important' },
},
'&:-webkit-autofill': {
marginInline: 'calc(var(--Input-paddingInline) * -1)',
paddingInline: 'var(--Input-paddingInline)',
},
},
},
} satisfies Components<Theme>['MuiFilledInput'];

View File

@@ -0,0 +1,8 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiFormControlLabel = {
defaultProps: { slotProps: { typography: { variant: 'subtitle2' } } },
styleOverrides: { root: { gap: '8px', margin: 0 } },
} satisfies Components<Theme>['MuiFormControlLabel'];

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiFormGroup = { styleOverrides: { root: { gap: '16px' } } } satisfies Components<Theme>['MuiFormGroup'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiFormLabel = {
styleOverrides: { root: { color: 'var(--mui-palette-text-primary)', fontSize: '0.875rem', fontWeight: 500 } },
} satisfies Components<Theme>['MuiFormLabel'];

View File

@@ -0,0 +1,49 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiIconButton = {
defaultProps: { color: 'secondary', disableRipple: true },
styleOverrides: {
root: {
borderRadius: '8px',
height: 'var(--IconButton-size)',
width: 'var(--IconButton-size)',
'&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.04)' },
'&:focus-visible': { outline: '2px solid var(--mui-palette-primary-main)' },
},
colorPrimary: {
color: 'var(--mui-palette-primary-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-primary-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-primary-activated)' },
},
colorSecondary: {
color: 'var(--mui-palette-secondary-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-secondary-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-secondary-activated)' },
},
colorInfo: {
color: 'var(--mui-palette-info-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-info-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-info-activated)' },
},
colorSuccess: {
color: 'var(--mui-palette-success-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-success-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-success-activated)' },
},
colorWarning: {
color: 'var(--mui-palette-warning-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-warning-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-warning-activated)' },
},
colorError: {
color: 'var(--mui-palette-error-main)',
'&:hover': { backgroundColor: 'var(--mui-palette-error-hovered)' },
'&:active': { backgroundColor: 'var(--mui-palette-error-activated)' },
},
sizeSmall: { '--IconButton-size': '32px' },
sizeMedium: { '--IconButton-size': '40px' },
sizeLarge: { '--IconButton-size': '48px' },
},
} satisfies Components<Theme>['MuiIconButton'];

View File

@@ -0,0 +1,34 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiInputBase = {
styleOverrides: {
root: {
'--Input-borderRadius': '8px',
'--Input-paddingBlock': 0,
'--Input-paddingInline': '12px',
'--Input-minHeight': '40px',
borderRadius: 'var(--Input-borderRadius)',
paddingBlock: 'var(--Input-paddingBlock)',
paddingInline: 'var(--Input-paddingInline)',
minHeight: 'var(--Input-minHeight)',
},
input: {
alignItems: 'center',
alignSelf: 'stretch',
display: 'inline-flex !important', // Fix flicker
fontSize: 'var(--Input-fontSize, 1rem)',
'&::placeholder': { color: 'var(--mui-palette-text-secondary)', opacity: 1 },
'&:-webkit-autofill': {
borderRadius: 'inherit',
marginBlock: 'calc(var(--Input-paddingBlock) * -1)',
marginInline: 'calc(var(--Input-paddingInline) * -1)',
paddingBlock: 'var(--Input-paddingBlock)',
paddingInline: 'var(--Input-paddingInline)',
},
},
multiline: { '--Input-paddingBlock': '12px' },
sizeSmall: { '--Input-fontSize': '0.875rem', '--Input-paddingInline': '8px', '--Input-minHeight': '32px' },
},
} satisfies Components<Theme>['MuiInputBase'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiInputLabel = {
styleOverrides: { root: { maxWidth: '100%', position: 'static', transform: 'none' } },
} satisfies Components<Theme>['MuiInputLabel'];

View File

@@ -0,0 +1,22 @@
import { inputBaseClasses } from '@mui/material/InputBase';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiInput = {
defaultProps: { disableUnderline: true },
styleOverrides: {
root: { 'label + &': { marginTop: '8px' } },
input: {
height: 'auto',
padding: 0,
[`label[data-shrink=false]+.${inputBaseClasses.formControl} &`]: {
'&::placeholder': { opacity: '1 !important' },
},
'&:-webkit-autofill': {
marginInline: 'calc(var(--Input-paddingInline) * -1)',
paddingInline: 'var(--Input-paddingInline)',
},
},
},
} satisfies Components<Theme>['MuiInput'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiLinearProgress = {
styleOverrides: { root: { borderRadius: '8px', overflow: 'hidden' } },
} satisfies Components<Theme>['MuiLinearProgress'];

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiLink = { defaultProps: { underline: 'hover' } } satisfies Components<Theme>['MuiLink'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiListItemAvatar = {
styleOverrides: { root: { minWidth: 'auto' } },
} satisfies Components<Theme>['MuiListItemAvatar'];

View File

@@ -0,0 +1,8 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiListItemButton = {
defaultProps: { disableRipple: true },
styleOverrides: { root: { gap: 'var(--ListItem-gap)' } },
} satisfies Components<Theme>['MuiListItemButton'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiListItemIcon = {
styleOverrides: { root: { color: 'inherit', fontSize: 'var(--icon-fontSize-md)', minWidth: 'auto' } },
} satisfies Components<Theme>['MuiListItemIcon'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiListItemText = {
styleOverrides: { root: { margin: 0 } },
} satisfies Components<Theme>['MuiListItemText'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiListItem = {
styleOverrides: { root: { gap: 'var(--ListItem-gap)' } },
} satisfies Components<Theme>['MuiListItem'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiList = {
styleOverrides: { root: { '--ListItem-gap': '16px' } },
} satisfies Components<Theme>['MuiList'];

View File

@@ -0,0 +1,17 @@
import { listItemIconClasses } from '@mui/material/ListItemIcon';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiMenuItem = {
defaultProps: { disableRipple: true },
styleOverrides: {
root: {
borderRadius: '8px',
gap: 'var(--ListItem-gap)',
paddingBlock: 'var(--MenuItem-paddingBlock, 4px)',
paddingInline: 'var(--MenuItem-paddingInline, 8px)',
[`& .${listItemIconClasses.root}`]: { minWidth: 'auto' },
},
},
} satisfies Components<Theme>['MuiMenuItem'];

View File

@@ -0,0 +1,8 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiMenu = {
defaultProps: { disableScrollLock: true },
styleOverrides: { list: { display: 'flex', flexDirection: 'column', gap: '4px', padding: '8px' } },
} satisfies Components<Theme>['MuiMenu'];

View File

@@ -0,0 +1,47 @@
import { inputBaseClasses } from '@mui/material/InputBase';
import { outlinedInputClasses } from '@mui/material/OutlinedInput';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiOutlinedInput = {
defaultProps: { notched: false },
styleOverrides: {
root: {
'--Input-focused': 0,
'--Input-focusedHighlight': 'var(--mui-palette-primary-main)',
'--Input-focusedThickness': '2px',
'--Input-borderWidth': '1px',
'--Input-borderColor': 'var(--mui-palette-OutlinedInput-border)',
'--Input-boxShadow': 'var(--mui-shadows-1)',
border: 'var(--Input-borderWidth) solid var(--Input-borderColor)',
boxShadow: 'var(--Input-boxShadow)',
'&::before': {
borderRadius: 'inherit',
bottom: 0,
boxShadow: '0 0 0 calc(var(--Input-focused) * var(--Input-focusedThickness)) var(--Input-focusedHighlight)',
content: '" "',
left: 0,
pointerEvents: 'none',
position: 'absolute',
right: 0,
top: 0,
},
'&:focus-within': { '&::before': { '--Input-focused': 1 } },
'label + &': { marginTop: '8px' },
[`&.${outlinedInputClasses.error}`]: {
'--Input-borderColor': 'var(--mui-palette-error-main)',
'--Input-focusedHighlight': 'var(--mui-palette-error-main)',
},
[`&.${outlinedInputClasses.disabled}`]: { '--Input-boxShadow': 'none' },
},
input: {
height: 'auto',
padding: 0,
[`label[data-shrink=false]+.${inputBaseClasses.formControl} &`]: {
'&::placeholder': { opacity: '1 !important' },
},
},
notchedOutline: { display: 'none' },
},
} satisfies Components<Theme>['MuiOutlinedInput'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiPaper = {
styleOverrides: { root: { backgroundImage: 'none' } },
} satisfies Components<Theme>['MuiPaper'];

View File

@@ -0,0 +1,8 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiPopover = {
defaultProps: { disableScrollLock: true, elevation: 16 },
styleOverrides: { paper: { border: '1px solid var(--mui-palette-divider)' } },
} satisfies Components<Theme>['MuiPopover'];

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
function Icon(): React.JSX.Element {
return (
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path
clipRule="evenodd"
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4Z"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
);
}
function CheckedIcon(): React.JSX.Element {
return (
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<rect fill="currentColor" height="20" rx="10" width="20" x="2" y="2" />
<rect fill="white" height="8" rx="4" width="8" x="8" y="8" />
</svg>
);
}
export const MuiRadio = {
defaultProps: { checkedIcon: <CheckedIcon />, color: 'primary', disableRipple: true, icon: <Icon /> },
styleOverrides: { root: { padding: 0 } },
} satisfies Components<Theme>['MuiRadio'];

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
import type { Components } from '@mui/material/styles';
import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown';
import type { Theme } from '../types';
function IconComponent(): React.JSX.Element {
return (
<CaretDownIcon
fontSize="1em"
style={{ flex: '0 0 auto', pointerEvents: 'none', position: 'absolute', right: '7px', top: 'calc(50% - .5em)' }}
/>
);
}
export const MuiSelect = {
defaultProps: { displayEmpty: true, IconComponent, MenuProps: { sx: { mt: '4px' } } },
styleOverrides: { select: { height: 'auto', minHeight: 'auto' } },
} satisfies Components<Theme>['MuiSelect'];

View File

@@ -0,0 +1,5 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiStack = { defaultProps: { useFlexGap: true } } satisfies Components<Theme>['MuiStack'];

View File

@@ -0,0 +1,12 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiSwitch = {
defaultProps: { color: 'primary', disableRipple: true },
styleOverrides: {
root: { marginLeft: '-12px', marginRight: '-12px' },
switchBase: { color: 'var(--mui-palette-neutral-500)' },
track: { backgroundColor: 'var(--mui-palette-neutral-400)', opacity: 1 },
},
} satisfies Components<Theme>['MuiSwitch'];

View File

@@ -0,0 +1,16 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiTab = {
defaultProps: { disableRipple: true },
styleOverrides: {
root: {
minWidth: 'auto',
paddingInline: 0,
textTransform: 'none',
'&:hover': { color: 'var(--mui-palette-text-primary)' },
'&:focus-visible': { outline: '2px solid var(--mui-palette-primary-main)' },
},
},
} satisfies Components<Theme>['MuiTab'];

View File

@@ -0,0 +1,13 @@
import type { Components } from '@mui/material/styles';
import { tableCellClasses } from '@mui/material/TableCell';
import { tableRowClasses } from '@mui/material/TableRow';
import type { Theme } from '../types';
export const MuiTableBody = {
styleOverrides: {
root: {
[`& .${tableRowClasses.root}:last-child`]: { [`& .${tableCellClasses.root}`]: { '--TableCell-borderWidth': 0 } },
},
},
} satisfies Components<Theme>['MuiTableBody'];

View File

@@ -0,0 +1,10 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiTableCell = {
styleOverrides: {
root: { borderBottom: 'var(--TableCell-borderWidth, 1px) solid var(--mui-palette-TableCell-border)' },
paddingCheckbox: { padding: '0 0 0 24px' },
},
} satisfies Components<Theme>['MuiTableCell'];

View File

@@ -0,0 +1,16 @@
import type { Components } from '@mui/material/styles';
import { tableCellClasses } from '@mui/material/TableCell';
import type { Theme } from '../types';
export const MuiTableHead = {
styleOverrides: {
root: {
[`& .${tableCellClasses.root}`]: {
backgroundColor: 'var(--mui-palette-background-level1)',
color: 'var(--mui-palette-text-secondary)',
lineHeight: 1,
},
},
},
} satisfies Components<Theme>['MuiTableHead'];

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import type { Components } from '@mui/material/styles';
import { CaretLeft as CaretLeftIcon } from '@phosphor-icons/react/dist/ssr/CaretLeft';
import { CaretRight as CaretRightIcon } from '@phosphor-icons/react/dist/ssr/CaretRight';
import type { Theme } from '../types';
function PreviousButtonIcon(): React.JSX.Element {
return <CaretLeftIcon fontSize="var(--fontSize-md)" />;
}
function NextButtonIcon(): React.JSX.Element {
return <CaretRightIcon fontSize="var(--fontSize-md)" />;
}
export const MuiTablePagination = {
defaultProps: {
slotProps: {
actions: { nextButtonIcon: { component: NextButtonIcon }, previousButtonIcon: { component: PreviousButtonIcon } },
select: { size: 'small', variant: 'outlined' },
},
},
styleOverrides: { input: { marginRight: '16px', padding: 0 } },
} satisfies Components<Theme>['MuiTablePagination'];

View File

@@ -0,0 +1,22 @@
import type { Components } from '@mui/material/styles';
import { tabClasses } from '@mui/material/Tab';
import { tabsClasses } from '@mui/material/Tabs';
import type { Theme } from '../types';
export const MuiTabs = {
styleOverrides: {
flexContainer: { [`&:not(.${tabsClasses.flexContainerVertical})`]: { gap: '24px' } },
indicator: { height: '4px', borderTopLeftRadius: '4px', borderTopRightRadius: '4px' },
vertical: {
[`& .${tabsClasses.indicator}`]: {
borderBottomRightRadius: '4px',
borderTopRightRadius: '4px',
left: 0,
right: 'auto',
width: '4px',
},
[`& .${tabClasses.root}`]: { justifyContent: 'flex-start', paddingInline: '24px' },
},
},
} satisfies Components<Theme>['MuiTabs'];

View File

@@ -0,0 +1,7 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiTimelineConnector = {
styleOverrides: { root: { backgroundColor: 'var(--mui-palette-divider)' } },
} satisfies Components<Theme>['MuiTimelineConnector'];

View File

@@ -0,0 +1,18 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiToggleButtonGroup = {
styleOverrides: {
root: {
border: '1px solid var(--mui-palette-divider)',
boxShadow: 'var(--mui-shadows-1)',
gap: '4px',
padding: '4px',
},
grouped: { border: 0, margin: 0 },
firstButton: { borderRadius: '8px' },
middleButton: { borderRadius: '8px' },
lastButton: { borderRadius: '8px' },
},
} satisfies Components<Theme>['MuiToggleButtonGroup'];

View File

@@ -0,0 +1,10 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiToggleButton = {
defaultProps: { disableRipple: true },
styleOverrides: {
root: { color: 'var(--mui-palette-text-primary)', fontSize: 'var(--icon-fontSize-md)', padding: '6px' },
},
} satisfies Components<Theme>['MuiToggleButton'];

View File

@@ -0,0 +1,8 @@
import type { Components } from '@mui/material/styles';
import type { Theme } from '../types';
export const MuiTooltip = {
defaultProps: { placement: 'top' },
styleOverrides: { tooltip: { backdropFilter: 'blur(6px)' } },
} satisfies Components<Theme>['MuiTooltip'];

View File

@@ -0,0 +1,27 @@
import { experimental_extendTheme as extendTheme } from '@mui/material/styles';
import { colorSchemes } from './color-schemes';
import { components } from './components/components';
import { shadows } from './shadows';
import type { ColorScheme, Direction, PrimaryColor, Theme } from './types';
import { typography } from './typography';
interface Config {
primaryColor: PrimaryColor;
colorScheme: ColorScheme;
direction?: Direction;
}
export function createTheme(config: Config): Theme {
const theme = extendTheme({
breakpoints: { values: { xs: 0, sm: 600, md: 900, lg: 1200, xl: 1440 } },
colorSchemes: colorSchemes({ primaryColor: config.primaryColor }),
components,
direction: config.direction,
shadows: config.colorScheme === 'dark' ? shadows.dark : shadows.light,
shape: { borderRadius: 8 },
typography,
});
return theme;
}

View File

@@ -0,0 +1,60 @@
import type { Shadows } from '@mui/material/styles/shadows';
import type { ColorScheme } from './types';
export const shadows = {
dark: [
'none',
'0px 1px 2px rgba(0, 0, 0, 0.5)',
'0px 1px 5px rgba(0, 0, 0, 0.5)',
'0px 1px 8px rgba(0, 0, 0, 0.5)',
'0px 1px 10px rgba(0, 0, 0, 0.5)',
'0px 1px 14px rgba(0, 0, 0, 0.5)',
'0px 1px 18px rgba(0, 0, 0, 0.5)',
'0px 2px 16px rgba(0, 0, 0, 0.5)',
'0px 3px 14px rgba(0, 0, 0, 0.5)',
'0px 3px 16px rgba(0, 0, 0, 0.5)',
'0px 4px 18px rgba(0, 0, 0, 0.5)',
'0px 4px 20px rgba(0, 0, 0, 0.5)',
'0px 5px 22px rgba(0, 0, 0, 0.5)',
'0px 5px 24px rgba(0, 0, 0, 0.5)',
'0px 5px 26px rgba(0, 0, 0, 0.5)',
'0px 6px 28px rgba(0, 0, 0, 0.5)',
'0px 6px 30px rgba(0, 0, 0, 0.5)',
'0px 6px 32px rgba(0, 0, 0, 0.5)',
'0px 7px 34px rgba(0, 0, 0, 0.5)',
'0px 7px 36px rgba(0, 0, 0, 0.5)',
'0px 8px 38px rgba(0, 0, 0, 0.5)',
'0px 8px 40px rgba(0, 0, 0, 0.5)',
'0px 8px 42px rgba(0, 0, 0, 0.5)',
'0px 9px 44px rgba(0, 0, 0, 0.5)',
'0px 9px 46px rgba(0, 0, 0, 0.5)',
],
light: [
'none',
'0px 1px 2px rgba(0, 0, 0, 0.08)',
'0px 1px 5px rgba(0, 0, 0, 0.08)',
'0px 1px 8px rgba(0, 0, 0, 0.08)',
'0px 1px 10px rgba(0, 0, 0, 0.08)',
'0px 1px 14px rgba(0, 0, 0, 0.08)',
'0px 1px 18px rgba(0, 0, 0, 0.08)',
'0px 2px 16px rgba(0, 0, 0, 0.08)',
'0px 3px 14px rgba(0, 0, 0, 0.08)',
'0px 3px 16px rgba(0, 0, 0, 0.08)',
'0px 4px 18px rgba(0, 0, 0, 0.08)',
'0px 4px 20px rgba(0, 0, 0, 0.08)',
'0px 5px 22px rgba(0, 0, 0, 0.08)',
'0px 5px 24px rgba(0, 0, 0, 0.08)',
'0px 5px 26px rgba(0, 0, 0, 0.08)',
'0px 6px 28px rgba(0, 0, 0, 0.08)',
'0px 6px 30px rgba(0, 0, 0, 0.08)',
'0px 6px 32px rgba(0, 0, 0, 0.08)',
'0px 7px 34px rgba(0, 0, 0, 0.08)',
'0px 7px 36px rgba(0, 0, 0, 0.08)',
'0px 8px 38px rgba(0, 0, 0, 0.08)',
'0px 8px 40px rgba(0, 0, 0, 0.08)',
'0px 8px 42px rgba(0, 0, 0, 0.08)',
'0px 9px 44px rgba(0, 0, 0, 0.08)',
'0px 9px 46px rgba(0, 0, 0, 0.08)',
],
} satisfies Record<ColorScheme, Shadows>;

View File

@@ -0,0 +1,88 @@
import type { TimelineConnectorClassKey, TimelineConnectorProps } from '@mui/lab/TimelineConnector';
import type { ComponentsOverrides, ComponentsProps, ComponentsVariants } from '@mui/material/styles';
declare module '@mui/material/styles/components' {
interface Components<Theme = unknown> {
MuiTimelineConnector: {
defaultProps?: ComponentsProps['MuiTimelineConnector'];
styleOverrides?: ComponentsOverrides<Theme>['MuiTimelineConnector'];
variants?: ComponentsVariants<Theme>['MuiTimelineConnector'];
};
}
}
declare module '@mui/material/styles/props' {
interface ComponentsPropsList {
MuiTimelineConnector: TimelineConnectorProps;
}
}
declare module '@mui/material/styles/overrides' {
interface ComponentNameToClassKey {
MuiTimelineConnector: TimelineConnectorClassKey;
}
}
declare module '@mui/material/Chip/Chip' {
interface ChipPropsVariantOverrides {
soft: true;
}
}
declare module '@mui/material/Chip/chipClasses' {
interface ChipClasses {
soft: string;
softPrimary: string;
softSecondary: string;
softSuccess: string;
softInfo: string;
softWarning: string;
softError: string;
}
}
declare module '@mui/material/styles/createPalette' {
interface PaletteRange {
50: string;
100: string;
200: string;
300: string;
400: string;
500: string;
600: string;
700: string;
800: string;
900: string;
950: string;
}
interface PaletteColor {
activated: string;
hovered: string;
selected: string;
}
interface SimplePaletteColorOptions {
activated?: string;
hovered?: string;
selected?: string;
}
interface Palette {
neutral: PaletteRange;
Backdrop: { bg: string };
OutlinedInput: { border: string };
}
interface PaletteOptions {
neutral?: PaletteRange;
Backdrop?: { bg?: string };
OutlinedInput?: { border?: string };
}
interface TypeBackground {
level1: string;
level2: string;
level3: string;
}
}

View File

@@ -0,0 +1,10 @@
import type { CssVarsTheme } from '@mui/material/styles';
import type { Theme as BaseTheme } from '@mui/material/styles/createTheme';
export type Theme = Omit<BaseTheme, 'palette'> & CssVarsTheme;
export type PrimaryColor = 'chateauGreen' | 'neonBlue' | 'royalBlue' | 'tomatoOrange';
export type Direction = 'ltr' | 'rtl';
export type ColorScheme = 'dark' | 'light';

View File

@@ -0,0 +1,25 @@
import type { TypographyOptions } from '@mui/material/styles/createTypography';
export const typography = {
fontFamily:
'"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
body1: { fontSize: '1rem', fontWeight: 400, lineHeight: 1.5 },
body2: { fontSize: '0.875rem', fontWeight: 400, lineHeight: 1.57 },
button: { fontWeight: 500 },
caption: { fontSize: '0.75rem', fontWeight: 400, lineHeight: 1.66 },
subtitle1: { fontSize: '1rem', fontWeight: 500, lineHeight: 1.57 },
subtitle2: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.57 },
overline: {
fontSize: '0.75rem',
fontWeight: 500,
letterSpacing: '0.5px',
lineHeight: 2.5,
textTransform: 'uppercase',
},
h1: { fontSize: '3.5rem', fontWeight: 500, lineHeight: 1.2 },
h2: { fontSize: '3rem', fontWeight: 500, lineHeight: 1.2 },
h3: { fontSize: '2.25rem', fontWeight: 500, lineHeight: 1.2 },
h4: { fontSize: '2rem', fontWeight: 500, lineHeight: 1.2 },
h5: { fontSize: '1.5rem', fontWeight: 500, lineHeight: 1.2 },
h6: { fontSize: '1.125rem', fontWeight: 500, lineHeight: 1.2 },
} satisfies TypographyOptions;