toast 메시지 추가

alert 글로벌화
loading 글로벌화
This commit is contained in:
2025-04-25 15:33:21 +09:00
parent d2ac5b338e
commit 826459f304
50 changed files with 3211 additions and 2385 deletions

View File

@@ -0,0 +1,156 @@
import React, { useEffect, useState } from 'react';
import styled, { keyframes, css, createGlobalStyle } from 'styled-components';
import { alertTypes } from '../../../assets/data/types';
const ToastAlert = ({ id, message, type = alertTypes.info, position = 'top-center', onClose }) => {
const [isVisible, setIsVisible] = useState(false);
const handleClose = () => {
setIsVisible(true);
setTimeout(() => {
onClose();
}, 300);
};
return (
<ToastContainer $type={type} $position={position} $isVisible={isVisible}>
<IconWrapper $type={type}>
<ToastIcon type={type} />
</IconWrapper>
<ToastMessage>{message}</ToastMessage>
<CloseButton onClick={handleClose}>×</CloseButton>
</ToastContainer>
);
};
const ToastIcon = ({ type }) => {
switch (type) {
case alertTypes.success:
return <span></span>;
case alertTypes.error:
return <span></span>;
case alertTypes.warning:
return <span></span>;
case alertTypes.info:
default:
return <span></span>;
}
};
const fadeIn = keyframes`
from { opacity: 0; transform: translateX(-50%) translateY(-20px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
`;
const fadeOut = keyframes`
from { opacity: 1; transform: translateX(-50%) translateY(0); }
to { opacity: 0; transform: translateX(-50%) translateY(-20px); }
`;
// 위치에 따른 스타일 지정 함수
const getPositionStyle = (position) => {
const positions = {
'top-left': css`
top: 20px;
left: 20px;
`,
'top-center': css`
top: 20px;
left: 50%;
transform: translateX(-50%) translateY(0);
`,
'top-right': css`
top: 20px;
right: 20px;
`,
'bottom-left': css`
bottom: 20px;
left: 20px;
`,
'bottom-center': css`
bottom: 20px;
left: 50%;
transform: translateX(-50%) translateY(0);
`,
'bottom-right': css`
bottom: 20px;
right: 20px;
`
};
return positions[position] || positions['top-center'];
};
// 타입에 따른 스타일 지정 함수
const getTypeStyle = (type) => {
const types = {
[alertTypes.success]: css`
background-color: #d4edda;
color: #155724;
border-color: #c3e6cb;
`,
[alertTypes.error]: css`
background-color: #f8d7da;
color: #721c24;
border-color: #f5c6cb;
`,
[alertTypes.warning]: css`
background-color: #fff3cd;
color: #856404;
border-color: #ffeeba;
`,
[alertTypes.info]: css`
background-color: #d1ecf1;
color: #0c5460;
border-color: #bee5eb;
`
};
return types[type] || types['info'];
};
const ToastContainer = styled.div`
position: fixed;
display: flex;
align-items: center;
min-width: 250px;
max-width: 450px;
padding: 12px 15px;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 10px;
z-index: 9999;
animation: ${props => props.$isExiting ? fadeOut : fadeIn} 0.3s ease forwards;
${props => getPositionStyle(props.$position)}
${props => getTypeStyle(props.$type)}
`;
const IconWrapper = styled.div`
margin-right: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
`;
const ToastMessage = styled.div`
flex: 1;
padding-right: 10px;
`;
const CloseButton = styled.button`
background: transparent;
border: none;
font-size: 18px;
cursor: pointer;
color: inherit;
opacity: 0.7;
&:hover {
opacity: 1;
}
`;
export default ToastAlert;