Update web/users.html
Browse files- web/users.html +101 -17
web/users.html
CHANGED
|
@@ -20,6 +20,70 @@
|
|
| 20 |
);
|
| 21 |
})();
|
| 22 |
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
</head>
|
| 24 |
|
| 25 |
<body class="vertical light">
|
|
@@ -392,27 +456,47 @@
|
|
| 392 |
}
|
| 393 |
|
| 394 |
function showAlert(type, message) {
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
const
|
| 403 |
-
<
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
</div>
|
|
|
|
|
|
|
| 409 |
`;
|
|
|
|
| 410 |
|
| 411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
|
| 413 |
-
setTimeout(() => {
|
| 414 |
-
|
| 415 |
-
|
|
|
|
|
|
|
|
|
|
| 416 |
}
|
| 417 |
</script>
|
| 418 |
|
|
|
|
| 20 |
);
|
| 21 |
})();
|
| 22 |
</script>
|
| 23 |
+
<style>
|
| 24 |
+
/* ── TOAST NOTIFICATIONS ─────────────────────────── */
|
| 25 |
+
#toast-container {
|
| 26 |
+
position: fixed;
|
| 27 |
+
bottom: 1.5rem;
|
| 28 |
+
right: 1.5rem;
|
| 29 |
+
z-index: 99999;
|
| 30 |
+
display: flex;
|
| 31 |
+
flex-direction: column;
|
| 32 |
+
gap: 0.6rem;
|
| 33 |
+
pointer-events: none;
|
| 34 |
+
}
|
| 35 |
+
.toast-notify {
|
| 36 |
+
display: flex;
|
| 37 |
+
align-items: flex-start;
|
| 38 |
+
gap: 12px;
|
| 39 |
+
min-width: 300px;
|
| 40 |
+
max-width: 380px;
|
| 41 |
+
padding: 14px 16px;
|
| 42 |
+
border-radius: 10px;
|
| 43 |
+
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
|
| 44 |
+
background: #fff;
|
| 45 |
+
border-left: 5px solid #ccc;
|
| 46 |
+
pointer-events: all;
|
| 47 |
+
opacity: 0;
|
| 48 |
+
transform: translateX(60px);
|
| 49 |
+
transition: opacity 0.3s ease, transform 0.3s ease;
|
| 50 |
+
position: relative;
|
| 51 |
+
overflow: hidden;
|
| 52 |
+
}
|
| 53 |
+
.toast-notify.show { opacity: 1; transform: translateX(0); }
|
| 54 |
+
.toast-notify.hide { opacity: 0; transform: translateX(60px); }
|
| 55 |
+
.toast-notify.toast-success { border-left-color: #28a745; }
|
| 56 |
+
.toast-notify.toast-error { border-left-color: #dc3545; }
|
| 57 |
+
.toast-notify.toast-warning { border-left-color: #ffc107; }
|
| 58 |
+
.toast-notify.toast-info { border-left-color: #17a2b8; }
|
| 59 |
+
.toast-icon { flex-shrink: 0; margin-top: 1px; }
|
| 60 |
+
.toast-success .toast-icon svg { stroke: #28a745; }
|
| 61 |
+
.toast-error .toast-icon svg { stroke: #dc3545; }
|
| 62 |
+
.toast-warning .toast-icon svg { stroke: #ffc107; }
|
| 63 |
+
.toast-info .toast-icon svg { stroke: #17a2b8; }
|
| 64 |
+
.toast-body { flex: 1; }
|
| 65 |
+
.toast-title { font-weight: 600; font-size: 0.875rem; margin-bottom: 2px; }
|
| 66 |
+
.toast-success .toast-title { color: #155724; }
|
| 67 |
+
.toast-error .toast-title { color: #721c24; }
|
| 68 |
+
.toast-warning .toast-title { color: #856404; }
|
| 69 |
+
.toast-info .toast-title { color: #0c5460; }
|
| 70 |
+
.toast-msg { font-size: 0.825rem; color: #555; line-height: 1.4; }
|
| 71 |
+
.toast-close {
|
| 72 |
+
background: none; border: none; font-size: 1rem;
|
| 73 |
+
line-height: 1; color: #aaa; cursor: pointer; padding: 0; flex-shrink: 0;
|
| 74 |
+
}
|
| 75 |
+
.toast-close:hover { color: #333; }
|
| 76 |
+
.toast-progress {
|
| 77 |
+
position: absolute;
|
| 78 |
+
bottom: 0; left: 0;
|
| 79 |
+
height: 3px;
|
| 80 |
+
border-radius: 0 0 0 10px;
|
| 81 |
+
}
|
| 82 |
+
.toast-success .toast-progress { background: #28a745; }
|
| 83 |
+
.toast-error .toast-progress { background: #dc3545; }
|
| 84 |
+
.toast-warning .toast-progress { background: #ffc107; }
|
| 85 |
+
.toast-info .toast-progress { background: #17a2b8; }
|
| 86 |
+
</style>
|
| 87 |
</head>
|
| 88 |
|
| 89 |
<body class="vertical light">
|
|
|
|
| 456 |
}
|
| 457 |
|
| 458 |
function showAlert(type, message) {
|
| 459 |
+
if (!document.getElementById('toast-container')) {
|
| 460 |
+
const container = document.createElement('div');
|
| 461 |
+
container.id = 'toast-container';
|
| 462 |
+
document.body.appendChild(container);
|
| 463 |
+
}
|
| 464 |
+
const container = document.getElementById('toast-container');
|
| 465 |
+
|
| 466 |
+
const icons = {
|
| 467 |
+
success: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',
|
| 468 |
+
error: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
|
| 469 |
+
warning: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
| 470 |
+
info: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>'
|
| 471 |
+
};
|
| 472 |
+
const titles = { success: 'Éxito', error: 'Error', warning: 'Advertencia', info: 'Información' };
|
| 473 |
+
const duration = type === 'error' ? 6000 : 4000;
|
| 474 |
+
|
| 475 |
+
const toast = document.createElement('div');
|
| 476 |
+
toast.className = `toast-notify toast-${type}`;
|
| 477 |
+
toast.innerHTML = `
|
| 478 |
+
<div class="toast-icon">${icons[type] || icons.info}</div>
|
| 479 |
+
<div class="toast-body">
|
| 480 |
+
<div class="toast-title">${titles[type] || 'Aviso'}</div>
|
| 481 |
+
<div class="toast-msg">${message}</div>
|
| 482 |
</div>
|
| 483 |
+
<button class="toast-close" onclick="this.closest('.toast-notify').remove()">×</button>
|
| 484 |
+
<div class="toast-progress" style="width:100%;transition:width ${duration}ms linear;"></div>
|
| 485 |
`;
|
| 486 |
+
container.appendChild(toast);
|
| 487 |
|
| 488 |
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
| 489 |
+
toast.classList.add('show');
|
| 490 |
+
const bar = toast.querySelector('.toast-progress');
|
| 491 |
+
if (bar) requestAnimationFrame(() => { bar.style.width = '0%'; });
|
| 492 |
+
}));
|
| 493 |
|
| 494 |
+
const timer = setTimeout(() => {
|
| 495 |
+
toast.classList.add('hide');
|
| 496 |
+
toast.addEventListener('transitionend', () => toast.remove(), { once: true });
|
| 497 |
+
}, duration);
|
| 498 |
+
|
| 499 |
+
toast.querySelector('.toast-close').addEventListener('click', () => clearTimeout(timer));
|
| 500 |
}
|
| 501 |
</script>
|
| 502 |
|