cleanups
This commit is contained in:
93
Software/MainBoard/rust/src_webpack/src/toast.ts
Normal file
93
Software/MainBoard/rust/src_webpack/src/toast.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
class ToastService {
|
||||
private container: HTMLElement;
|
||||
private stylesInjected = false;
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
private injectStyles() {
|
||||
if (this.stylesInjected) return;
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
z-index: 9999;
|
||||
}
|
||||
.toast {
|
||||
max-width: 320px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.toast.info {
|
||||
background-color: #d4edda; /* green-ish */
|
||||
color: #155724;
|
||||
border-left: 4px solid #28a745;
|
||||
}
|
||||
.toast.error {
|
||||
background-color: #f8d7da; /* red-ish */
|
||||
color: #721c24;
|
||||
border-left: 4px solid #dc3545;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
this.stylesInjected = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const toast = new ToastService();
|
||||
Reference in New Issue
Block a user