56 lines
1.3 KiB
TypeScript
56 lines
1.3 KiB
TypeScript
export {}
|
|
|
|
interface ToastOptions {
|
|
message: string
|
|
duration?: number
|
|
}
|
|
|
|
const toastContainer = (): HTMLElement => {
|
|
let container = document.getElementById('toast-container')
|
|
if (!container) {
|
|
container = document.createElement('div')
|
|
container.id = 'toast-container'
|
|
container.className = 'fixed bottom-4 right-4 z-100 flex flex-col gap-2'
|
|
document.body.appendChild(container)
|
|
}
|
|
return container
|
|
}
|
|
|
|
const showToast = ({ message, duration = 3000 }: ToastOptions): void => {
|
|
const container = toastContainer()
|
|
const template = document.getElementById('toast-template') as HTMLTemplateElement | null
|
|
|
|
if (!template) {
|
|
return
|
|
}
|
|
|
|
const toast = template.content.cloneNode(true) as HTMLElement
|
|
const messageEl = toast.querySelector('.toast-message')
|
|
const closeBtn = toast.querySelector('.toast-close')
|
|
|
|
if (messageEl) {
|
|
messageEl.textContent = message
|
|
}
|
|
|
|
closeBtn?.addEventListener('click', () => toast.remove())
|
|
|
|
container.appendChild(toast)
|
|
|
|
requestAnimationFrame(() => {
|
|
toast.classList.remove('translate-y-2', 'opacity-0')
|
|
})
|
|
|
|
setTimeout(() => {
|
|
toast.classList.add('translate-y-2', 'opacity-0')
|
|
setTimeout(() => toast.remove(), 300)
|
|
}, duration)
|
|
}
|
|
|
|
declare global {
|
|
interface Window {
|
|
showToast: typeof showToast
|
|
}
|
|
}
|
|
|
|
window.showToast = showToast
|