Skip to content

Commit b0da5d7

Browse files
authored
Merge pull request #314 from kbss-cvut/progression-animation
Implement progression and sliding animation
2 parents 9501136 + 47856c1 commit b0da5d7

File tree

1 file changed

+70
-7
lines changed

1 file changed

+70
-7
lines changed

src/components/message/Message.jsx

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,85 @@ import { dismissMessage } from "../../actions/MessageActions";
55
import { useI18n } from "../../hooks/useI18n";
66
import { MESSAGE_DURATION } from "../../constants/DefaultConstants";
77
import PropTypes from "prop-types";
8+
import { useCallback, useEffect } from "react";
89

910
export const Message = ({ message }) => {
1011
const { formatMessage } = useI18n();
1112
const dispatch = useDispatch();
12-
const dismiss = React.useCallback(() => dispatch(dismissMessage(message)), [message, dispatch]);
13-
React.useEffect(() => {
13+
const [progress, setProgress] = React.useState(0);
14+
const [isVisible, setIsVisible] = React.useState(false);
15+
16+
const dismiss = useCallback(() => dispatch(dismissMessage(message)), [message, dispatch]);
17+
18+
useEffect(() => {
19+
requestAnimationFrame(() => {
20+
setIsVisible(true);
21+
});
22+
23+
const startTime = Date.now();
1424
const timer = setTimeout(() => {
15-
dismiss();
25+
setIsVisible(false);
26+
27+
setTimeout(() => {
28+
dismiss();
29+
}, 400);
1630
}, MESSAGE_DURATION);
17-
return () => clearTimeout(timer);
31+
32+
const progressInterval = setInterval(() => {
33+
const elapsed = Date.now() - startTime;
34+
const newProgress = Math.min((elapsed / MESSAGE_DURATION) * 100, 100);
35+
setProgress(newProgress);
36+
}, 50);
37+
38+
return () => {
39+
clearTimeout(timer);
40+
clearInterval(progressInterval);
41+
};
1842
}, [dismiss, message]);
1943

44+
const size = 24;
45+
const strokeWidth = 2;
46+
const radius = (size - strokeWidth) / 2;
47+
const circumference = 2 * Math.PI * radius;
48+
const offset = circumference - (progress / 100) * circumference;
49+
2050
return (
21-
<Alert variant={message.type} onClose={dismiss} dismissible={true}>
22-
{message.messageId ? formatMessage(message.messageId, message.values) : message.message}
23-
</Alert>
51+
<div
52+
style={{
53+
transform: isVisible ? "translateX(0)" : "translateX(100%)",
54+
opacity: isVisible ? 1 : 0,
55+
transition: "transform 0.4s ease-out, opacity 0.4s ease-out",
56+
}}
57+
>
58+
<Alert variant={message.type} onClose={dismiss} dismissible={true}>
59+
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
60+
<svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
61+
<circle
62+
cx={size / 2}
63+
cy={size / 2}
64+
r={radius}
65+
fill="none"
66+
stroke="currentColor"
67+
strokeWidth={strokeWidth}
68+
opacity={0.2}
69+
/>
70+
<circle
71+
cx={size / 2}
72+
cy={size / 2}
73+
r={radius}
74+
fill="none"
75+
stroke="currentColor"
76+
strokeWidth={strokeWidth}
77+
strokeDasharray={circumference}
78+
strokeDashoffset={offset}
79+
strokeLinecap="round"
80+
style={{ transition: "stroke-dashoffset 0.05s linear" }}
81+
/>
82+
</svg>
83+
<span>{message.messageId ? formatMessage(message.messageId, message.values) : message.message}</span>
84+
</div>
85+
</Alert>
86+
</div>
2487
);
2588
};
2689

0 commit comments

Comments
 (0)