baseline
This commit is contained in:
89
web/js/components/app-async-flash.js
Normal file
89
web/js/components/app-async-flash.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Async Flash Messages & Loading State
|
||||
* Renders flash messages into #async-messages for JS-triggered notifications
|
||||
* Provides loading cursor state management
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set global loading state (cursor + pointer-events)
|
||||
* @param {boolean} loading - Whether to show loading state
|
||||
*/
|
||||
export function setLoading(loading) {
|
||||
if (loading) {
|
||||
document.body.classList.add('is-loading');
|
||||
} else {
|
||||
document.body.classList.remove('is-loading');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an async function with loading state
|
||||
* @param {Function} fn - Async function to execute
|
||||
* @returns {Promise<any>} - Result of the function
|
||||
*/
|
||||
export async function withLoading(fn) {
|
||||
setLoading(true);
|
||||
try {
|
||||
return await fn();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
const defaultTimeouts = {
|
||||
success: 10000,
|
||||
info: 10000,
|
||||
warning: 10000,
|
||||
error: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Show an async flash message
|
||||
* @param {string} type - Message type: 'success', 'info', 'warning', 'error'
|
||||
* @param {string} message - The message text
|
||||
* @param {number} [timeout] - Auto-dismiss timeout in ms (0 = no auto-dismiss)
|
||||
*/
|
||||
export function showAsyncFlash(type, message, timeout) {
|
||||
const container = document.getElementById('async-messages');
|
||||
if (!container) {
|
||||
console.warn('async-messages container not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const effectiveTimeout = timeout ?? defaultTimeouts[type] ?? 5000;
|
||||
|
||||
const notice = document.createElement('div');
|
||||
notice.className = 'notice';
|
||||
notice.setAttribute('data-variant', type);
|
||||
|
||||
const messageSpan = document.createElement('span');
|
||||
messageSpan.textContent = message;
|
||||
notice.appendChild(messageSpan);
|
||||
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.type = 'button';
|
||||
closeButton.className = 'contrast outline small';
|
||||
closeButton.innerHTML = '<i class="bi bi-x"></i>';
|
||||
closeButton.addEventListener('click', () => notice.remove());
|
||||
notice.appendChild(closeButton);
|
||||
|
||||
container.appendChild(notice);
|
||||
|
||||
if (effectiveTimeout > 0) {
|
||||
notice.style.setProperty('--flash-timeout', `${effectiveTimeout}ms`);
|
||||
notice.classList.add('flash-timed');
|
||||
setTimeout(() => notice.remove(), effectiveTimeout);
|
||||
}
|
||||
|
||||
return notice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all async flash messages
|
||||
*/
|
||||
export function clearAsyncFlash() {
|
||||
const container = document.getElementById('async-messages');
|
||||
if (container) {
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user