diff --git a/Software/MainBoard/rust/src_webpack/src/toast.ts b/Software/MainBoard/rust/src_webpack/src/toast.ts index 868788e..bca6b71 100644 --- a/Software/MainBoard/rust/src_webpack/src/toast.ts +++ b/Software/MainBoard/rust/src_webpack/src/toast.ts @@ -1,50 +1,60 @@ class ToastService { - private container: HTMLElement; - private stylesInjected = false; + private container: HTMLElement; + private stylesInjected = false; - constructor() { - this.container = document.getElementById('toast-container') as HTMLElement; - this.injectStyles(); + constructor() { + this.container = this.ensureContainer(); + this.injectStyles(); + } + + info(message: string, timeoutMs: number = 5000) { + const el = this.createToast(message, 'info'); + this.container.appendChild(el); + // Auto-dismiss after timeout + const timer = window.setTimeout(() => this.dismiss(el), timeoutMs); + // Dismiss on click immediately + el.addEventListener('click', () => { + window.clearTimeout(timer); + this.dismiss(el); + }); + } + + error(message: string) { + console.error(message); + const el = this.createToast(message, 'error'); + this.container.appendChild(el); + // Only dismiss on click + el.addEventListener('click', () => this.dismiss(el)); + } + + private dismiss(el: HTMLElement) { + if (!el.parentElement) return; + el.parentElement.removeChild(el); + } + + private createToast(message: string, type: 'info' | 'error'): HTMLElement { + const div = document.createElement('div'); + div.className = `toast ${type}`; + div.textContent = message; + div.setAttribute('role', 'status'); + div.setAttribute('aria-live', 'polite'); + return div; + } + + private ensureContainer(): HTMLElement { + let container = document.getElementById('toast-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'toast-container'; + document.body.appendChild(container); } + return container; + } - info(message: string, timeoutMs: number = 5000) { - const el = this.createToast(message, 'info'); - this.container.appendChild(el); - // Auto-dismiss after timeout - const timer = window.setTimeout(() => this.dismiss(el), timeoutMs); - // Dismiss on click immediately - el.addEventListener('click', () => { - window.clearTimeout(timer); - this.dismiss(el); - }); - } - - error(message: string) { - console.error(message); - const el = this.createToast(message, 'error'); - this.container.appendChild(el); - // Only dismiss on click - el.addEventListener('click', () => this.dismiss(el)); - } - - private dismiss(el: HTMLElement) { - if (!el.parentElement) return; - el.parentElement.removeChild(el); - } - - private createToast(message: string, type: 'info' | 'error'): HTMLElement { - const div = document.createElement('div'); - div.className = `toast ${type}`; - div.textContent = message; - div.setAttribute('role', 'status'); - div.setAttribute('aria-live', 'polite'); - return div; - } - - private injectStyles() { - if (this.stylesInjected) return; - const style = document.createElement('style'); - style.textContent = ` + private injectStyles() { + if (this.stylesInjected) return; + const style = document.createElement('style'); + style.textContent = ` #toast-container { position: fixed; top: 12px; @@ -76,9 +86,9 @@ class ToastService { border-left: 4px solid #dc3545; } `; - document.head.appendChild(style); - this.stylesInjected = true; - } + document.head.appendChild(style); + this.stylesInjected = true; + } } export const toast = new ToastService();