Files

78 lines
2.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Hoover — components/toast.js
*
* ToastContainer component that renders queued toast notifications.
* Uses the toast/dismissToast state from api.js.
*
* Long messages (>200 chars or containing newlines) render compact —
* first line with an ellipsis — plus a "Details" button that opens a
* modal with the full text. Dismissal is only via the × button;
* hovering the toast pauses its auto-dismiss timer.
*/
import { h } from '../vdom.js';
import { _toasts, dismissToast } from '../api.js';
import { openModal } from './modal.js';
/** Messages longer than this (or containing newlines) render compact. */
const _LONG_MESSAGE_CHARS = 200;
function _isLong(message) {
return message.length > _LONG_MESSAGE_CHARS || message.includes('\n');
}
function _firstLine(message) {
return message.split('\n')[0].trim();
}
function _showDetails(t) {
openModal(
h('div', null,
h('h2', { class: 'modal-title' }, 'Details'),
h('div', { class: 'modal-body' },
h('pre', { class: 'toast-details-msg' }, t.message),
),
),
);
}
/**
* Render all pending toast notifications.
*
* @returns {VNode}
*/
export function ToastContainer() {
if (!_toasts.length) return h('#text', '');
const clsMap = {
info: 'toast-info',
success: 'toast-success',
error: 'toast-error',
warning: 'toast-warning',
};
return h('div', { class: 'toast' },
..._toasts.map(t => {
const long = _isLong(t.message);
return h('div', {
class: `toast-message ${clsMap[t.type] || clsMap.info}`,
'on:mouseover': () => { t.hovered = true; },
'on:mouseout': () => { t.hovered = false; },
},
h('span', { class: 'toast-text' + (long ? ' toast-text-long' : '') },
long ? _firstLine(t.message) : t.message),
h('div', { class: 'toast-actions' },
long ? h('button', {
class: 'toast-btn toast-details',
'on:click': (e) => { e.stopPropagation(); _showDetails(t); },
}, 'Details') : null,
h('button', {
class: 'toast-btn toast-close',
'on:click': (e) => { e.stopPropagation(); dismissToast(t.id); },
}, '\u00d7'),
),
);
}),
);
}