0 directories, 46 files

util

Home / tinai / util
/**
 * Minimal notification stack anchored to the bottom center of the screen, above
 * the footer. Each notification shows for 1.5 seconds and is then removed.
 * Items are tracked in a Map so multiple notifications stack up and clear
 * independently; the footer bell is visible while at least one is displayed.
 */

const DISPLAY_MS = 1500;
const FADE_MS = 200;

/** @type {Map<string, {el: HTMLElement, timer: number}>} */
const items = new Map();
let nextId = 1;

/**
 * Shows a notification in the stack; it is removed automatically after 1.5 seconds.
 * @param {string} text - Notification text.
 */
export function showNotification(text) {
	const container = ensureContainer();
	const bell = ensureBell();
	const id = `notification-${nextId++}`;

	const el = document.createElement('div');
	el.className = 'div-notification-item';
	el.textContent = text;
	container.appendChild(el);

	const timer = window.setTimeout(() => removeNotification(id), DISPLAY_MS);
	items.set(id, { el: el, timer: timer });
	bell.hidden = false;
}

/**
 * Removes one notification and updates the footer bell.
 * @param {string} id - Notification id.
 */
function removeNotification(id) {
	const item = items.get(id);
	if (!item) {
		return;
	}
	window.clearTimeout(item.timer);
	items.delete(id);
	const bell = ensureBell();
	bell.hidden = items.size === 0;
	item.el.classList.add('is-fading-out');
	window.setTimeout(() => item.el.remove(), FADE_MS);
}

/**
 * Returns the notification stack container, creating it on first use and
 * re-anchoring it above the footer.
 * @returns {HTMLElement} The stack container.
 */
function ensureContainer() {
	let container = document.getElementById('id-notification-stack');
	if (!container) {
		container = document.createElement('div');
		container.id = 'id-notification-stack';
		container.className = 'div-notification-stack';
		document.body.appendChild(container);
	}
	const footer = document.querySelector('.div-structure-footer');
	container.style.bottom = footer ? (footer.offsetHeight + 12) + 'px' : '2em';
	return container;
}

/**
 * Returns the footer bell element, creating it if the footer lacks one.
 * @returns {HTMLElement} The bell element.
 */
function ensureBell() {
	let bell = document.getElementById('id-span-footer-bell');
	if (!bell) {
		bell = document.createElement('span');
		bell.id = 'id-span-footer-bell';
		bell.className = 'span-footer-bell as-icon';
		bell.textContent = '🔔';
		bell.hidden = true;
		document.querySelector('.div-structure-footer .is-center')?.appendChild(bell);
	}
	return bell;
}
🌐
notification-stack.js ×
Type: Web, text/plain
2.50 Kilobytes
Last Modified 2026-11-04 09:48:28
⬇ Download File