code handover
This commit is contained in:
88
src/components/@extended/AnimateButton.js
Normal file
88
src/components/@extended/AnimateButton.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// third-party
|
||||
import { motion, useCycle } from 'framer-motion';
|
||||
|
||||
// ==============================|| ANIMATION BUTTON ||============================== //
|
||||
|
||||
export default function AnimateButton({
|
||||
children,
|
||||
type = 'scale',
|
||||
direction = 'right',
|
||||
offset = 10,
|
||||
scale = {
|
||||
hover: 1.05,
|
||||
tap: 0.95
|
||||
}
|
||||
}) {
|
||||
let offset1;
|
||||
let offset2;
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
case 'left':
|
||||
offset1 = offset;
|
||||
offset2 = 0;
|
||||
break;
|
||||
case 'right':
|
||||
case 'down':
|
||||
default:
|
||||
offset1 = 0;
|
||||
offset2 = offset;
|
||||
break;
|
||||
}
|
||||
|
||||
const [x, cycleX] = useCycle(offset1, offset2);
|
||||
const [y, cycleY] = useCycle(offset1, offset2);
|
||||
|
||||
switch (type) {
|
||||
case 'rotate':
|
||||
return (
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{
|
||||
repeat: Infinity,
|
||||
repeatType: 'loop',
|
||||
duration: 2,
|
||||
repeatDelay: 0
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
case 'slide':
|
||||
if (direction === 'up' || direction === 'down') {
|
||||
return (
|
||||
<motion.div animate={{ y: y !== undefined ? y : '' }} onHoverEnd={() => cycleY()} onHoverStart={() => cycleY()}>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<motion.div animate={{ x: x !== undefined ? x : '' }} onHoverEnd={() => cycleX()} onHoverStart={() => cycleX()}>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
case 'scale':
|
||||
default:
|
||||
if (typeof scale === 'number') {
|
||||
scale = {
|
||||
hover: scale,
|
||||
tap: scale
|
||||
};
|
||||
}
|
||||
return (
|
||||
<motion.div whileHover={{ scale: scale?.hover }} whileTap={{ scale: scale?.tap }}>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AnimateButton.propTypes = {
|
||||
children: PropTypes.node,
|
||||
offset: PropTypes.number,
|
||||
type: PropTypes.oneOf(['slide', 'scale', 'rotate']),
|
||||
direction: PropTypes.oneOf(['up', 'down', 'left', 'right']),
|
||||
scale: PropTypes.oneOfType([PropTypes.number, PropTypes.object])
|
||||
};
|
||||
119
src/components/@extended/Avatar.js
Normal file
119
src/components/@extended/Avatar.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import MuiAvatar from '@mui/material/Avatar';
|
||||
|
||||
// project import
|
||||
import getColors from 'utils/getColors';
|
||||
|
||||
// ==============================|| AVATAR - COLOR STYLE ||============================== //
|
||||
|
||||
function getColorStyle({ theme, color, type }) {
|
||||
const colors = getColors(theme, color);
|
||||
const { lighter, light, main, contrastText } = colors;
|
||||
|
||||
switch (type) {
|
||||
case 'filled':
|
||||
return {
|
||||
color: contrastText,
|
||||
backgroundColor: main
|
||||
};
|
||||
case 'outlined':
|
||||
return {
|
||||
color: main,
|
||||
border: '1px solid',
|
||||
borderColor: main,
|
||||
backgroundColor: 'transparent'
|
||||
};
|
||||
case 'combined':
|
||||
return {
|
||||
color: main,
|
||||
border: '1px solid',
|
||||
borderColor: light,
|
||||
backgroundColor: lighter
|
||||
};
|
||||
default:
|
||||
return {
|
||||
color: main,
|
||||
backgroundColor: lighter
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| AVATAR - SIZE STYLE ||============================== //
|
||||
|
||||
function getSizeStyle(size) {
|
||||
switch (size) {
|
||||
case 'badge':
|
||||
return {
|
||||
border: '2px solid',
|
||||
fontSize: '0.675rem',
|
||||
width: 20,
|
||||
height: 20
|
||||
};
|
||||
case 'xs':
|
||||
return {
|
||||
fontSize: '0.75rem',
|
||||
width: 24,
|
||||
height: 24
|
||||
};
|
||||
case 'sm':
|
||||
return {
|
||||
fontSize: '0.875rem',
|
||||
width: 32,
|
||||
height: 32
|
||||
};
|
||||
case 'lg':
|
||||
return {
|
||||
fontSize: '1.2rem',
|
||||
width: 52,
|
||||
height: 52
|
||||
};
|
||||
case 'xl':
|
||||
return {
|
||||
fontSize: '1.5rem',
|
||||
width: 64,
|
||||
height: 64
|
||||
};
|
||||
case 'md':
|
||||
default:
|
||||
return {
|
||||
fontSize: '1rem',
|
||||
width: 40,
|
||||
height: 40
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| STYLED - AVATAR ||============================== //
|
||||
|
||||
const AvatarStyle = styled(MuiAvatar, { shouldForwardProp: (prop) => prop !== 'color' && prop !== 'type' && prop !== 'size' })(
|
||||
({ theme, variant, color, type, size }) => ({
|
||||
...getSizeStyle(size),
|
||||
...getColorStyle({ variant, theme, color, type }),
|
||||
...(size === 'badge' && {
|
||||
borderColor: theme.palette.background.default
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
// ==============================|| EXTENDED - AVATAR ||============================== //
|
||||
|
||||
export default function Avatar({ variant = 'circular', children, color = 'primary', type, size = 'md', ...others }) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<AvatarStyle variant={variant} theme={theme} color={color} type={type} size={size} {...others}>
|
||||
{children}
|
||||
</AvatarStyle>
|
||||
);
|
||||
}
|
||||
|
||||
Avatar.propTypes = {
|
||||
children: PropTypes.node,
|
||||
color: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
size: PropTypes.string,
|
||||
variant: PropTypes.string
|
||||
};
|
||||
222
src/components/@extended/Breadcrumbs.js
Normal file
222
src/components/@extended/Breadcrumbs.js
Normal file
@@ -0,0 +1,222 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Divider, Grid, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
|
||||
// assets
|
||||
import { ApartmentOutlined, HomeFilled, HomeOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| BREADCRUMBS ||============================== //
|
||||
|
||||
const Breadcrumbs = ({
|
||||
card,
|
||||
divider = true,
|
||||
icon,
|
||||
icons,
|
||||
maxItems,
|
||||
navigation,
|
||||
rightAlign,
|
||||
separator,
|
||||
title,
|
||||
titleBottom,
|
||||
sx,
|
||||
...others
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const location = useLocation();
|
||||
const [main, setMain] = useState();
|
||||
const [item, setItem] = useState();
|
||||
|
||||
let currentPath = location.pathname;
|
||||
|
||||
// only used for component demo breadcrumbs
|
||||
if (currentPath.includes('/components-overview/breadcrumbs')) {
|
||||
currentPath = '/apps/kanban/board';
|
||||
}
|
||||
|
||||
if (currentPath.includes('/apps/kanban/backlogs')) {
|
||||
currentPath = '/apps/kanban/board';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPath.includes('/apps/profiles/user/payment')) {
|
||||
setItem(undefined);
|
||||
}
|
||||
}, [item, currentPath]);
|
||||
|
||||
const iconSX = {
|
||||
marginRight: theme.spacing(0.75),
|
||||
marginTop: `-${theme.spacing(0.25)}`,
|
||||
width: '1rem',
|
||||
height: '1rem',
|
||||
color: theme.palette.secondary.main
|
||||
};
|
||||
|
||||
// set active item state
|
||||
const getCollapse = (menu) => {
|
||||
if (menu.children) {
|
||||
menu.children.filter((collapse) => {
|
||||
if (collapse.type && collapse.type === 'collapse') {
|
||||
getCollapse(collapse);
|
||||
if (collapse.url === currentPath) {
|
||||
setMain(collapse);
|
||||
setItem(collapse);
|
||||
}
|
||||
} else if (collapse.type && collapse.type === 'item') {
|
||||
if (currentPath.includes(collapse.url)) {
|
||||
setMain(menu);
|
||||
setItem(collapse);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
navigation?.items?.map((menu) => {
|
||||
if (menu.type && menu.type === 'group') {
|
||||
getCollapse(menu);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// item separator
|
||||
const SeparatorIcon = separator;
|
||||
const separatorIcon = separator ? <SeparatorIcon style={{ fontSize: '0.75rem', marginTop: 2 }} /> : '/';
|
||||
|
||||
let mainContent;
|
||||
let itemContent;
|
||||
let breadcrumbContent = <Typography />;
|
||||
let itemTitle = '';
|
||||
let CollapseIcon;
|
||||
let ItemIcon;
|
||||
|
||||
// collapse item
|
||||
if (main && main.type === 'collapse' && main.breadcrumbs === true) {
|
||||
CollapseIcon = main.icon ? main.icon : ApartmentOutlined;
|
||||
mainContent = (
|
||||
<Typography component={Link} to={document.location.pathname} variant="h6" sx={{ textDecoration: 'none' }} color="textSecondary">
|
||||
{icons && <CollapseIcon style={iconSX} />}
|
||||
{main.title}
|
||||
</Typography>
|
||||
);
|
||||
breadcrumbContent = (
|
||||
<MainCard
|
||||
border={card}
|
||||
sx={card === false ? { mb: 3, bgcolor: 'transparent', ...sx } : { mb: 3, ...sx }}
|
||||
{...others}
|
||||
content={card}
|
||||
shadow="none"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
direction={rightAlign ? 'row' : 'column'}
|
||||
justifyContent={rightAlign ? 'space-between' : 'flex-start'}
|
||||
alignItems={rightAlign ? 'center' : 'flex-start'}
|
||||
spacing={1}
|
||||
>
|
||||
<Grid item>
|
||||
<MuiBreadcrumbs aria-label="breadcrumb" maxItems={maxItems || 8} separator={separatorIcon}>
|
||||
<Typography component={Link} to="/" color="textSecondary" variant="h6" sx={{ textDecoration: 'none' }}>
|
||||
{icons && <HomeOutlined style={iconSX} />}
|
||||
{icon && !icons && <HomeFilled style={{ ...iconSX, marginRight: 0 }} />}
|
||||
{(!icon || icons) && 'Home'}
|
||||
</Typography>
|
||||
{mainContent}
|
||||
</MuiBreadcrumbs>
|
||||
</Grid>
|
||||
{title && titleBottom && (
|
||||
<Grid item sx={{ mt: card === false ? 0.25 : 1 }}>
|
||||
<Typography variant="h2">{main.title}</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
{card === false && divider !== false && <Divider sx={{ mt: 2 }} />}
|
||||
</MainCard>
|
||||
);
|
||||
}
|
||||
|
||||
// items
|
||||
if (item && item.type === 'item') {
|
||||
itemTitle = item.title;
|
||||
|
||||
ItemIcon = item.icon ? item.icon : ApartmentOutlined;
|
||||
itemContent = (
|
||||
<Typography variant="subtitle1" color="textPrimary">
|
||||
{icons && <ItemIcon style={iconSX} />}
|
||||
{itemTitle}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
// main
|
||||
if (item.breadcrumbs !== false) {
|
||||
breadcrumbContent = (
|
||||
<MainCard
|
||||
border={card}
|
||||
sx={card === false ? { mb: 3, bgcolor: 'transparent', ...sx } : { mb: 3, ...sx }}
|
||||
{...others}
|
||||
content={card}
|
||||
shadow="none"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
direction={rightAlign ? 'row' : 'column'}
|
||||
justifyContent={rightAlign ? 'space-between' : 'flex-start'}
|
||||
alignItems={rightAlign ? 'center' : 'flex-start'}
|
||||
spacing={1}
|
||||
>
|
||||
{title && !titleBottom && (
|
||||
<Grid item>
|
||||
<Typography variant="h2">{item.title}</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item>
|
||||
<MuiBreadcrumbs aria-label="breadcrumb" maxItems={maxItems || 8} separator={separatorIcon}>
|
||||
<Typography component={Link} to="/" color="textSecondary" variant="h6" sx={{ textDecoration: 'none' }}>
|
||||
{icons && <HomeOutlined style={iconSX} />}
|
||||
{icon && !icons && <HomeFilled style={{ ...iconSX, marginRight: 0 }} />}
|
||||
{(!icon || icons) && 'Home'}
|
||||
</Typography>
|
||||
{mainContent}
|
||||
{itemContent}
|
||||
</MuiBreadcrumbs>
|
||||
</Grid>
|
||||
{title && titleBottom && (
|
||||
<Grid item sx={{ mt: card === false ? 0.25 : 1 }}>
|
||||
<Typography variant="h2">{item.title}</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
{card === false && divider !== false && <Divider sx={{ mt: 2 }} />}
|
||||
</MainCard>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return breadcrumbContent;
|
||||
};
|
||||
|
||||
Breadcrumbs.propTypes = {
|
||||
card: PropTypes.bool,
|
||||
divider: PropTypes.bool,
|
||||
icon: PropTypes.bool,
|
||||
icons: PropTypes.bool,
|
||||
maxItems: PropTypes.number,
|
||||
navigation: PropTypes.object,
|
||||
rightAlign: PropTypes.bool,
|
||||
separator: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
||||
title: PropTypes.bool,
|
||||
titleBottom: PropTypes.bool,
|
||||
sx: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
|
||||
};
|
||||
|
||||
export default Breadcrumbs;
|
||||
39
src/components/@extended/Dot.js
Normal file
39
src/components/@extended/Dot.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import getColors from 'utils/getColors';
|
||||
|
||||
const Dot = ({ color, size, variant, sx }) => {
|
||||
const theme = useTheme();
|
||||
const colors = getColors(theme, color || 'primary');
|
||||
const { main } = colors;
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
width: size || 8,
|
||||
height: size || 8,
|
||||
borderRadius: '50%',
|
||||
bgcolor: variant === 'outlined' ? '' : main,
|
||||
...(variant === 'outlined' && {
|
||||
border: `1px solid ${main}`
|
||||
}),
|
||||
...sx
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Dot.propTypes = {
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
variant: PropTypes.string,
|
||||
sx: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
|
||||
};
|
||||
|
||||
export default Dot;
|
||||
162
src/components/@extended/IconButton.js
Normal file
162
src/components/@extended/IconButton.js
Normal file
@@ -0,0 +1,162 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
// material-ui
|
||||
import MuiIconButton from '@mui/material/IconButton';
|
||||
import { alpha, styled, useTheme } from '@mui/material/styles';
|
||||
|
||||
// project imports
|
||||
import getColors from 'utils/getColors';
|
||||
import getShadow from 'utils/getShadow';
|
||||
|
||||
// ==============================|| ICON BUTTON - COLOR STYLE ||============================== //
|
||||
|
||||
function getColorStyle({ variant, theme, color }) {
|
||||
const colors = getColors(theme, color);
|
||||
const { lighter, light, dark, main, contrastText } = colors;
|
||||
|
||||
const buttonShadow = `${color}Button`;
|
||||
const shadows = getShadow(theme, buttonShadow);
|
||||
|
||||
const commonShadow = {
|
||||
'&::after': {
|
||||
boxShadow: `0 0 6px 6px ${alpha(main, 0.9)}`
|
||||
},
|
||||
'&:active::after': {
|
||||
boxShadow: `0 0 0 0 ${alpha(main, 0.9)}`
|
||||
},
|
||||
'&:focus-visible': {
|
||||
outline: `2px solid ${dark}`,
|
||||
outlineOffset: 2
|
||||
}
|
||||
};
|
||||
|
||||
switch (variant) {
|
||||
case 'contained':
|
||||
return {
|
||||
color: contrastText,
|
||||
backgroundColor: main,
|
||||
'&:hover': {
|
||||
backgroundColor: dark
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'light':
|
||||
return {
|
||||
color: main,
|
||||
backgroundColor: lighter,
|
||||
'&:hover': {
|
||||
backgroundColor: light
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'shadow':
|
||||
return {
|
||||
boxShadow: shadows,
|
||||
color: contrastText,
|
||||
backgroundColor: main,
|
||||
'&:hover': {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: dark
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'outlined':
|
||||
return {
|
||||
'&:hover': {
|
||||
backgroundColor: 'transparent',
|
||||
color: dark,
|
||||
borderColor: dark
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'dashed':
|
||||
return {
|
||||
backgroundColor: lighter,
|
||||
'&:hover': {
|
||||
color: dark,
|
||||
borderColor: dark
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'text':
|
||||
default:
|
||||
return {
|
||||
'&:hover': {
|
||||
color: dark,
|
||||
backgroundColor: lighter
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| STYLED - ICON BUTTON ||============================== //
|
||||
|
||||
const IconButtonStyle = styled(MuiIconButton, { shouldForwardProp: (prop) => prop !== 'variant' && prop !== 'shape' })(
|
||||
({ theme, variant, shape, color }) => ({
|
||||
position: 'relative',
|
||||
'::after': {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: shape === 'rounded' ? '50%' : 4,
|
||||
opacity: 0,
|
||||
transition: 'all 0.5s'
|
||||
},
|
||||
|
||||
':active::after': {
|
||||
position: 'absolute',
|
||||
borderRadius: shape === 'rounded' ? '50%' : 4,
|
||||
left: 0,
|
||||
top: 0,
|
||||
opacity: 1,
|
||||
transition: '0s'
|
||||
},
|
||||
...(shape === 'rounded' && {
|
||||
borderRadius: '50%'
|
||||
}),
|
||||
...(variant === 'outlined' && {
|
||||
border: '1px solid',
|
||||
borderColor: 'inherit'
|
||||
}),
|
||||
...(variant === 'dashed' && {
|
||||
border: '1px dashed',
|
||||
borderColor: 'inherit'
|
||||
}),
|
||||
...(variant !== 'text' && {
|
||||
'&.Mui-disabled': {
|
||||
backgroundColor: theme.palette.grey[200]
|
||||
}
|
||||
}),
|
||||
...getColorStyle({ variant, theme, color })
|
||||
})
|
||||
);
|
||||
|
||||
// ==============================|| EXTENDED - ICON BUTTON ||============================== //
|
||||
|
||||
const IconButton = forwardRef(({ variant = 'text', shape = 'square', children, color = 'primary', ...others }, ref) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<IconButtonStyle ref={ref} disableRipple variant={variant} shape={shape} theme={theme} color={color} {...others}>
|
||||
{children}
|
||||
</IconButtonStyle>
|
||||
);
|
||||
});
|
||||
|
||||
IconButton.propTypes = {
|
||||
variant: PropTypes.string,
|
||||
shape: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
color: PropTypes.string
|
||||
};
|
||||
|
||||
IconButton.displayName = 'IconButton';
|
||||
|
||||
export default IconButton;
|
||||
231
src/components/@extended/LoadingButton.js
Normal file
231
src/components/@extended/LoadingButton.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
// material-ui
|
||||
import MuiLoadingButton from '@mui/lab/LoadingButton';
|
||||
import { alpha, styled, useTheme } from '@mui/material/styles';
|
||||
|
||||
// project imports
|
||||
import getColors from 'utils/getColors';
|
||||
import getShadow from 'utils/getShadow';
|
||||
|
||||
// ==============================|| LOADING BUTTON - COLOR STYLE ||============================== //
|
||||
|
||||
function getColorStyle({ variant, theme, color, loadingPosition }) {
|
||||
const colors = getColors(theme, color);
|
||||
const { lighter, main, dark, contrastText } = colors;
|
||||
|
||||
const buttonShadow = `${color}Button`;
|
||||
const shadows = getShadow(theme, buttonShadow);
|
||||
|
||||
const loadingIndicator = {
|
||||
'& .MuiLoadingButton-loadingIndicator': {
|
||||
color: main
|
||||
}
|
||||
};
|
||||
|
||||
const loadingColor = {
|
||||
...(loadingPosition &&
|
||||
loadingPosition !== 'center' && {
|
||||
color: main
|
||||
})
|
||||
};
|
||||
|
||||
const commonShadow = {
|
||||
'&::after': {
|
||||
boxShadow: `0 0 6px 6px ${alpha(main, 0.9)}`
|
||||
},
|
||||
'&:active::after': {
|
||||
boxShadow: `0 0 0 0 ${alpha(main, 0.9)}`
|
||||
},
|
||||
'&:focus-visible': {
|
||||
outline: `2px solid ${dark}`,
|
||||
outlineOffset: 2
|
||||
}
|
||||
};
|
||||
|
||||
switch (variant) {
|
||||
case 'contained':
|
||||
return {
|
||||
backgroundColor: main,
|
||||
...(loadingPosition &&
|
||||
loadingPosition !== 'center' && {
|
||||
color: contrastText
|
||||
}),
|
||||
'& .MuiLoadingButton-loadingIndicator': {
|
||||
color: contrastText
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: dark,
|
||||
color: contrastText
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'light':
|
||||
return {
|
||||
backgroundColor: main,
|
||||
...(loadingPosition &&
|
||||
loadingPosition !== 'center' && {
|
||||
color: contrastText
|
||||
}),
|
||||
'& .MuiLoadingButton-loadingIndicator': {
|
||||
color: contrastText
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: dark,
|
||||
color: contrastText
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'shadow':
|
||||
return {
|
||||
boxShadow: shadows,
|
||||
backgroundColor: main,
|
||||
...(loadingPosition &&
|
||||
loadingPosition !== 'center' && {
|
||||
color: contrastText
|
||||
}),
|
||||
'& .MuiLoadingButton-loadingIndicator': {
|
||||
color: contrastText
|
||||
},
|
||||
'&:hover': {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: dark,
|
||||
color: contrastText
|
||||
},
|
||||
...commonShadow
|
||||
};
|
||||
case 'outlined':
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: main,
|
||||
...loadingColor,
|
||||
...loadingIndicator
|
||||
};
|
||||
case 'dashed':
|
||||
return {
|
||||
backgroundColor: lighter,
|
||||
borderColor: main,
|
||||
...loadingColor,
|
||||
...loadingIndicator,
|
||||
...commonShadow
|
||||
};
|
||||
case 'text':
|
||||
default:
|
||||
return {
|
||||
color: main,
|
||||
...loadingIndicator,
|
||||
...commonShadow
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| STYLED - LOADING BUTTON ||============================== //
|
||||
|
||||
const LoadingButtonStyle = styled(MuiLoadingButton, { shouldForwardProp: (prop) => prop !== 'shape' && prop !== 'variant' })(
|
||||
({ theme, variant, shape, color, loading, loadingPosition }) => ({
|
||||
'::after': {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: shape === 'rounded' ? '50%' : 4,
|
||||
opacity: 0,
|
||||
transition: 'all 0.5s'
|
||||
},
|
||||
|
||||
':active::after': {
|
||||
position: 'absolute',
|
||||
borderRadius: shape === 'rounded' ? '50%' : 4,
|
||||
left: 0,
|
||||
top: 0,
|
||||
opacity: 1,
|
||||
transition: '0s'
|
||||
},
|
||||
...(variant === 'text' && {
|
||||
...getColorStyle({ variant, theme, color, loadingPosition }),
|
||||
'&.MuiButton-sizeMedium': {
|
||||
height: 36
|
||||
},
|
||||
'&.MuiButton-sizeSmall': {
|
||||
height: 30
|
||||
},
|
||||
'&.MuiButton-sizeLarge': {
|
||||
height: 44
|
||||
}
|
||||
}),
|
||||
...(shape && {
|
||||
minWidth: 0,
|
||||
'&.MuiButton-sizeMedium': {
|
||||
width: 36,
|
||||
height: 36
|
||||
},
|
||||
'&.MuiButton-sizeSmall': {
|
||||
width: 30,
|
||||
height: 30
|
||||
},
|
||||
'&.MuiButton-sizeLarge': {
|
||||
width: 44,
|
||||
height: 44
|
||||
},
|
||||
...(shape === 'rounded' && {
|
||||
borderRadius: '50%'
|
||||
})
|
||||
}),
|
||||
|
||||
...(variant === 'outlined' && {
|
||||
border: '1px solid'
|
||||
}),
|
||||
...(variant === 'dashed' && {
|
||||
border: '1px dashed'
|
||||
}),
|
||||
...((variant === 'contained' || variant === 'shadow') &&
|
||||
!loading && {
|
||||
color: '#fff'
|
||||
}),
|
||||
...(variant !== 'text' && {
|
||||
...getColorStyle({ variant, theme, color, loadingPosition })
|
||||
}),
|
||||
|
||||
'&.Mui-disabled': {
|
||||
...(variant !== 'text' && {
|
||||
...getColorStyle({ variant, theme, color, loadingPosition })
|
||||
})
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// ==============================|| EXTENDED - LOADING BUTTON ||============================== //
|
||||
|
||||
const LoadingButton = forwardRef(({ variant = 'text', shape, children, color = 'primary', ...others }, ref) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<LoadingButtonStyle
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
shape={shape}
|
||||
theme={theme}
|
||||
loadingPosition={others.loadingPosition}
|
||||
loading={others.loading}
|
||||
color={color}
|
||||
{...others}
|
||||
>
|
||||
{children}
|
||||
</LoadingButtonStyle>
|
||||
);
|
||||
});
|
||||
|
||||
LoadingButton.propTypes = {
|
||||
variant: PropTypes.string,
|
||||
shape: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
color: PropTypes.string
|
||||
};
|
||||
|
||||
LoadingButton.displayName = 'LoadingButton';
|
||||
|
||||
export default LoadingButton;
|
||||
128
src/components/@extended/Snackbar.js
Normal file
128
src/components/@extended/Snackbar.js
Normal file
@@ -0,0 +1,128 @@
|
||||
// material-ui
|
||||
import { Alert, Button, Fade, Grow, Slide } from '@mui/material';
|
||||
import MuiSnackbar from '@mui/material/Snackbar';
|
||||
|
||||
// project-import
|
||||
import IconButton from './IconButton';
|
||||
import { dispatch, useSelector } from 'store';
|
||||
import { closeSnackbar } from 'store/reducers/snackbar';
|
||||
|
||||
// assets
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
|
||||
// animation function
|
||||
function TransitionSlideLeft(props) {
|
||||
return <Slide {...props} direction="left" />;
|
||||
}
|
||||
|
||||
function TransitionSlideUp(props) {
|
||||
return <Slide {...props} direction="up" />;
|
||||
}
|
||||
|
||||
function TransitionSlideRight(props) {
|
||||
return <Slide {...props} direction="right" />;
|
||||
}
|
||||
|
||||
function TransitionSlideDown(props) {
|
||||
return <Slide {...props} direction="down" />;
|
||||
}
|
||||
|
||||
function GrowTransition(props) {
|
||||
return <Grow {...props} />;
|
||||
}
|
||||
|
||||
// animation options
|
||||
const animation = {
|
||||
SlideLeft: TransitionSlideLeft,
|
||||
SlideUp: TransitionSlideUp,
|
||||
SlideRight: TransitionSlideRight,
|
||||
SlideDown: TransitionSlideDown,
|
||||
Grow: GrowTransition,
|
||||
Fade
|
||||
};
|
||||
|
||||
// ==============================|| SNACKBAR ||============================== //
|
||||
|
||||
const Snackbar = () => {
|
||||
const snackbar = useSelector((state) => state.snackbar);
|
||||
const { actionButton, anchorOrigin, alert, close, message, open, transition, variant } = snackbar;
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === 'clickaway') {
|
||||
return;
|
||||
}
|
||||
dispatch(closeSnackbar());
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* default snackbar */}
|
||||
{variant === 'default' && (
|
||||
<MuiSnackbar
|
||||
anchorOrigin={anchorOrigin}
|
||||
open={open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
message={message}
|
||||
TransitionComponent={animation[transition]}
|
||||
action={
|
||||
<>
|
||||
<Button color="secondary" size="small" onClick={handleClose}>
|
||||
UNDO
|
||||
</Button>
|
||||
<IconButton size="small" aria-label="close" color="inherit" onClick={handleClose} sx={{ mt: 0.25 }}>
|
||||
<CloseOutlined />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* alert snackbar */}
|
||||
{variant === 'alert' && (
|
||||
<MuiSnackbar
|
||||
TransitionComponent={animation[transition]}
|
||||
anchorOrigin={anchorOrigin}
|
||||
open={open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert
|
||||
variant={alert.variant}
|
||||
color={alert.color}
|
||||
action={
|
||||
<>
|
||||
{actionButton !== false && (
|
||||
<Button color={alert.color} size="small" onClick={handleClose}>
|
||||
UNDO
|
||||
</Button>
|
||||
)}
|
||||
{close !== false && (
|
||||
<IconButton
|
||||
sx={{ mt: 0.25 }}
|
||||
size="small"
|
||||
aria-label="close"
|
||||
variant="contained"
|
||||
color={alert.color}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<CloseOutlined />
|
||||
</IconButton>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
sx={{
|
||||
...(alert.variant === 'outlined' && {
|
||||
bgcolor: 'grey.0'
|
||||
})
|
||||
}}
|
||||
>
|
||||
{message}
|
||||
</Alert>
|
||||
</MuiSnackbar>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Snackbar;
|
||||
67
src/components/@extended/Tooltip.js
Normal file
67
src/components/@extended/Tooltip.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import { Box, tooltipClasses, Tooltip as MuiTooltip } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import getColors from 'utils/getColors';
|
||||
|
||||
// ==============================|| TOOLTIP - VARIANT ||============================== //
|
||||
|
||||
function getVariantStyle({ color, theme, labelColor }) {
|
||||
const colors = getColors(theme, color);
|
||||
const { main, contrastText } = colors;
|
||||
let colorValue = color ? color : '';
|
||||
|
||||
if (['primary', 'secondary', 'info', 'success', 'warning', 'error'].includes(colorValue)) {
|
||||
return {
|
||||
[`& .${tooltipClasses.tooltip}`]: {
|
||||
backgroundColor: main,
|
||||
color: labelColor ? labelColor : contrastText
|
||||
},
|
||||
[`& .${tooltipClasses.arrow}`]: {
|
||||
color: main
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
[`& .${tooltipClasses.tooltip}`]: {
|
||||
backgroundColor: colorValue,
|
||||
color: labelColor ? labelColor : contrastText,
|
||||
boxShadow: theme.shadows[1]
|
||||
},
|
||||
[`& .${tooltipClasses.arrow}`]: {
|
||||
color: colorValue
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| STYLED - TOOLTIP COLOR ||============================== //
|
||||
|
||||
const TooltipStyle = styled(({ className, ...props }) => <MuiTooltip {...props} classes={{ popper: className }} />, {
|
||||
shouldForwardProp: (prop) => prop !== 'color' && prop !== 'labelColor'
|
||||
})(({ theme, color, labelColor }) => ({
|
||||
...(color && getVariantStyle({ color, theme, labelColor }))
|
||||
}));
|
||||
|
||||
// ==============================|| EXTENDED - TOOLTIP ||============================== //
|
||||
|
||||
export default function CustomTooltip({ children, arrow, labelColor = '', ...rest }) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Box display="flex">
|
||||
<TooltipStyle arrow={arrow} {...rest} theme={theme} labelColor={labelColor}>
|
||||
{children}
|
||||
</TooltipStyle>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
CustomTooltip.propTypes = {
|
||||
children: PropTypes.element,
|
||||
arrow: PropTypes.bool,
|
||||
labelColor: PropTypes.string,
|
||||
rest: PropTypes.array
|
||||
};
|
||||
116
src/components/@extended/Transitions.js
Normal file
116
src/components/@extended/Transitions.js
Normal file
@@ -0,0 +1,116 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { Collapse, Fade, Box, Grow, Slide, Zoom } from '@mui/material';
|
||||
|
||||
// ==============================|| TRANSITIONS ||============================== //
|
||||
|
||||
const Transitions = forwardRef(({ children, position = 'top-left', type = 'grow', direction = 'up', ...others }, ref) => {
|
||||
let positionSX = {
|
||||
transformOrigin: '0 0 0'
|
||||
};
|
||||
|
||||
switch (position) {
|
||||
case 'top-right':
|
||||
positionSX = {
|
||||
transformOrigin: 'top right'
|
||||
};
|
||||
break;
|
||||
case 'top':
|
||||
positionSX = {
|
||||
transformOrigin: 'top'
|
||||
};
|
||||
break;
|
||||
case 'bottom-left':
|
||||
positionSX = {
|
||||
transformOrigin: 'bottom left'
|
||||
};
|
||||
break;
|
||||
case 'bottom-right':
|
||||
positionSX = {
|
||||
transformOrigin: 'bottom right'
|
||||
};
|
||||
break;
|
||||
case 'bottom':
|
||||
positionSX = {
|
||||
transformOrigin: 'bottom'
|
||||
};
|
||||
break;
|
||||
case 'top-left':
|
||||
default:
|
||||
positionSX = {
|
||||
transformOrigin: '0 0 0'
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box ref={ref}>
|
||||
{type === 'grow' && (
|
||||
<Grow
|
||||
{...others}
|
||||
timeout={{
|
||||
appear: 0,
|
||||
enter: 150,
|
||||
exit: 150
|
||||
}}
|
||||
>
|
||||
<Box sx={positionSX}>{children}</Box>
|
||||
</Grow>
|
||||
)}
|
||||
|
||||
{type === 'collapse' && (
|
||||
<Collapse {...others} sx={positionSX}>
|
||||
{children}
|
||||
</Collapse>
|
||||
)}
|
||||
|
||||
{type === 'fade' && (
|
||||
<Fade
|
||||
{...others}
|
||||
timeout={{
|
||||
appear: 0,
|
||||
enter: 300,
|
||||
exit: 150
|
||||
}}
|
||||
>
|
||||
<Box sx={positionSX}>{children}</Box>
|
||||
</Fade>
|
||||
)}
|
||||
|
||||
{type === 'slide' && (
|
||||
<Slide
|
||||
{...others}
|
||||
timeout={{
|
||||
appear: 0,
|
||||
enter: 150,
|
||||
exit: 150
|
||||
}}
|
||||
direction={direction}
|
||||
>
|
||||
<Box sx={positionSX}>{children}</Box>
|
||||
</Slide>
|
||||
)}
|
||||
|
||||
{type === 'zoom' && (
|
||||
<Zoom {...others}>
|
||||
<Box sx={positionSX}>{children}</Box>
|
||||
</Zoom>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
Transitions.propTypes = {
|
||||
children: PropTypes.node,
|
||||
type: PropTypes.oneOf(['grow', 'fade', 'collapse', 'slide', 'zoom']),
|
||||
position: PropTypes.oneOf(['top-left', 'top-right', 'top', 'bottom-left', 'bottom-right', 'bottom']),
|
||||
direction: PropTypes.oneOf(['up', 'down', 'left', 'right'])
|
||||
};
|
||||
|
||||
export default Transitions;
|
||||
|
||||
export const PopupTransition = forwardRef(function Transition(props, ref) {
|
||||
return <Zoom ref={ref} timeout={200} {...props} />;
|
||||
});
|
||||
32
src/components/@extended/progress/CircularWithLabel.js
Normal file
32
src/components/@extended/progress/CircularWithLabel.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, CircularProgress, Typography } from '@mui/material';
|
||||
|
||||
// ==============================|| PROGRESS - CIRCULAR LABEL ||============================== //
|
||||
|
||||
export default function CircularWithLabel({ value, ...others }) {
|
||||
return (
|
||||
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
|
||||
<CircularProgress variant="determinate" value={value} {...others} />
|
||||
<Box
|
||||
sx={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" component="div" color="text.secondary">{`${Math.round(value)}%`}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
CircularWithLabel.propTypes = {
|
||||
value: PropTypes.number
|
||||
};
|
||||
65
src/components/@extended/progress/CircularWithPath.js
Normal file
65
src/components/@extended/progress/CircularWithPath.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, CircularProgress, Typography, circularProgressClasses } from '@mui/material';
|
||||
|
||||
// ==============================|| PROGRESS - CIRCULAR PATH ||============================== //
|
||||
|
||||
export default function CircularWithPath({ value, size, variant, thickness, showLabel, pathColor, sx, ...others }) {
|
||||
return (
|
||||
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
sx={{ color: pathColor ? pathColor : 'grey.200' }}
|
||||
size={size}
|
||||
thickness={thickness}
|
||||
{...others}
|
||||
value={100}
|
||||
/>
|
||||
{showLabel && (
|
||||
<Box
|
||||
sx={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" component="div" color="text.secondary">
|
||||
{value ? `${Math.round(value)}%` : '0%'}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<CircularProgress
|
||||
variant={variant}
|
||||
sx={{
|
||||
...sx,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
[`& .${circularProgressClasses.circle}`]: {
|
||||
strokeLinecap: 'round'
|
||||
}
|
||||
}}
|
||||
size={size}
|
||||
thickness={thickness}
|
||||
value={value}
|
||||
{...others}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
CircularWithPath.propTypes = {
|
||||
value: PropTypes.number,
|
||||
size: PropTypes.number,
|
||||
variant: PropTypes.string,
|
||||
thickness: PropTypes.number,
|
||||
showLabel: PropTypes.bool,
|
||||
pathColor: PropTypes.string,
|
||||
sx: PropTypes.array,
|
||||
others: PropTypes.array
|
||||
};
|
||||
22
src/components/@extended/progress/LinearWithIcon.js
Normal file
22
src/components/@extended/progress/LinearWithIcon.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, LinearProgress } from '@mui/material';
|
||||
|
||||
// ==============================|| PROGRESS - LINEAR ICON ||============================== //
|
||||
|
||||
export default function LinearWithIcon({ icon, value, ...others }) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box sx={{ width: '100%', mr: 1 }}>
|
||||
<LinearProgress variant="determinate" value={value} {...others} />
|
||||
</Box>
|
||||
<Box sx={{ minWidth: 35 }}>{icon}</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
LinearWithIcon.propTypes = {
|
||||
icon: PropTypes.node,
|
||||
value: PropTypes.number
|
||||
};
|
||||
23
src/components/@extended/progress/LinearWithLabel.js
Normal file
23
src/components/@extended/progress/LinearWithLabel.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, LinearProgress, Typography } from '@mui/material';
|
||||
|
||||
// ==============================|| PROGRESS - LINEAR WITH LABEL ||============================== //
|
||||
|
||||
export default function LinearWithLabel({ value, ...others }) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box sx={{ width: '100%', mr: 1 }}>
|
||||
<LinearProgress variant="determinate" value={value} {...others} />
|
||||
</Box>
|
||||
<Box sx={{ minWidth: 35 }}>
|
||||
<Typography variant="body2" color="text.secondary">{`${Math.round(value)}%`}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
LinearWithLabel.propTypes = {
|
||||
value: PropTypes.number
|
||||
};
|
||||
Reference in New Issue
Block a user