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:
@ -1,57 +1,39 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||
|
||||
import { useSnackBarManagerScopedStates } from '@/ui/feedback/snack-bar-manager/hooks/internal/useSnackBarManagerScopedStates';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
|
||||
import { SnackBar } from './SnackBar';
|
||||
|
||||
const StyledSnackBarContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 99999999;
|
||||
`;
|
||||
right: ${({ theme }) => theme.spacing(3)};
|
||||
bottom: ${({ theme }) => theme.spacing(3)};
|
||||
z-index: ${({ theme }) => theme.lastLayerZIndex};
|
||||
|
||||
const StyledSnackBarMotionContainer = styled(motion.div)`
|
||||
margin-right: ${({ theme }) => theme.spacing(3)};
|
||||
margin-top: ${({ theme }) => theme.spacing(3)};
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
bottom: ${({ theme }) => theme.spacing(16)};
|
||||
right: 50%;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
`;
|
||||
|
||||
const variants = {
|
||||
initial: {
|
||||
out: {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
y: 40,
|
||||
},
|
||||
animate: {
|
||||
in: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
},
|
||||
};
|
||||
|
||||
const reducedVariants = {
|
||||
initial: {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
},
|
||||
animate: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
y: -40,
|
||||
},
|
||||
};
|
||||
|
||||
export const SnackBarProvider = ({ children }: React.PropsWithChildren) => {
|
||||
const reducedMotion = useReducedMotion();
|
||||
|
||||
const { snackBarInternal } = useSnackBarManagerScopedStates();
|
||||
const { handleSnackBarClose } = useSnackBar();
|
||||
|
||||
@ -59,24 +41,26 @@ export const SnackBarProvider = ({ children }: React.PropsWithChildren) => {
|
||||
<>
|
||||
{children}
|
||||
<StyledSnackBarContainer>
|
||||
{snackBarInternal.queue.map(
|
||||
({ duration, icon, id, message, title, variant }) => (
|
||||
<StyledSnackBarMotionContainer
|
||||
key={id}
|
||||
variants={reducedMotion ? reducedVariants : variants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit="exit"
|
||||
transition={{ duration: 0.5 }}
|
||||
layout
|
||||
>
|
||||
<SnackBar
|
||||
{...{ duration, icon, message, title, variant }}
|
||||
onClose={() => handleSnackBarClose(id)}
|
||||
/>
|
||||
</StyledSnackBarMotionContainer>
|
||||
),
|
||||
)}
|
||||
<AnimatePresence>
|
||||
{snackBarInternal.queue.map(
|
||||
({ duration, icon, id, message, title, variant }) => (
|
||||
<motion.div
|
||||
key={id}
|
||||
variants={variants}
|
||||
initial="out"
|
||||
animate="in"
|
||||
exit="out"
|
||||
transition={{ duration: 0.5 }}
|
||||
layout
|
||||
>
|
||||
<SnackBar
|
||||
{...{ duration, icon, message, title, variant }}
|
||||
onClose={() => handleSnackBarClose(id)}
|
||||
/>
|
||||
</motion.div>
|
||||
),
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</StyledSnackBarContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user