atproto explorer pdsls.dev
atproto tool

add toast slide animation

juli.ee 85a31a92 ed7cdacc

verified
Changed files
+34 -1
src
components
styles
+12 -1
src/components/notification.tsx
···
};
const [notifications, setNotifications] = createSignal<Notification[]>([]);
+
const [removingIds, setRemovingIds] = createSignal<Set<string>>(new Set());
export const addNotification = (notification: Omit<Notification, "id">) => {
const id = `notification-${Date.now()}-${Math.random()}`;
···
};
export const removeNotification = (id: string) => {
-
setNotifications(notifications().filter((n) => n.id !== id));
+
setRemovingIds(new Set([...removingIds(), id]));
+
setTimeout(() => {
+
setNotifications(notifications().filter((n) => n.id !== id));
+
setRemovingIds((ids) => {
+
const newIds = new Set(ids);
+
newIds.delete(id);
+
return newIds;
+
});
+
}, 250);
};
export const NotificationContainer = () => {
···
"border-blue-500 dark:border-blue-400": notification.type === "info",
"border-green-500 dark:border-green-400": notification.type === "success",
"border-red-500 dark:border-red-400": notification.type === "error",
+
"animate-[slideIn_0.25s_ease-in]": !removingIds().has(notification.id),
+
"animate-[slideOut_0.25s_ease-in]": removingIds().has(notification.id),
}}
onClick={() => removeNotification(notification.id)}
>
+22
src/styles/index.css
···
.ri--bluesky {
--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");
}
+
+
@keyframes slideIn {
+
0% {
+
transform: translateY(20px);
+
opacity: 0;
+
}
+
100% {
+
transform: translateY(0);
+
opacity: 1;
+
}
+
}
+
+
@keyframes slideOut {
+
0% {
+
transform: translateY(0);
+
opacity: 1;
+
}
+
100% {
+
transform: translateY(20px);
+
opacity: 0;
+
}
+
}