72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { Show, createEffect, createSignal, onCleanup } from "solid-js"
|
|
import { toastMessage, toastVariant, setToastMessage } from "@/lib/state"
|
|
|
|
export default function Toast() {
|
|
const [visible, setVisible] = createSignal(false)
|
|
|
|
let hideTimer: number | undefined
|
|
let clearTimer: number | undefined
|
|
let rafOne: number | undefined
|
|
let rafTwo: number | undefined
|
|
|
|
function clearTimers() {
|
|
if (hideTimer) window.clearTimeout(hideTimer)
|
|
if (clearTimer) window.clearTimeout(clearTimer)
|
|
if (rafOne) window.cancelAnimationFrame(rafOne)
|
|
if (rafTwo) window.cancelAnimationFrame(rafTwo)
|
|
hideTimer = undefined
|
|
clearTimer = undefined
|
|
rafOne = undefined
|
|
rafTwo = undefined
|
|
}
|
|
|
|
createEffect(() => {
|
|
const message = toastMessage()?.trim()
|
|
clearTimers()
|
|
|
|
if (!message) {
|
|
setVisible(false)
|
|
return
|
|
}
|
|
|
|
setVisible(false)
|
|
rafOne = window.requestAnimationFrame(() => {
|
|
rafTwo = window.requestAnimationFrame(() => {
|
|
setVisible(true)
|
|
rafOne = undefined
|
|
rafTwo = undefined
|
|
})
|
|
})
|
|
|
|
hideTimer = window.setTimeout(() => {
|
|
setVisible(false)
|
|
clearTimer = window.setTimeout(() => {
|
|
setToastMessage("")
|
|
clearTimer = undefined
|
|
}, 250)
|
|
hideTimer = undefined
|
|
}, 10_000)
|
|
})
|
|
|
|
onCleanup(() => {
|
|
clearTimers()
|
|
})
|
|
|
|
return (
|
|
<Show when={toastMessage()}>
|
|
<div
|
|
role="alert"
|
|
class="fixed bottom-4 right-4 z-50 max-w-md rounded-xl border px-4 py-3 text-base shadow-lg transition-all duration-400 ease-out"
|
|
classList={{
|
|
"translate-y-0 opacity-100 scale-100": visible(),
|
|
"translate-y-3 opacity-0 scale-95": !visible(),
|
|
"border-red-200 bg-red-50 text-red-700": toastVariant() === "error",
|
|
"border-green-200 bg-green-50 text-green-700": toastVariant() === "success",
|
|
}}
|
|
>
|
|
{toastMessage()}
|
|
</div>
|
|
</Show>
|
|
)
|
|
}
|