style.css: +93 lines — sidebar, view, tabs, toolbar, field (label on top), skeleton, snackbar, combobox classes. Font scale 13/14/16. icons.js (NEW): 10 inline-SVG Lucide icons (play, edit, trash, check, x, chevronDown, search, plus, rotateCw, cloud). stroke=currentColor. snackbar.js (NEW): showSnackbar(msg, type). bottom-right, 4s/8s auto-hide, stacking max 4, accessibility role=status aria-live=polite. index.html: include icons.js before utils.js
31 lines
1.1 KiB
JavaScript
31 lines
1.1 KiB
JavaScript
// snackbar.js — лёгкие уведомления (без зависимостей)
|
|
// showSnackbar(msg, type='info') — type: info, success, error
|
|
|
|
function showSnackbar(msg, type) {
|
|
type = type || 'info';
|
|
let container = document.getElementById('snackbar-container');
|
|
if (!container) {
|
|
container = document.createElement('div');
|
|
container.id = 'snackbar-container';
|
|
container.className = 'snackbar-container';
|
|
container.setAttribute('role', 'status');
|
|
container.setAttribute('aria-live', 'polite');
|
|
document.body.appendChild(container);
|
|
}
|
|
const el = document.createElement('div');
|
|
el.className = 'snackbar ' + type;
|
|
el.textContent = msg;
|
|
el.onclick = function() { el.remove(); };
|
|
container.appendChild(el);
|
|
|
|
// Limit stacking
|
|
const all = container.querySelectorAll('.snackbar');
|
|
if (all.length > 4) all[0].remove();
|
|
|
|
// Auto-hide: info/success 4s, error 8s
|
|
const delay = (type === 'error') ? 8000 : 4000;
|
|
setTimeout(function() {
|
|
if (el.parentNode) el.remove();
|
|
}, delay);
|
|
}
|