+12
-1
src/components/notification.tsx
+12
-1
src/components/notification.tsx
···
9
9
};
10
10
11
11
const [notifications, setNotifications] = createSignal<Notification[]>([]);
12
+
const [removingIds, setRemovingIds] = createSignal<Set<string>>(new Set());
12
13
13
14
export const addNotification = (notification: Omit<Notification, "id">) => {
14
15
const id = `notification-${Date.now()}-${Math.random()}`;
···
21
22
};
22
23
23
24
export const removeNotification = (id: string) => {
24
-
setNotifications(notifications().filter((n) => n.id !== id));
25
+
setRemovingIds(new Set([...removingIds(), id]));
26
+
setTimeout(() => {
27
+
setNotifications(notifications().filter((n) => n.id !== id));
28
+
setRemovingIds((ids) => {
29
+
const newIds = new Set(ids);
30
+
newIds.delete(id);
31
+
return newIds;
32
+
});
33
+
}, 250);
25
34
};
26
35
27
36
export const NotificationContainer = () => {
···
35
44
"border-blue-500 dark:border-blue-400": notification.type === "info",
36
45
"border-green-500 dark:border-green-400": notification.type === "success",
37
46
"border-red-500 dark:border-red-400": notification.type === "error",
47
+
"animate-[slideIn_0.25s_ease-in]": !removingIds().has(notification.id),
48
+
"animate-[slideOut_0.25s_ease-in]": removingIds().has(notification.id),
38
49
}}
39
50
onClick={() => removeNotification(notification.id)}
40
51
>
+22
src/styles/index.css
+22
src/styles/index.css
···
43
43
.ri--bluesky {
44
44
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 11.388c-.906-1.761-3.372-5.044-5.665-6.662c-2.197-1.55-3.034-1.283-3.583-1.033C2.116 3.978 2 4.955 2 5.528c0 .575.315 4.709.52 5.4c.68 2.28 3.094 3.05 5.32 2.803c-3.26.483-6.157 1.67-2.36 5.898c4.178 4.325 5.726-.927 6.52-3.59c.794 2.663 1.708 7.726 6.444 3.59c3.556-3.59.977-5.415-2.283-5.898c2.225.247 4.64-.523 5.319-2.803c.205-.69.52-4.825.52-5.399c0-.575-.116-1.55-.752-1.838c-.549-.248-1.386-.517-3.583 1.033c-2.293 1.621-4.76 4.904-5.665 6.664'/%3E%3C/svg%3E");
45
45
}
46
+
47
+
@keyframes slideIn {
48
+
0% {
49
+
transform: translateY(20px);
50
+
opacity: 0;
51
+
}
52
+
100% {
53
+
transform: translateY(0);
54
+
opacity: 1;
55
+
}
56
+
}
57
+
58
+
@keyframes slideOut {
59
+
0% {
60
+
transform: translateY(0);
61
+
opacity: 1;
62
+
}
63
+
100% {
64
+
transform: translateY(20px);
65
+
opacity: 0;
66
+
}
67
+
}