feat: implement new SnackBar design (#5515)

Closes #5383

## Light theme

<img width="905" alt="image"
src="https://github.com/twentyhq/twenty/assets/3098428/ab0683c5-ded3-420c-ace6-684d38794a2d">

## Dark theme

<img width="903" alt="image"
src="https://github.com/twentyhq/twenty/assets/3098428/4e43ca35-438d-4ba0-8388-1f061c6ccfb0">
This commit is contained in:
Thaïs
2024-05-23 12:19:50 +02:00
committed by GitHub
parent 453525ca25
commit 8019ba8782
53 changed files with 485 additions and 552 deletions

View File

@ -1,110 +1,43 @@
import {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import { useTheme } from '@emotion/react';
import { useState } from 'react';
import styled from '@emotion/styled';
import { AnimationControls, motion, useAnimation } from 'framer-motion';
import { motion } from 'framer-motion';
export type ProgressBarProps = {
duration?: number;
delay?: number;
easing?: string;
barHeight?: number;
barColor?: string;
autoStart?: boolean;
className?: string;
color?: string;
value: number;
};
export type StyledBarProps = {
barHeight?: number;
className?: string;
};
export type ProgressBarControls = AnimationControls & {
start: () => Promise<any>;
pause: () => Promise<any>;
};
const StyledBar = styled.div<StyledBarProps>`
height: ${({ barHeight }) => barHeight}px;
height: ${({ theme }) => theme.spacing(2)};
overflow: hidden;
width: 100%;
`;
const StyledBarFilling = styled(motion.div)`
const StyledBarFilling = styled(motion.div)<{ color?: string }>`
background-color: ${({ color, theme }) => color ?? theme.font.color.primary};
height: 100%;
width: 100%;
`;
export const ProgressBar = forwardRef<ProgressBarControls, ProgressBarProps>(
(
{
duration = 3,
delay = 0,
easing = 'easeInOut',
barHeight = 24,
barColor,
autoStart = true,
className,
},
ref,
) => {
const theme = useTheme();
export const ProgressBar = ({ className, color, value }: ProgressBarProps) => {
const [initialValue] = useState(value);
const controls = useAnimation();
// eslint-disable-next-line @nx/workspace-no-state-useref
const startTimestamp = useRef<number>(0);
// eslint-disable-next-line @nx/workspace-no-state-useref
const remainingTime = useRef<number>(duration);
const start = useCallback(async () => {
startTimestamp.current = Date.now();
return controls.start({
scaleX: 0,
transition: {
duration: remainingTime.current / 1000, // convert ms to s for framer-motion
delay: delay / 1000, // likewise
ease: easing,
},
});
}, [controls, delay, easing]);
useImperativeHandle(ref, () => ({
...controls,
start: async () => {
return start();
},
pause: async () => {
const elapsed = Date.now() - startTimestamp.current;
remainingTime.current = remainingTime.current - elapsed;
return controls.stop();
},
}));
useEffect(() => {
if (autoStart) {
start();
}
}, [controls, delay, duration, easing, autoStart, start]);
return (
<StyledBar className={className} barHeight={barHeight}>
<StyledBarFilling
style={{
originX: 0,
// Seems like custom props are not well handled by react when used with framer-motion and emotion styled
backgroundColor: barColor ?? theme.color.gray80,
}}
initial={{ scaleX: 1 }}
animate={controls}
exit={{ scaleX: 0 }}
/>
</StyledBar>
);
},
);
return (
<StyledBar
className={className}
role="progressbar"
aria-valuenow={Math.ceil(value)}
>
<StyledBarFilling
initial={{ width: `${initialValue}%` }}
animate={{ width: `${value}%` }}
color={color}
transition={{ ease: 'linear' }}
/>
</StyledBar>
);
};