Separate Client Portal & Dashboard
This commit is contained in:
13
frontend/dashboard/src/theme/breakpoints.ts
Normal file
13
frontend/dashboard/src/theme/breakpoints.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const breakpoints = {
|
||||
values: {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 900,
|
||||
lg: 1200,
|
||||
xl: 1536
|
||||
}
|
||||
};
|
||||
|
||||
export default breakpoints;
|
||||
53
frontend/dashboard/src/theme/index.tsx
Normal file
53
frontend/dashboard/src/theme/index.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useMemo, ReactNode } from 'react';
|
||||
// @mui
|
||||
import { CssBaseline } from '@mui/material';
|
||||
import {
|
||||
createTheme,
|
||||
ThemeOptions,
|
||||
ThemeProvider as MUIThemeProvider,
|
||||
StyledEngineProvider,
|
||||
} from '@mui/material/styles';
|
||||
// hooks
|
||||
import useSettings from '../hooks/useSettings';
|
||||
//
|
||||
import palette from './palette';
|
||||
import typography from './typography';
|
||||
import breakpoints from './breakpoints';
|
||||
import componentsOverride from './overrides';
|
||||
import shadows, { customShadows } from './shadows';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function ThemeProvider({ children }: Props) {
|
||||
const { themeMode, themeDirection } = useSettings();
|
||||
const isLight = themeMode === 'light';
|
||||
|
||||
const themeOptions: ThemeOptions = useMemo(
|
||||
() => ({
|
||||
palette: isLight ? palette.light : palette.dark,
|
||||
typography,
|
||||
breakpoints,
|
||||
shape: { borderRadius: 8 },
|
||||
direction: themeDirection,
|
||||
shadows: isLight ? shadows.light : shadows.dark,
|
||||
customShadows: isLight ? customShadows.light : customShadows.dark,
|
||||
}),
|
||||
[isLight, themeDirection]
|
||||
);
|
||||
|
||||
const theme = createTheme(themeOptions);
|
||||
theme.components = componentsOverride(theme);
|
||||
|
||||
return (
|
||||
<StyledEngineProvider injectFirst>
|
||||
<MUIThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</MUIThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
);
|
||||
}
|
||||
39
frontend/dashboard/src/theme/overrides/Accordion.ts
Normal file
39
frontend/dashboard/src/theme/overrides/Accordion.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Accordion(theme: Theme) {
|
||||
return {
|
||||
MuiAccordion: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-expanded': {
|
||||
boxShadow: theme.customShadows.z8,
|
||||
borderRadius: theme.shape.borderRadius
|
||||
},
|
||||
'&.Mui-disabled': {
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiAccordionSummary: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingRight: theme.spacing(1),
|
||||
'&.Mui-disabled': {
|
||||
opacity: 1,
|
||||
color: theme.palette.action.disabled,
|
||||
'& .MuiTypography-root': {
|
||||
color: 'inherit'
|
||||
}
|
||||
}
|
||||
},
|
||||
expandIconWrapper: {
|
||||
color: 'inherit'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
74
frontend/dashboard/src/theme/overrides/Alert.tsx
Normal file
74
frontend/dashboard/src/theme/overrides/Alert.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
// @mui
|
||||
import { Theme } from '@mui/material/styles';
|
||||
// theme
|
||||
import { ColorSchema } from '../palette';
|
||||
//
|
||||
import { ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Alert(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
const standardStyle = (color: ColorSchema) => ({
|
||||
color: theme.palette[color][isLight ? 'darker' : 'lighter'],
|
||||
backgroundColor: theme.palette[color][isLight ? 'lighter' : 'darker'],
|
||||
'& .MuiAlert-icon': {
|
||||
color: theme.palette[color][isLight ? 'main' : 'light'],
|
||||
},
|
||||
});
|
||||
|
||||
const filledStyle = (color: ColorSchema) => ({
|
||||
color: theme.palette[color].contrastText,
|
||||
});
|
||||
|
||||
const outlinedStyle = (color: ColorSchema) => ({
|
||||
color: theme.palette[color][isLight ? 'darker' : 'lighter'],
|
||||
border: `solid 1px ${theme.palette[color][isLight ? 'light' : 'dark']}`,
|
||||
backgroundColor: theme.palette[color][isLight ? 'lighter' : 'darker'],
|
||||
'& .MuiAlert-icon': {
|
||||
color: theme.palette[color][isLight ? 'main' : 'light'],
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
MuiAlert: {
|
||||
defaultProps: {
|
||||
iconMapping: {
|
||||
info: <InfoIcon />,
|
||||
success: <SuccessIcon />,
|
||||
warning: <WarningIcon />,
|
||||
error: <ErrorIcon />,
|
||||
},
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
message: {
|
||||
'& .MuiAlertTitle-root': {
|
||||
marginBottom: theme.spacing(0.5),
|
||||
},
|
||||
},
|
||||
action: {
|
||||
'& button:not(:first-of-type)': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
|
||||
standardInfo: standardStyle('info'),
|
||||
standardSuccess: standardStyle('success'),
|
||||
standardWarning: standardStyle('warning'),
|
||||
standardError: standardStyle('error'),
|
||||
|
||||
filledInfo: filledStyle('info'),
|
||||
filledSuccess: filledStyle('success'),
|
||||
filledWarning: filledStyle('warning'),
|
||||
filledError: filledStyle('error'),
|
||||
|
||||
outlinedInfo: outlinedStyle('info'),
|
||||
outlinedSuccess: outlinedStyle('success'),
|
||||
outlinedWarning: outlinedStyle('warning'),
|
||||
outlinedError: outlinedStyle('error'),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
23
frontend/dashboard/src/theme/overrides/Autocomplete.ts
Normal file
23
frontend/dashboard/src/theme/overrides/Autocomplete.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Autocomplete(theme: Theme) {
|
||||
return {
|
||||
MuiAutocomplete: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
boxShadow: theme.customShadows.dropdown,
|
||||
},
|
||||
listbox: {
|
||||
padding: theme.spacing(0, 1),
|
||||
'& .MuiAutocomplete-option': {
|
||||
padding: theme.spacing(1),
|
||||
margin: theme.spacing(1, 0),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
29
frontend/dashboard/src/theme/overrides/Avatar.ts
Normal file
29
frontend/dashboard/src/theme/overrides/Avatar.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Avatar(theme: Theme) {
|
||||
return {
|
||||
MuiAvatar: {
|
||||
styleOverrides: {
|
||||
colorDefault: {
|
||||
color: theme.palette.text.secondary,
|
||||
backgroundColor: theme.palette.grey[400]
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiAvatarGroup: {
|
||||
styleOverrides: {
|
||||
avatar: {
|
||||
fontSize: 16,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
'&:first-of-type': {
|
||||
fontSize: 14,
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.primary.lighter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
26
frontend/dashboard/src/theme/overrides/Backdrop.ts
Normal file
26
frontend/dashboard/src/theme/overrides/Backdrop.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { alpha, Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Backdrop(theme: Theme) {
|
||||
const varLow = alpha(theme.palette.grey[900], 0.48);
|
||||
const varHigh = alpha(theme.palette.grey[900], 1);
|
||||
|
||||
return {
|
||||
MuiBackdrop: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
background: [
|
||||
`rgb(22,28,36)`,
|
||||
`-moz-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`,
|
||||
`-webkit-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`,
|
||||
`linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`
|
||||
],
|
||||
'&.MuiBackdrop-invisible': {
|
||||
background: 'transparent'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
17
frontend/dashboard/src/theme/overrides/Badge.ts
Normal file
17
frontend/dashboard/src/theme/overrides/Badge.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Badge(theme: Theme) {
|
||||
return {
|
||||
MuiBadge: {
|
||||
styleOverrides: {
|
||||
dot: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: '50%'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
16
frontend/dashboard/src/theme/overrides/Breadcrumbs.ts
Normal file
16
frontend/dashboard/src/theme/overrides/Breadcrumbs.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Breadcrumbs(theme: Theme) {
|
||||
return {
|
||||
MuiBreadcrumbs: {
|
||||
styleOverrides: {
|
||||
separator: {
|
||||
marginLeft: theme.spacing(2),
|
||||
marginRight: theme.spacing(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
58
frontend/dashboard/src/theme/overrides/Button.ts
Normal file
58
frontend/dashboard/src/theme/overrides/Button.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Button(theme: Theme) {
|
||||
return {
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:hover': {
|
||||
boxShadow: 'none',
|
||||
},
|
||||
},
|
||||
sizeLarge: {
|
||||
height: 48,
|
||||
},
|
||||
// contained
|
||||
containedInherit: {
|
||||
color: theme.palette.grey[800],
|
||||
boxShadow: theme.customShadows.z8,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.grey[400],
|
||||
},
|
||||
},
|
||||
containedPrimary: {
|
||||
boxShadow: theme.customShadows.primary,
|
||||
},
|
||||
containedSecondary: {
|
||||
boxShadow: theme.customShadows.secondary,
|
||||
},
|
||||
containedInfo: {
|
||||
boxShadow: theme.customShadows.info,
|
||||
},
|
||||
containedSuccess: {
|
||||
boxShadow: theme.customShadows.success,
|
||||
},
|
||||
containedWarning: {
|
||||
boxShadow: theme.customShadows.warning,
|
||||
},
|
||||
containedError: {
|
||||
boxShadow: theme.customShadows.error,
|
||||
},
|
||||
// outlined
|
||||
outlinedInherit: {
|
||||
border: `1px solid ${theme.palette.grey[500_32]}`,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
textInherit: {
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
51
frontend/dashboard/src/theme/overrides/ButtonGroup.ts
Normal file
51
frontend/dashboard/src/theme/overrides/ButtonGroup.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function ButtonGroup(theme: Theme) {
|
||||
const styleContained = (
|
||||
color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'
|
||||
) => ({
|
||||
props: { variant: 'contained', color },
|
||||
style: { boxShadow: theme.customShadows[color] }
|
||||
});
|
||||
|
||||
return {
|
||||
MuiButtonGroup: {
|
||||
variants: [
|
||||
{
|
||||
props: { variant: 'contained', color: 'inherit' },
|
||||
style: { boxShadow: theme.customShadows.z8 }
|
||||
},
|
||||
styleContained('primary'),
|
||||
styleContained('secondary'),
|
||||
styleContained('info'),
|
||||
styleContained('success'),
|
||||
styleContained('warning'),
|
||||
styleContained('error'),
|
||||
|
||||
{
|
||||
props: { disabled: true },
|
||||
style: {
|
||||
boxShadow: 'none',
|
||||
'& .MuiButtonGroup-grouped.Mui-disabled': {
|
||||
color: theme.palette.action.disabled,
|
||||
borderColor: `${theme.palette.action.disabledBackground} !important`,
|
||||
'&.MuiButton-contained': {
|
||||
backgroundColor: theme.palette.action.disabledBackground
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:hover': {
|
||||
boxShadow: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
36
frontend/dashboard/src/theme/overrides/Card.ts
Normal file
36
frontend/dashboard/src/theme/overrides/Card.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Card(theme: Theme) {
|
||||
return {
|
||||
MuiCard: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
position: 'relative',
|
||||
boxShadow: theme.customShadows.card,
|
||||
borderRadius: Number(theme.shape.borderRadius) * 2,
|
||||
zIndex: 0, // Fix Safari overflow: hidden with border radius
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
defaultProps: {
|
||||
titleTypographyProps: { variant: 'h6' },
|
||||
subheaderTypographyProps: { variant: 'body2', marginTop: theme.spacing(0.5) },
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(3, 3, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
40
frontend/dashboard/src/theme/overrides/Checkbox.tsx
Normal file
40
frontend/dashboard/src/theme/overrides/Checkbox.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
import { CheckboxIcon, CheckboxCheckedIcon, CheckboxIndeterminateIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Checkbox(theme: Theme) {
|
||||
return {
|
||||
MuiCheckbox: {
|
||||
defaultProps: {
|
||||
icon: <CheckboxIcon />,
|
||||
checkedIcon: <CheckboxCheckedIcon />,
|
||||
indeterminateIcon: <CheckboxIndeterminateIcon />,
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(1),
|
||||
'&.Mui-checked.Mui-disabled, &.Mui-disabled': {
|
||||
color: theme.palette.action.disabled,
|
||||
},
|
||||
'& .MuiSvgIcon-fontSizeMedium': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
},
|
||||
'& .MuiSvgIcon-fontSizeSmall': {
|
||||
width: 20,
|
||||
height: 20,
|
||||
},
|
||||
svg: {
|
||||
fontSize: 24,
|
||||
'&[font-size=small]': {
|
||||
fontSize: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
49
frontend/dashboard/src/theme/overrides/Chip.tsx
Normal file
49
frontend/dashboard/src/theme/overrides/Chip.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
import { CloseIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Chip(theme: Theme) {
|
||||
return {
|
||||
MuiChip: {
|
||||
defaultProps: {
|
||||
deleteIcon: <CloseIcon />,
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
colorDefault: {
|
||||
'& .MuiChip-avatarMedium, .MuiChip-avatarSmall': {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
outlined: {
|
||||
borderColor: theme.palette.grey[500_32],
|
||||
'&.MuiChip-colorPrimary': {
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
'&.MuiChip-colorSecondary': {
|
||||
borderColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
//
|
||||
avatarColorInfo: {
|
||||
color: theme.palette.info.contrastText,
|
||||
backgroundColor: theme.palette.info.dark,
|
||||
},
|
||||
avatarColorSuccess: {
|
||||
color: theme.palette.success.contrastText,
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
},
|
||||
avatarColorWarning: {
|
||||
color: theme.palette.warning.contrastText,
|
||||
backgroundColor: theme.palette.warning.dark,
|
||||
},
|
||||
avatarColorError: {
|
||||
color: theme.palette.error.contrastText,
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
29
frontend/dashboard/src/theme/overrides/ControlLabel.ts
Normal file
29
frontend/dashboard/src/theme/overrides/ControlLabel.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function ControlLabel(theme: Theme) {
|
||||
return {
|
||||
MuiFormControlLabel: {
|
||||
styleOverrides: {
|
||||
label: {
|
||||
...theme.typography.body2
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiFormHelperText: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
marginTop: theme.spacing(1)
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiFormLabel: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
47
frontend/dashboard/src/theme/overrides/CssBaseline.ts
Normal file
47
frontend/dashboard/src/theme/overrides/CssBaseline.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function CssBaseline(theme: Theme) {
|
||||
return {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
'*': {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
html: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
WebkitOverflowScrolling: 'touch',
|
||||
},
|
||||
body: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
'#root': {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
input: {
|
||||
'&[type=number]': {
|
||||
MozAppearance: 'textfield',
|
||||
'&::-webkit-outer-spin-button': {
|
||||
margin: 0,
|
||||
WebkitAppearance: 'none',
|
||||
},
|
||||
'&::-webkit-inner-spin-button': {
|
||||
margin: 0,
|
||||
WebkitAppearance: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
img: {
|
||||
display: 'block',
|
||||
maxWidth: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
122
frontend/dashboard/src/theme/overrides/CustomIcons.tsx
Normal file
122
frontend/dashboard/src/theme/overrides/CustomIcons.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
// @mui
|
||||
import { SvgIcon, SvgIconProps } from '@mui/material';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// CloseIcon
|
||||
export function CloseIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 C17.5228475,22 22,17.5228475 22,12 C22,9.3478351 20.9464316,6.80429597 19.0710678,4.92893219 C17.195704,3.0535684 14.6521649,2 12,2 Z M14.71,13.29 C14.8993127,13.4777666 15.0057983,13.7333625 15.0057983,14 C15.0057983,14.2666375 14.8993127,14.5222334 14.71,14.71 C14.5222334,14.8993127 14.2666375,15.0057983 14,15.0057983 C13.7333625,15.0057983 13.4777666,14.8993127 13.29,14.71 L12,13.41 L10.71,14.71 C10.5222334,14.8993127 10.2666375,15.0057983 10,15.0057983 C9.73336246,15.0057983 9.4777666,14.8993127 9.29,14.71 C9.10068735,14.5222334 8.99420168,14.2666375 8.99420168,14 C8.99420168,13.7333625 9.10068735,13.4777666 9.29,13.29 L10.59,12 L9.29,10.71 C8.89787783,10.3178778 8.89787783,9.68212217 9.29,9.29 C9.68212217,8.89787783 10.3178778,8.89787783 10.71,9.29 L12,10.59 L13.29,9.29 C13.6821222,8.89787783 14.3178778,8.89787783 14.71,9.29 C15.1021222,9.68212217 15.1021222,10.3178778 14.71,10.71 L13.41,12 L14.71,13.29 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
// StarIcon
|
||||
export function StarIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M17.56,21 C17.4000767,21.0006435 17.2423316,20.9629218 17.1,20.89 L12,18.22 L6.9,20.89 C6.56213339,21.067663 6.15259539,21.0374771 5.8444287,20.8121966 C5.53626201,20.5869161 5.38323252,20.2058459 5.45,19.83 L6.45,14.2 L2.33,10.2 C2.06805623,9.93860108 1.9718844,9.55391377 2.08,9.2 C2.19824414,8.83742187 2.51242293,8.57366684 2.89,8.52 L8.59,7.69 L11.1,2.56 C11.2670864,2.21500967 11.6166774,1.99588989 12,1.99588989 C12.3833226,1.99588989 12.7329136,2.21500967 12.9,2.56 L15.44,7.68 L21.14,8.51 C21.5175771,8.56366684 21.8317559,8.82742187 21.95,9.19 C22.0581156,9.54391377 21.9619438,9.92860108 21.7,10.19 L17.58,14.19 L18.58,19.82 C18.652893,20.2027971 18.4967826,20.5930731 18.18,20.82 C17.9989179,20.9468967 17.7808835,21.010197 17.56,21 L17.56,21 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
// Using for Alert
|
||||
export function InfoIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 C17.5228475,22 22,17.5228475 22,12 C22,9.3478351 20.9464316,6.80429597 19.0710678,4.92893219 C17.195704,3.0535684 14.6521649,2 12,2 Z M13,16 C13,16.5522847 12.5522847,17 12,17 C11.4477153,17 11,16.5522847 11,16 L11,11 C11,10.4477153 11.4477153,10 12,10 C12.5522847,10 13,10.4477153 13,11 L13,16 Z M12,9 C11.4477153,9 11,8.55228475 11,8 C11,7.44771525 11.4477153,7 12,7 C12.5522847,7 13,7.44771525 13,8 C13,8.55228475 12.5522847,9 12,9 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function WarningIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M22.56,16.3 L14.89,3.58 C14.2597186,2.59400001 13.1702353,1.99737652 12,1.99737652 C10.8297647,1.99737652 9.74028139,2.59400001 9.11,3.58 L1.44,16.3 C0.888546003,17.2192471 0.869485343,18.3628867 1.39,19.3 C1.99197363,20.3551378 3.11522982,21.0046397 4.33,21 L19.67,21 C20.8765042,21.0128744 21.9978314,20.3797441 22.61,19.34 C23.146086,18.3926382 23.1269508,17.2292197 22.56,16.3 L22.56,16.3 Z M12,17 C11.4477153,17 11,16.5522847 11,16 C11,15.4477153 11.4477153,15 12,15 C12.5522847,15 13,15.4477153 13,16 C13,16.5522847 12.5522847,17 12,17 Z M13,13 C13,13.5522847 12.5522847,14 12,14 C11.4477153,14 11,13.5522847 11,13 L11,9 C11,8.44771525 11.4477153,8 12,8 C12.5522847,8 13,8.44771525 13,9 L13,13 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function SuccessIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 C17.5228475,22 22,17.5228475 22,12 C22,9.3478351 20.9464316,6.80429597 19.0710678,4.92893219 C17.195704,3.0535684 14.6521649,2 12,2 Z M16.3,9.61 L11.73,15.61 C11.5412074,15.855247 11.2494966,15.9992561 10.94,16.0000145 C10.6322197,16.001658 10.3408221,15.861492 10.15,15.62 L7.71,12.51 C7.49028166,12.2277602 7.43782669,11.8497415 7.57239438,11.5183399 C7.70696206,11.1869384 8.00810836,10.9525017 8.36239438,10.9033399 C8.7166804,10.8541782 9.07028166,10.9977602 9.29,11.28 L10.92,13.36 L14.7,8.36 C14.917932,8.07418751 15.2717886,7.92635122 15.6282755,7.97217964 C15.9847624,8.01800806 16.2897207,8.25053875 16.4282755,8.58217966 C16.5668304,8.91382056 16.517932,9.29418753 16.3,9.58 L16.3,9.61 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 C17.5228475,22 22,17.5228475 22,12 C22,9.3478351 20.9464316,6.80429597 19.0710678,4.92893219 C17.195704,3.0535684 14.6521649,2 12,2 Z M12,17 C11.4477153,17 11,16.5522847 11,16 C11,15.4477153 11.4477153,15 12,15 C12.5522847,15 13,15.4477153 13,16 C13,16.5522847 12.5522847,17 12,17 Z M13,13 C13,13.5522847 12.5522847,14 12,14 C11.4477153,14 11,13.5522847 11,13 L11,8 C11,7.44771525 11.4477153,7 12,7 C12.5522847,7 13,7.44771525 13,8 L13,13 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
// Using for Checkbox
|
||||
export function CheckboxIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M17 3a4 4 0 014 4v10a4 4 0 01-4 4H7a4 4 0 01-4-4V7a4 4 0 014-4h10zm0 2H7a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function CheckboxCheckedIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M17 3a4 4 0 014 4v10a4 4 0 01-4 4H7a4 4 0 01-4-4V7a4 4 0 014-4h10zm-1.372 4.972a1.006 1.006 0 00-.928.388l-3.78 5-1.63-2.08a1.001 1.001 0 00-1.58 1.23l2.44 3.11a1 1 0 001.58-.01l4.57-6v-.03a1.006 1.006 0 00-.672-1.608z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function CheckboxIndeterminateIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M17 3a4 4 0 014 4v10a4 4 0 01-4 4H7a4 4 0 01-4-4V7a4 4 0 014-4h10zm-1.75 8h-6.5a.75.75 0 00-.75.75v.5c0 .414.336.75.75.75h6.5a.75.75 0 00.75-.75v-.5a.75.75 0 00-.75-.75z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
// Using for Select Input
|
||||
export function InputSelectIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon
|
||||
{...props}
|
||||
sx={{
|
||||
right: 12,
|
||||
fontSize: 16,
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
<path d="M12,16 C11.7663478,16.0004565 11.5399121,15.9190812 11.36,15.77 L5.36,10.77 C4.93474074,10.4165378 4.87653776,9.78525926 5.23,9.36 C5.58346224,8.93474074 6.21474074,8.87653776 6.64,9.23 L12,13.71 L17.36,9.39 C17.5665934,9.2222295 17.8315409,9.14373108 18.0961825,9.17188444 C18.3608241,9.2000378 18.6033268,9.33252029 18.77,9.54 C18.9551341,9.74785947 19.0452548,10.0234772 19.0186853,10.3005589 C18.9921158,10.5776405 18.8512608,10.8311099 18.63,11 L12.63,15.83 C12.444916,15.955516 12.2231011,16.0153708 12,16 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
// Using for TreeView
|
||||
export function TreeViewCollapseIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M18,3 C19.6568542,3 21,4.34314575 21,6 L21,6 L21,18 C21,19.6568542 19.6568542,21 18,21 L18,21 L6,21 C4.34314575,21 3,19.6568542 3,18 L3,18 L3,6 C3,4.34314575 4.34314575,3 6,3 L6,3 Z M18,5 L6,5 C5.44771525,5 5,5.44771525 5,6 L5,6 L5,18 C5,18.5522847 5.44771525,19 6,19 L6,19 L18,19 C18.5522847,19 19,18.5522847 19,18 L19,18 L19,6 C19,5.44771525 18.5522847,5 18,5 L18,5 Z M12,8 C12.5522847,8 13,8.44771525 13,9 L13,9 L13,11 L15,11 C15.5522847,11 16,11.4477153 16,12 C16,12.5522847 15.5522847,13 15,13 L15,13 L13,13 L13,15 C13,15.5522847 12.5522847,16 12,16 C11.4477153,16 11,15.5522847 11,15 L11,15 L11,13 L9,13 C8.44771525,13 8,12.5522847 8,12 C8,11.4477153 8.44771525,11 9,11 L9,11 L11,11 L11,9 C11,8.44771525 11.4477153,8 12,8 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function TreeViewExpandIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M18,3 C19.6568542,3 21,4.34314575 21,6 L21,6 L21,18 C21,19.6568542 19.6568542,21 18,21 L18,21 L6,21 C4.34314575,21 3,19.6568542 3,18 L3,18 L3,6 C3,4.34314575 4.34314575,3 6,3 L6,3 Z M18,5 L6,5 C5.44771525,5 5,5.44771525 5,6 L5,6 L5,18 C5,18.5522847 5.44771525,19 6,19 L6,19 L18,19 C18.5522847,19 19,18.5522847 19,18 L19,18 L19,6 C19,5.44771525 18.5522847,5 18,5 L18,5 Z M15,11 C15.5522847,11 16,11.4477153 16,12 C16,12.5522847 15.5522847,13 15,13 L15,13 L9,13 C8.44771525,13 8,12.5522847 8,12 C8,11.4477153 8.44771525,11 9,11 L9,11 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function TreeViewEndIcon(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="M18,3 C19.6568542,3 21,4.34314575 21,6 L21,6 L21,18 C21,19.6568542 19.6568542,21 18,21 L18,21 L6,21 C4.34314575,21 3,19.6568542 3,18 L3,18 L3,6 C3,4.34314575 4.34314575,3 6,3 L6,3 Z M18,5 L6,5 C5.44771525,5 5,5.44771525 5,6 L5,6 L5,18 C5,18.5522847 5.44771525,19 6,19 L6,19 L18,19 C18.5522847,19 19,18.5522847 19,18 L19,18 L19,6 C19,5.44771525 18.5522847,5 18,5 L18,5 Z M14,8.99420168 C14.2666375,8.99420168 14.5222334,9.10068735 14.71,9.29 C14.8993127,9.4777666 15.0057983,9.73336246 15.0057983,10 C15.0057983,10.2666375 14.8993127,10.5222334 14.71,10.71 L14.71,10.71 L13.41,12 L14.71,13.29 C14.8993127,13.4777666 15.0057983,13.7333625 15.0057983,14 C15.0057983,14.2666375 14.8993127,14.5222334 14.71,14.71 C14.5222334,14.8993127 14.2666375,15.0057983 14,15.0057983 C13.7333625,15.0057983 13.4777666,14.8993127 13.29,14.71 L13.29,14.71 L12,13.41 L10.71,14.71 C10.5222334,14.8993127 10.2666375,15.0057983 10,15.0057983 C9.73336246,15.0057983 9.4777666,14.8993127 9.29,14.71 C9.10068735,14.5222334 8.99420168,14.2666375 8.99420168,14 C8.99420168,13.7333625 9.10068735,13.4777666 9.29,13.29 L9.29,13.29 L10.59,12 L9.29,10.71 C8.89787783,10.3178778 8.89787783,9.68212217 9.29,9.29 C9.68212217,8.89787783 10.3178778,8.89787783 10.71,9.29 L10.71,9.29 L12,10.59 L13.29,9.29 C13.4777666,9.10068735 13.7333625,8.99420168 14,8.99420168 Z" />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
101
frontend/dashboard/src/theme/overrides/DataGrid.ts
Normal file
101
frontend/dashboard/src/theme/overrides/DataGrid.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function DataGrid(theme: Theme) {
|
||||
return {
|
||||
MuiDataGrid: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 0,
|
||||
border: `1px solid transparent`,
|
||||
'& .MuiTablePagination-root': {
|
||||
borderTop: 0,
|
||||
},
|
||||
'& .MuiDataGrid-toolbarContainer': {
|
||||
padding: theme.spacing(2),
|
||||
backgroundColor: theme.palette.background.neutral,
|
||||
'& .MuiButton-root': {
|
||||
marginRight: theme.spacing(1.5),
|
||||
color: theme.palette.text.primary,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .MuiDataGrid-cell, .MuiDataGrid-columnsContainer': {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
'& .MuiDataGrid-columnSeparator': {
|
||||
color: theme.palette.divider,
|
||||
},
|
||||
'& .MuiDataGrid-columnHeader[data-field="__check__"]': {
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiGridMenu: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiDataGrid-gridMenuList': {
|
||||
boxShadow: theme.customShadows.z20,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
'& .MuiMenuItem-root': {
|
||||
...theme.typography.body2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiGridFilterForm: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(1.5, 0),
|
||||
'& .MuiFormControl-root': {
|
||||
margin: theme.spacing(0, 0.5),
|
||||
},
|
||||
'& .MuiInput-root': {
|
||||
marginTop: theme.spacing(3),
|
||||
'&::before, &::after': {
|
||||
display: 'none',
|
||||
},
|
||||
'& .MuiNativeSelect-select, .MuiInput-input': {
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(0.75, 1),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.neutral,
|
||||
},
|
||||
'& .MuiSvgIcon-root': {
|
||||
right: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiGridPanelFooter: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(2),
|
||||
justifyContent: 'flex-end',
|
||||
'& .MuiButton-root': {
|
||||
'&:first-of-type': {
|
||||
marginRight: theme.spacing(1.5),
|
||||
color: theme.palette.text.primary,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
'&:last-of-type': {
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
60
frontend/dashboard/src/theme/overrides/Dialog.ts
Normal file
60
frontend/dashboard/src/theme/overrides/Dialog.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Dialog(theme: Theme) {
|
||||
return {
|
||||
MuiDialog: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
boxShadow: theme.customShadows.dialog,
|
||||
'&.MuiPaper-rounded': {
|
||||
borderRadius: Number(theme.shape.borderRadius) * 2,
|
||||
},
|
||||
'&.MuiDialog-paperFullScreen': {
|
||||
borderRadius: 0,
|
||||
},
|
||||
'&.MuiDialog-paper .MuiDialogActions-root': {
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
'@media (max-width: 600px)': {
|
||||
margin: theme.spacing(2),
|
||||
},
|
||||
'@media (max-width: 663.95px)': {
|
||||
'&.MuiDialog-paperWidthSm.MuiDialog-paperScrollBody': {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
paperFullWidth: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(3, 3, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderTop: 0,
|
||||
borderBottom: 0,
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& > :not(:first-of-type)': {
|
||||
marginLeft: theme.spacing(1.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
30
frontend/dashboard/src/theme/overrides/Drawer.ts
Normal file
30
frontend/dashboard/src/theme/overrides/Drawer.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { alpha, Theme } from '@mui/material';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Drawer(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
return {
|
||||
MuiDrawer: {
|
||||
styleOverrides: {
|
||||
modal: {
|
||||
'&[role="presentation"]': {
|
||||
'& .MuiDrawer-paperAnchorLeft': {
|
||||
boxShadow: `8px 24px 24px 12px ${alpha(
|
||||
theme.palette.grey[900],
|
||||
isLight ? 0.16 : 0.48
|
||||
)}`
|
||||
},
|
||||
'& .MuiDrawer-paperAnchorRight': {
|
||||
boxShadow: `-8px 24px 24px 12px ${alpha(
|
||||
theme.palette.grey[900],
|
||||
isLight ? 0.16 : 0.48
|
||||
)}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
40
frontend/dashboard/src/theme/overrides/Fab.ts
Normal file
40
frontend/dashboard/src/theme/overrides/Fab.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Fab(theme: Theme) {
|
||||
return {
|
||||
MuiFab: {
|
||||
defaultProps: {
|
||||
color: 'primary'
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: theme.customShadows.z8,
|
||||
'&:hover': {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: theme.palette.grey[400]
|
||||
}
|
||||
},
|
||||
primary: {
|
||||
boxShadow: theme.customShadows.primary,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.dark
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
boxShadow: theme.customShadows.secondary,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.secondary.dark
|
||||
}
|
||||
},
|
||||
extended: {
|
||||
'& svg': {
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
67
frontend/dashboard/src/theme/overrides/Input.ts
Normal file
67
frontend/dashboard/src/theme/overrides/Input.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Input(theme: Theme) {
|
||||
return {
|
||||
MuiInputBase: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-disabled': {
|
||||
'& svg': { color: theme.palette.text.disabled },
|
||||
},
|
||||
},
|
||||
input: {
|
||||
'&::placeholder': {
|
||||
opacity: 1,
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiInput: {
|
||||
styleOverrides: {
|
||||
underline: {
|
||||
'&:before': {
|
||||
borderBottomColor: theme.palette.grey[500_56],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiFilledInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: theme.palette.grey[500_12],
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.grey[500_16],
|
||||
},
|
||||
'&.Mui-focused': {
|
||||
backgroundColor: theme.palette.action.focus,
|
||||
},
|
||||
'&.Mui-disabled': {
|
||||
backgroundColor: theme.palette.action.disabledBackground,
|
||||
},
|
||||
},
|
||||
underline: {
|
||||
'&:before': {
|
||||
borderBottomColor: theme.palette.grey[500_56],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: theme.palette.grey[500_32],
|
||||
},
|
||||
'&.Mui-disabled': {
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: theme.palette.action.disabledBackground,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
13
frontend/dashboard/src/theme/overrides/Link.ts
Normal file
13
frontend/dashboard/src/theme/overrides/Link.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Link(theme: Theme) {
|
||||
return {
|
||||
MuiLink: {
|
||||
defaultProps: {
|
||||
underline: 'hover',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
37
frontend/dashboard/src/theme/overrides/List.ts
Normal file
37
frontend/dashboard/src/theme/overrides/List.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function List(theme: Theme) {
|
||||
return {
|
||||
MuiListItemIcon: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: 'inherit',
|
||||
minWidth: 'auto',
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemAvatar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minWidth: 'auto',
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemText: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
},
|
||||
multiline: {
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
22
frontend/dashboard/src/theme/overrides/LoadingButton.ts
Normal file
22
frontend/dashboard/src/theme/overrides/LoadingButton.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function LoadingButton(theme: Theme) {
|
||||
return {
|
||||
MuiLoadingButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.MuiButton-text': {
|
||||
'& .MuiLoadingButton-startIconPendingStart': {
|
||||
marginLeft: 0
|
||||
},
|
||||
'& .MuiLoadingButton-endIconPendingEnd': {
|
||||
marginRight: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
20
frontend/dashboard/src/theme/overrides/Menu.ts
Normal file
20
frontend/dashboard/src/theme/overrides/Menu.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Menu(theme: Theme) {
|
||||
return {
|
||||
MuiMenuItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: theme.palette.action.selected,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
35
frontend/dashboard/src/theme/overrides/Pagination.ts
Normal file
35
frontend/dashboard/src/theme/overrides/Pagination.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { alpha, Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Pagination(theme: Theme) {
|
||||
return {
|
||||
MuiPaginationItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-selected': {
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
},
|
||||
},
|
||||
textPrimary: {
|
||||
'&.Mui-selected': {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: alpha(theme.palette.primary.main, 0.08),
|
||||
'&:hover, &.Mui-focusVisible': {
|
||||
backgroundColor: `${alpha(theme.palette.primary.main, 0.24)} !important`,
|
||||
},
|
||||
},
|
||||
},
|
||||
outlined: {
|
||||
border: `1px solid ${theme.palette.grey[500_32]}`,
|
||||
},
|
||||
outlinedPrimary: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: alpha(theme.palette.primary.main, 0.08),
|
||||
border: `1px solid ${alpha(theme.palette.primary.main, 0.24)}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
26
frontend/dashboard/src/theme/overrides/Paper.ts
Normal file
26
frontend/dashboard/src/theme/overrides/Paper.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Paper(theme: Theme) {
|
||||
return {
|
||||
MuiPaper: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
|
||||
variants: [
|
||||
{
|
||||
props: { variant: 'outlined' },
|
||||
style: { borderColor: theme.palette.grey[500_12] },
|
||||
},
|
||||
],
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
16
frontend/dashboard/src/theme/overrides/Popover.ts
Normal file
16
frontend/dashboard/src/theme/overrides/Popover.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Popover(theme: Theme) {
|
||||
return {
|
||||
MuiPopover: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
boxShadow: theme.customShadows.dropdown,
|
||||
borderRadius: Number(theme.shape.borderRadius) * 1.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
27
frontend/dashboard/src/theme/overrides/Progress.ts
Normal file
27
frontend/dashboard/src/theme/overrides/Progress.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Progress(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
return {
|
||||
MuiLinearProgress: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
bar: {
|
||||
borderRadius: 4
|
||||
},
|
||||
colorPrimary: {
|
||||
backgroundColor: theme.palette.primary[isLight ? 'lighter' : 'darker']
|
||||
},
|
||||
buffer: {
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
21
frontend/dashboard/src/theme/overrides/Radio.ts
Normal file
21
frontend/dashboard/src/theme/overrides/Radio.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Radio(theme: Theme) {
|
||||
return {
|
||||
MuiRadio: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(1),
|
||||
svg: {
|
||||
fontSize: 24,
|
||||
'&[font-size=small]': {
|
||||
fontSize: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
30
frontend/dashboard/src/theme/overrides/Rating.tsx
Normal file
30
frontend/dashboard/src/theme/overrides/Rating.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
import { StarIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const ICON_SMALL = { width: 20, height: 20 };
|
||||
const ICON_LARGE = { width: 28, height: 28 };
|
||||
|
||||
export default function Rating(theme: Theme) {
|
||||
return {
|
||||
MuiRating: {
|
||||
defaultProps: {
|
||||
emptyIcon: <StarIcon />,
|
||||
icon: <StarIcon />,
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-disabled': {
|
||||
opacity: 0.48,
|
||||
},
|
||||
},
|
||||
iconEmpty: { color: theme.palette.grey[500_48] },
|
||||
sizeSmall: { '& svg': { ...ICON_SMALL } },
|
||||
sizeLarge: { '& svg': { ...ICON_LARGE } },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
16
frontend/dashboard/src/theme/overrides/Select.tsx
Normal file
16
frontend/dashboard/src/theme/overrides/Select.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
//
|
||||
import { InputSelectIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Select(theme: Theme) {
|
||||
return {
|
||||
MuiSelect: {
|
||||
defaultProps: {
|
||||
IconComponent: InputSelectIcon,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
19
frontend/dashboard/src/theme/overrides/Skeleton.ts
Normal file
19
frontend/dashboard/src/theme/overrides/Skeleton.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Skeleton(theme: Theme) {
|
||||
return {
|
||||
MuiSkeleton: {
|
||||
defaultProps: {
|
||||
animation: 'wave'
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: theme.palette.background.neutral
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
31
frontend/dashboard/src/theme/overrides/Slider.ts
Normal file
31
frontend/dashboard/src/theme/overrides/Slider.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Slider(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
return {
|
||||
MuiSlider: {
|
||||
defaultProps: {
|
||||
size: 'small'
|
||||
},
|
||||
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-disabled': {
|
||||
color: theme.palette.action.disabled
|
||||
}
|
||||
},
|
||||
markLabel: {
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.disabled
|
||||
},
|
||||
valueLabel: {
|
||||
borderRadius: 8,
|
||||
backgroundColor: theme.palette.grey[isLight ? 800 : 700]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
15
frontend/dashboard/src/theme/overrides/Stepper.ts
Normal file
15
frontend/dashboard/src/theme/overrides/Stepper.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Stepper(theme: Theme) {
|
||||
return {
|
||||
MuiStepConnector: {
|
||||
styleOverrides: {
|
||||
line: {
|
||||
borderColor: theme.palette.divider
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
22
frontend/dashboard/src/theme/overrides/SvgIcon.ts
Normal file
22
frontend/dashboard/src/theme/overrides/SvgIcon.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function SvgIcon(theme: Theme) {
|
||||
return {
|
||||
MuiSvgIcon: {
|
||||
styleOverrides: {
|
||||
fontSizeSmall: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
fontSize: 'inherit'
|
||||
},
|
||||
fontSizeLarge: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
fontSize: 'inherit'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
35
frontend/dashboard/src/theme/overrides/Switch.ts
Normal file
35
frontend/dashboard/src/theme/overrides/Switch.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Switch(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
return {
|
||||
MuiSwitch: {
|
||||
styleOverrides: {
|
||||
thumb: {
|
||||
boxShadow: theme.customShadows.z1
|
||||
},
|
||||
track: {
|
||||
opacity: 1,
|
||||
backgroundColor: theme.palette.grey[500]
|
||||
},
|
||||
switchBase: {
|
||||
left: 0,
|
||||
right: 'auto',
|
||||
'&:not(:.Mui-checked)': {
|
||||
color: theme.palette.grey[isLight ? 100 : 300]
|
||||
},
|
||||
'&.Mui-checked.Mui-disabled, &.Mui-disabled': {
|
||||
color: theme.palette.grey[isLight ? 400 : 600]
|
||||
},
|
||||
'&.Mui-disabled+.MuiSwitch-track': {
|
||||
opacity: 1,
|
||||
backgroundColor: `${theme.palette.action.disabledBackground} !important`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
75
frontend/dashboard/src/theme/overrides/Table.ts
Normal file
75
frontend/dashboard/src/theme/overrides/Table.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Table(theme: Theme) {
|
||||
return {
|
||||
MuiTableRow: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: theme.palette.action.selected,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
head: {
|
||||
color: theme.palette.text.secondary,
|
||||
backgroundColor: theme.palette.background.neutral,
|
||||
'&:first-of-type': {
|
||||
paddingLeft: theme.spacing(3),
|
||||
borderTopLeftRadius: theme.shape.borderRadius,
|
||||
borderBottomLeftRadius: theme.shape.borderRadius,
|
||||
boxShadow: `inset 8px 0 0 ${theme.palette.background.paper}`,
|
||||
},
|
||||
'&:last-of-type': {
|
||||
paddingRight: theme.spacing(3),
|
||||
borderTopRightRadius: theme.shape.borderRadius,
|
||||
borderBottomRightRadius: theme.shape.borderRadius,
|
||||
boxShadow: `inset -8px 0 0 ${theme.palette.background.paper}`,
|
||||
},
|
||||
},
|
||||
stickyHeader: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
backgroundImage: `linear-gradient(to bottom, ${theme.palette.background.neutral} 0%, ${theme.palette.background.neutral} 100%)`,
|
||||
},
|
||||
body: {
|
||||
'&:first-of-type': {
|
||||
paddingLeft: theme.spacing(3),
|
||||
},
|
||||
'&:last-of-type': {
|
||||
paddingRight: theme.spacing(3),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTablePagination: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderTop: `solid 1px ${theme.palette.divider}`,
|
||||
},
|
||||
toolbar: {
|
||||
height: 64,
|
||||
},
|
||||
select: {
|
||||
'&:focus': {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
},
|
||||
selectIcon: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
marginTop: -4,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
58
frontend/dashboard/src/theme/overrides/Tabs.ts
Normal file
58
frontend/dashboard/src/theme/overrides/Tabs.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Tabs(theme: Theme) {
|
||||
return {
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 0,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
borderTopLeftRadius: theme.shape.borderRadius,
|
||||
borderTopRightRadius: theme.shape.borderRadius,
|
||||
'&.Mui-selected': {
|
||||
color: theme.palette.text.primary
|
||||
},
|
||||
'&:not(:last-of-type)': {
|
||||
marginRight: theme.spacing(5)
|
||||
},
|
||||
'@media (min-width: 600px)': {
|
||||
minWidth: 48
|
||||
}
|
||||
},
|
||||
labelIcon: {
|
||||
minHeight: 48,
|
||||
flexDirection: 'row',
|
||||
'& > *:first-of-type': {
|
||||
marginBottom: 0,
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
},
|
||||
wrapper: {
|
||||
flexDirection: 'row',
|
||||
whiteSpace: 'nowrap'
|
||||
},
|
||||
textColorInherit: {
|
||||
opacity: 1,
|
||||
color: theme.palette.text.secondary
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTabPanel: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTabScrollButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
width: 48,
|
||||
borderRadius: '50%'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
23
frontend/dashboard/src/theme/overrides/Timeline.ts
Normal file
23
frontend/dashboard/src/theme/overrides/Timeline.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Timeline(theme: Theme) {
|
||||
return {
|
||||
MuiTimelineDot: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
MuiTimelineConnector: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: theme.palette.divider
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
55
frontend/dashboard/src/theme/overrides/ToggleButton.ts
Normal file
55
frontend/dashboard/src/theme/overrides/ToggleButton.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Theme, alpha } from '@mui/material/styles';
|
||||
//
|
||||
import { ColorSchema } from '../palette';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function ToggleButton(theme: Theme) {
|
||||
const style = (color: ColorSchema) => ({
|
||||
props: { color },
|
||||
style: {
|
||||
'&:hover': {
|
||||
borderColor: alpha(theme.palette[color].main, 0.48),
|
||||
backgroundColor: alpha(theme.palette[color].main, theme.palette.action.hoverOpacity),
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
borderColor: alpha(theme.palette[color].main, 0.48),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
MuiToggleButton: {
|
||||
variants: [
|
||||
{
|
||||
props: { color: 'standard' },
|
||||
style: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: theme.palette.action.selected,
|
||||
},
|
||||
},
|
||||
},
|
||||
style('primary'),
|
||||
style('secondary'),
|
||||
style('info'),
|
||||
style('success'),
|
||||
style('warning'),
|
||||
style('error'),
|
||||
],
|
||||
},
|
||||
MuiToggleButtonGroup: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: `solid 1px ${theme.palette.grey[500_12]}`,
|
||||
'& .MuiToggleButton-root': {
|
||||
margin: 4,
|
||||
borderColor: 'transparent !important',
|
||||
borderRadius: `${theme.shape.borderRadius}px !important`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
20
frontend/dashboard/src/theme/overrides/Tooltip.ts
Normal file
20
frontend/dashboard/src/theme/overrides/Tooltip.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Tooltip(theme: Theme) {
|
||||
const isLight = theme.palette.mode === 'light';
|
||||
|
||||
return {
|
||||
MuiTooltip: {
|
||||
styleOverrides: {
|
||||
tooltip: {
|
||||
backgroundColor: theme.palette.grey[isLight ? 800 : 700]
|
||||
},
|
||||
arrow: {
|
||||
color: theme.palette.grey[isLight ? 800 : 700]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
23
frontend/dashboard/src/theme/overrides/TreeView.tsx
Normal file
23
frontend/dashboard/src/theme/overrides/TreeView.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
import { TreeViewCollapseIcon, TreeViewExpandIcon, TreeViewEndIcon } from './CustomIcons';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function TreeView(theme: Theme) {
|
||||
return {
|
||||
MuiTreeView: {
|
||||
defaultProps: {
|
||||
defaultCollapseIcon: <TreeViewCollapseIcon sx={{ width: 20, height: 20 }} />,
|
||||
defaultExpandIcon: <TreeViewExpandIcon sx={{ width: 20, height: 20 }} />,
|
||||
defaultEndIcon: <TreeViewEndIcon sx={{ color: 'text.secondary', width: 20, height: 20 }} />,
|
||||
},
|
||||
},
|
||||
MuiTreeItem: {
|
||||
styleOverrides: {
|
||||
label: { ...theme.typography.body2 },
|
||||
iconContainer: { width: 'auto' },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
18
frontend/dashboard/src/theme/overrides/Typography.ts
Normal file
18
frontend/dashboard/src/theme/overrides/Typography.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Typography(theme: Theme) {
|
||||
return {
|
||||
MuiTypography: {
|
||||
styleOverrides: {
|
||||
paragraph: {
|
||||
marginBottom: theme.spacing(2)
|
||||
},
|
||||
gutterBottom: {
|
||||
marginBottom: theme.spacing(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
93
frontend/dashboard/src/theme/overrides/index.ts
Normal file
93
frontend/dashboard/src/theme/overrides/index.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
//
|
||||
import Fab from './Fab';
|
||||
import Card from './Card';
|
||||
import Chip from './Chip';
|
||||
import Tabs from './Tabs';
|
||||
import Menu from './Menu';
|
||||
import Link from './Link';
|
||||
import Lists from './List';
|
||||
import Table from './Table';
|
||||
import Alert from './Alert';
|
||||
import Badge from './Badge';
|
||||
import Paper from './Paper';
|
||||
import Input from './Input';
|
||||
import Radio from './Radio';
|
||||
import Drawer from './Drawer';
|
||||
import Dialog from './Dialog';
|
||||
import Avatar from './Avatar';
|
||||
import Rating from './Rating';
|
||||
import Slider from './Slider';
|
||||
import Button from './Button';
|
||||
import Switch from './Switch';
|
||||
import Select from './Select';
|
||||
import SvgIcon from './SvgIcon';
|
||||
import Tooltip from './Tooltip';
|
||||
import Popover from './Popover';
|
||||
import Stepper from './Stepper';
|
||||
import DataGrid from './DataGrid';
|
||||
import Skeleton from './Skeleton';
|
||||
import Backdrop from './Backdrop';
|
||||
import Progress from './Progress';
|
||||
import Timeline from './Timeline';
|
||||
import TreeView from './TreeView';
|
||||
import Checkbox from './Checkbox';
|
||||
import Accordion from './Accordion';
|
||||
import Typography from './Typography';
|
||||
import Pagination from './Pagination';
|
||||
import Breadcrumbs from './Breadcrumbs';
|
||||
import ButtonGroup from './ButtonGroup';
|
||||
import CssBaseline from './CssBaseline';
|
||||
import Autocomplete from './Autocomplete';
|
||||
import ToggleButton from './ToggleButton';
|
||||
import ControlLabel from './ControlLabel';
|
||||
import LoadingButton from './LoadingButton';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function ComponentsOverrides(theme: Theme) {
|
||||
return Object.assign(
|
||||
Fab(theme),
|
||||
Tabs(theme),
|
||||
Chip(theme),
|
||||
Card(theme),
|
||||
Menu(theme),
|
||||
Link(theme),
|
||||
Input(theme),
|
||||
Radio(theme),
|
||||
Badge(theme),
|
||||
Lists(theme),
|
||||
Table(theme),
|
||||
Paper(theme),
|
||||
Alert(theme),
|
||||
Switch(theme),
|
||||
Select(theme),
|
||||
Button(theme),
|
||||
Rating(theme),
|
||||
Dialog(theme),
|
||||
Avatar(theme),
|
||||
Slider(theme),
|
||||
Drawer(theme),
|
||||
Stepper(theme),
|
||||
Tooltip(theme),
|
||||
Popover(theme),
|
||||
SvgIcon(theme),
|
||||
Checkbox(theme),
|
||||
DataGrid(theme),
|
||||
Skeleton(theme),
|
||||
Timeline(theme),
|
||||
TreeView(theme),
|
||||
Backdrop(theme),
|
||||
Progress(theme),
|
||||
Accordion(theme),
|
||||
Typography(theme),
|
||||
Pagination(theme),
|
||||
ButtonGroup(theme),
|
||||
Breadcrumbs(theme),
|
||||
CssBaseline(theme),
|
||||
Autocomplete(theme),
|
||||
ControlLabel(theme),
|
||||
ToggleButton(theme),
|
||||
LoadingButton(theme)
|
||||
);
|
||||
}
|
||||
184
frontend/dashboard/src/theme/palette.ts
Normal file
184
frontend/dashboard/src/theme/palette.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { alpha } from '@mui/material/styles';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
function createGradient(color1: string, color2: string) {
|
||||
return `linear-gradient(to bottom, ${color1}, ${color2})`;
|
||||
}
|
||||
|
||||
export type ColorSchema = 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error';
|
||||
|
||||
interface GradientsPaletteOptions {
|
||||
primary: string;
|
||||
info: string;
|
||||
success: string;
|
||||
warning: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface ChartPaletteOptions {
|
||||
violet: string[];
|
||||
blue: string[];
|
||||
green: string[];
|
||||
yellow: string[];
|
||||
red: string[];
|
||||
}
|
||||
|
||||
declare module '@mui/material/styles/createPalette' {
|
||||
interface TypeBackground {
|
||||
neutral: string;
|
||||
}
|
||||
interface SimplePaletteColorOptions {
|
||||
lighter: string;
|
||||
darker: string;
|
||||
}
|
||||
interface PaletteColor {
|
||||
lighter: string;
|
||||
darker: string;
|
||||
}
|
||||
interface Palette {
|
||||
gradients: GradientsPaletteOptions;
|
||||
chart: ChartPaletteOptions;
|
||||
}
|
||||
interface PaletteOptions {
|
||||
gradients: GradientsPaletteOptions;
|
||||
chart: ChartPaletteOptions;
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@mui/material' {
|
||||
interface Color {
|
||||
0: string;
|
||||
500_8: string;
|
||||
500_12: string;
|
||||
500_16: string;
|
||||
500_24: string;
|
||||
500_32: string;
|
||||
500_48: string;
|
||||
500_56: string;
|
||||
500_80: string;
|
||||
}
|
||||
}
|
||||
|
||||
// SETUP COLORS
|
||||
const PRIMARY = {
|
||||
lighter: '#C8FACD',
|
||||
light: '#5BE584',
|
||||
main: '#00AB55',
|
||||
dark: '#007B55',
|
||||
darker: '#005249',
|
||||
};
|
||||
const SECONDARY = {
|
||||
lighter: '#D6E4FF',
|
||||
light: '#84A9FF',
|
||||
main: '#3366FF',
|
||||
dark: '#1939B7',
|
||||
darker: '#091A7A',
|
||||
};
|
||||
const INFO = {
|
||||
lighter: '#D0F2FF',
|
||||
light: '#74CAFF',
|
||||
main: '#1890FF',
|
||||
dark: '#0C53B7',
|
||||
darker: '#04297A',
|
||||
};
|
||||
const SUCCESS = {
|
||||
lighter: '#E9FCD4',
|
||||
light: '#AAF27F',
|
||||
main: '#54D62C',
|
||||
dark: '#229A16',
|
||||
darker: '#08660D',
|
||||
};
|
||||
const WARNING = {
|
||||
lighter: '#FFF7CD',
|
||||
light: '#FFE16A',
|
||||
main: '#FFC107',
|
||||
dark: '#B78103',
|
||||
darker: '#7A4F01',
|
||||
};
|
||||
const ERROR = {
|
||||
lighter: '#FFE7D9',
|
||||
light: '#FFA48D',
|
||||
main: '#FF4842',
|
||||
dark: '#B72136',
|
||||
darker: '#7A0C2E',
|
||||
};
|
||||
|
||||
const GREY = {
|
||||
0: '#FFFFFF',
|
||||
100: '#F9FAFB',
|
||||
200: '#F4F6F8',
|
||||
300: '#DFE3E8',
|
||||
400: '#C4CDD5',
|
||||
500: '#919EAB',
|
||||
600: '#637381',
|
||||
700: '#454F5B',
|
||||
800: '#212B36',
|
||||
900: '#161C24',
|
||||
500_8: alpha('#919EAB', 0.08),
|
||||
500_12: alpha('#919EAB', 0.12),
|
||||
500_16: alpha('#919EAB', 0.16),
|
||||
500_24: alpha('#919EAB', 0.24),
|
||||
500_32: alpha('#919EAB', 0.32),
|
||||
500_48: alpha('#919EAB', 0.48),
|
||||
500_56: alpha('#919EAB', 0.56),
|
||||
500_80: alpha('#919EAB', 0.8),
|
||||
};
|
||||
|
||||
const GRADIENTS = {
|
||||
primary: createGradient(PRIMARY.light, PRIMARY.main),
|
||||
info: createGradient(INFO.light, INFO.main),
|
||||
success: createGradient(SUCCESS.light, SUCCESS.main),
|
||||
warning: createGradient(WARNING.light, WARNING.main),
|
||||
error: createGradient(ERROR.light, ERROR.main),
|
||||
};
|
||||
|
||||
const CHART_COLORS = {
|
||||
violet: ['#826AF9', '#9E86FF', '#D0AEFF', '#F7D2FF'],
|
||||
blue: ['#2D99FF', '#83CFFF', '#A5F3FF', '#CCFAFF'],
|
||||
green: ['#2CD9C5', '#60F1C8', '#A4F7CC', '#C0F2DC'],
|
||||
yellow: ['#FFE700', '#FFEF5A', '#FFF7AE', '#FFF3D6'],
|
||||
red: ['#FF6C40', '#FF8F6D', '#FFBD98', '#FFF2D4'],
|
||||
};
|
||||
|
||||
const COMMON = {
|
||||
common: { black: '#000', white: '#fff' },
|
||||
primary: { ...PRIMARY, contrastText: '#fff' },
|
||||
secondary: { ...SECONDARY, contrastText: '#fff' },
|
||||
info: { ...INFO, contrastText: '#fff' },
|
||||
success: { ...SUCCESS, contrastText: GREY[800] },
|
||||
warning: { ...WARNING, contrastText: GREY[800] },
|
||||
error: { ...ERROR, contrastText: '#fff' },
|
||||
grey: GREY,
|
||||
gradients: GRADIENTS,
|
||||
chart: CHART_COLORS,
|
||||
divider: GREY[500_24],
|
||||
action: {
|
||||
hover: GREY[500_8],
|
||||
selected: GREY[500_16],
|
||||
disabled: GREY[500_80],
|
||||
disabledBackground: GREY[500_24],
|
||||
focus: GREY[500_24],
|
||||
hoverOpacity: 0.08,
|
||||
disabledOpacity: 0.48,
|
||||
},
|
||||
};
|
||||
|
||||
const palette = {
|
||||
light: {
|
||||
...COMMON,
|
||||
mode: 'light',
|
||||
text: { primary: GREY[800], secondary: GREY[600], disabled: GREY[500] },
|
||||
background: { paper: '#fff', default: '#fff', neutral: GREY[200] },
|
||||
action: { active: GREY[600], ...COMMON.action },
|
||||
},
|
||||
dark: {
|
||||
...COMMON,
|
||||
mode: 'dark',
|
||||
text: { primary: '#fff', secondary: GREY[500], disabled: GREY[600] },
|
||||
background: { paper: GREY[800], default: GREY[900], neutral: GREY[500_16] },
|
||||
action: { active: GREY[500], ...COMMON.action },
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default palette;
|
||||
110
frontend/dashboard/src/theme/shadows.ts
Normal file
110
frontend/dashboard/src/theme/shadows.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
// @mui
|
||||
import { alpha } from '@mui/material/styles';
|
||||
import { Shadows } from '@mui/material/styles/shadows';
|
||||
//
|
||||
import palette from './palette';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
interface CustomShadowOptions {
|
||||
z1: string;
|
||||
z8: string;
|
||||
z12: string;
|
||||
z16: string;
|
||||
z20: string;
|
||||
z24: string;
|
||||
//
|
||||
primary: string;
|
||||
secondary: string;
|
||||
info: string;
|
||||
success: string;
|
||||
warning: string;
|
||||
error: string;
|
||||
//
|
||||
card: string;
|
||||
dialog: string;
|
||||
dropdown: string;
|
||||
}
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Theme {
|
||||
customShadows: CustomShadowOptions;
|
||||
}
|
||||
interface ThemeOptions {
|
||||
customShadows?: CustomShadowOptions;
|
||||
}
|
||||
}
|
||||
|
||||
const LIGHT_MODE = palette.light.grey[500];
|
||||
const DARK_MODE = '#000000';
|
||||
|
||||
const createShadow = (color: string): Shadows => {
|
||||
const transparent1 = alpha(color, 0.2);
|
||||
const transparent2 = alpha(color, 0.14);
|
||||
const transparent3 = alpha(color, 0.12);
|
||||
return [
|
||||
'none',
|
||||
`0px 2px 1px -1px ${transparent1},0px 1px 1px 0px ${transparent2},0px 1px 3px 0px ${transparent3}`,
|
||||
`0px 3px 1px -2px ${transparent1},0px 2px 2px 0px ${transparent2},0px 1px 5px 0px ${transparent3}`,
|
||||
`0px 3px 3px -2px ${transparent1},0px 3px 4px 0px ${transparent2},0px 1px 8px 0px ${transparent3}`,
|
||||
`0px 2px 4px -1px ${transparent1},0px 4px 5px 0px ${transparent2},0px 1px 10px 0px ${transparent3}`,
|
||||
`0px 3px 5px -1px ${transparent1},0px 5px 8px 0px ${transparent2},0px 1px 14px 0px ${transparent3}`,
|
||||
`0px 3px 5px -1px ${transparent1},0px 6px 10px 0px ${transparent2},0px 1px 18px 0px ${transparent3}`,
|
||||
`0px 4px 5px -2px ${transparent1},0px 7px 10px 1px ${transparent2},0px 2px 16px 1px ${transparent3}`,
|
||||
`0px 5px 5px -3px ${transparent1},0px 8px 10px 1px ${transparent2},0px 3px 14px 2px ${transparent3}`,
|
||||
`0px 5px 6px -3px ${transparent1},0px 9px 12px 1px ${transparent2},0px 3px 16px 2px ${transparent3}`,
|
||||
`0px 6px 6px -3px ${transparent1},0px 10px 14px 1px ${transparent2},0px 4px 18px 3px ${transparent3}`,
|
||||
`0px 6px 7px -4px ${transparent1},0px 11px 15px 1px ${transparent2},0px 4px 20px 3px ${transparent3}`,
|
||||
`0px 7px 8px -4px ${transparent1},0px 12px 17px 2px ${transparent2},0px 5px 22px 4px ${transparent3}`,
|
||||
`0px 7px 8px -4px ${transparent1},0px 13px 19px 2px ${transparent2},0px 5px 24px 4px ${transparent3}`,
|
||||
`0px 7px 9px -4px ${transparent1},0px 14px 21px 2px ${transparent2},0px 5px 26px 4px ${transparent3}`,
|
||||
`0px 8px 9px -5px ${transparent1},0px 15px 22px 2px ${transparent2},0px 6px 28px 5px ${transparent3}`,
|
||||
`0px 8px 10px -5px ${transparent1},0px 16px 24px 2px ${transparent2},0px 6px 30px 5px ${transparent3}`,
|
||||
`0px 8px 11px -5px ${transparent1},0px 17px 26px 2px ${transparent2},0px 6px 32px 5px ${transparent3}`,
|
||||
`0px 9px 11px -5px ${transparent1},0px 18px 28px 2px ${transparent2},0px 7px 34px 6px ${transparent3}`,
|
||||
`0px 9px 12px -6px ${transparent1},0px 19px 29px 2px ${transparent2},0px 7px 36px 6px ${transparent3}`,
|
||||
`0px 10px 13px -6px ${transparent1},0px 20px 31px 3px ${transparent2},0px 8px 38px 7px ${transparent3}`,
|
||||
`0px 10px 13px -6px ${transparent1},0px 21px 33px 3px ${transparent2},0px 8px 40px 7px ${transparent3}`,
|
||||
`0px 10px 14px -6px ${transparent1},0px 22px 35px 3px ${transparent2},0px 8px 42px 7px ${transparent3}`,
|
||||
`0px 11px 14px -7px ${transparent1},0px 23px 36px 3px ${transparent2},0px 9px 44px 8px ${transparent3}`,
|
||||
`0px 11px 15px -7px ${transparent1},0px 24px 38px 3px ${transparent2},0px 9px 46px 8px ${transparent3}`,
|
||||
];
|
||||
};
|
||||
|
||||
const createCustomShadow = (color: string) => {
|
||||
const transparent = alpha(color, 0.16);
|
||||
return {
|
||||
z1: `0 1px 2px 0 ${transparent}`,
|
||||
z8: `0 8px 16px 0 ${transparent}`,
|
||||
z12: `0 12px 24px -4px ${transparent}`,
|
||||
z16: `0 16px 32px -4px ${transparent}`,
|
||||
z20: `0 20px 40px -4px ${transparent}`,
|
||||
z24: `0 24px 48px 0 ${transparent}`,
|
||||
//
|
||||
primary: `0 8px 16px 0 ${alpha(palette.light.primary.main, 0.24)}`,
|
||||
info: `0 8px 16px 0 ${alpha(palette.light.info.main, 0.24)}`,
|
||||
secondary: `0 8px 16px 0 ${alpha(palette.light.secondary.main, 0.24)}`,
|
||||
success: `0 8px 16px 0 ${alpha(palette.light.success.main, 0.24)}`,
|
||||
warning: `0 8px 16px 0 ${alpha(palette.light.warning.main, 0.24)}`,
|
||||
error: `0 8px 16px 0 ${alpha(palette.light.error.main, 0.24)}`,
|
||||
//
|
||||
card: `0 0 2px 0 ${alpha(color, 0.2)}, 0 12px 24px -4px ${alpha(color, 0.12)}`,
|
||||
dialog: `-40px 40px 80px -8px ${alpha(palette.light.common.black, 0.24)}`,
|
||||
dropdown: `0 0 2px 0 ${alpha(color, 0.24)}, -20px 20px 40px -4px ${alpha(color, 0.24)}`,
|
||||
};
|
||||
};
|
||||
|
||||
export const customShadows = {
|
||||
light: createCustomShadow(LIGHT_MODE),
|
||||
dark: createCustomShadow(DARK_MODE),
|
||||
};
|
||||
|
||||
const shadows: {
|
||||
light: Shadows;
|
||||
dark: Shadows;
|
||||
} = {
|
||||
light: createShadow(LIGHT_MODE),
|
||||
dark: createShadow(DARK_MODE),
|
||||
};
|
||||
|
||||
export default shadows;
|
||||
86
frontend/dashboard/src/theme/typography.ts
Normal file
86
frontend/dashboard/src/theme/typography.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { pxToRem, responsiveFontSizes } from '../utils/getFontValue';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const FONT_PRIMARY = 'Public Sans, sans-serif'; // Google Font
|
||||
// const FONT_SECONDARY = 'CircularStd, sans-serif'; // Local Font
|
||||
|
||||
const typography = {
|
||||
fontFamily: FONT_PRIMARY,
|
||||
fontWeightRegular: 400,
|
||||
fontWeightMedium: 600,
|
||||
fontWeightBold: 700,
|
||||
h1: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 80 / 64,
|
||||
fontSize: pxToRem(40),
|
||||
letterSpacing: 2,
|
||||
...responsiveFontSizes({ sm: 52, md: 58, lg: 64 }),
|
||||
},
|
||||
h2: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 64 / 48,
|
||||
fontSize: pxToRem(32),
|
||||
...responsiveFontSizes({ sm: 40, md: 44, lg: 48 }),
|
||||
},
|
||||
h3: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(24),
|
||||
...responsiveFontSizes({ sm: 26, md: 30, lg: 32 }),
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(20),
|
||||
...responsiveFontSizes({ sm: 20, md: 24, lg: 24 }),
|
||||
},
|
||||
h5: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(18),
|
||||
...responsiveFontSizes({ sm: 19, md: 20, lg: 20 }),
|
||||
},
|
||||
h6: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 28 / 18,
|
||||
fontSize: pxToRem(17),
|
||||
...responsiveFontSizes({ sm: 18, md: 18, lg: 18 }),
|
||||
},
|
||||
subtitle1: {
|
||||
fontWeight: 600,
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(16),
|
||||
},
|
||||
subtitle2: {
|
||||
fontWeight: 600,
|
||||
lineHeight: 22 / 14,
|
||||
fontSize: pxToRem(14),
|
||||
},
|
||||
body1: {
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(16),
|
||||
},
|
||||
body2: {
|
||||
lineHeight: 22 / 14,
|
||||
fontSize: pxToRem(14),
|
||||
},
|
||||
caption: {
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
overline: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.5,
|
||||
fontSize: pxToRem(12),
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
button: {
|
||||
fontWeight: 700,
|
||||
lineHeight: 24 / 14,
|
||||
fontSize: pxToRem(14),
|
||||
textTransform: 'capitalize',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default typography;
|
||||
Reference in New Issue
Block a user