// Super objeto para todos los modales AXZ const axzModal = { // Inyectar estilos solo una vez _initStyles: function() { if (document.getElementById('axz_modal-styles')) return; const style = document.createElement('style'); style.id = 'axz_modal-styles'; style.textContent = ` .axz_modal-backdrop { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.13); z-index: 10000; display: flex; align-items: center; justify-content: center; animation: axz_modal_fadein 0.2s; } @keyframes axz_modal_fadein { from { opacity: 0; } to { opacity: 1; } } .axz_modal { background: #fff; border-radius: 0.7rem; box-shadow: 0 4px 32px rgba(0,0,0,0.13); min-width: 320px; max-width: 95vw; max-height: 90vh; padding: 2rem 2rem 1.5rem 2rem; position: relative; font-family: 'Segoe UI', Arial, sans-serif; animation: axz_modal_in 0.25s; } .axz_modal-info { border-top: 6px solid #0dcaf0; } .axz_modal-success { border-top: 6px solid #198754; } .axz_modal-warning { border-top: 6px solid #ffc107; } .axz_modal-error { border-top: 6px solid #dc3545; } .axz_modal-confirm { border-top: 6px solid #0d6efd; } @keyframes axz_modal_in { from { transform: translateY(-60px) scale(0.98); opacity: 0; } to { transform: translateY(0) scale(1); opacity: 1; } } .axz_modal-header { font-size: 1.3rem; font-weight: 600; margin-bottom: 1.2rem; display: flex; align-items: center; gap: 0.5rem; } .axz_modal-header.axz_info { color: #0dcaf0; } .axz_modal-header.axz_success { color: #198754; } .axz_modal-header.axz_warning { color: #ffc107; } .axz_modal-header.axz_error { color: #dc3545; } .axz_modal-header.axz_confirm { color: #0d6efd; } .axz_modal-close { position: absolute; top: 1.1rem; right: 1.3rem; background: none; border: none; font-size: 1.7rem; color: #888; cursor: pointer; transition: color 0.2s; } .axz_modal-close:hover { color: #0dcaf0; } .axz_modal-close.axz_error:hover { color: #dc3545; } .axz_modal-content { font-size: 1.08rem; margin-bottom: 1.5rem; color: #444; } .axz_modal-footer { text-align: right; margin-top: 0.5rem; } .axz_btn-info { background: #0dcaf0; color: #fff; border: none; border-radius: 0.3rem; padding: 0.5rem 1.2rem; font-size: 1rem; cursor: pointer; } .axz_btn-info:hover { background: #31d2f2; } .axz_btn-success { background: #198754; color: #fff; border: none; border-radius: 0.3rem; padding: 0.5rem 1.2rem; font-size: 1rem; cursor: pointer; } .axz_btn-success:hover { background: #157347; } .axz_btn-warning { background: #ffc107; color: #222; border: none; border-radius: 0.3rem; padding: 0.5rem 1.2rem; font-size: 1rem; cursor: pointer; } .axz_btn-warning:hover { background: #ffcd39; } .axz_btn-error { background: #dc3545; color: #fff; border: none; border-radius: 0.3rem; padding: 0.5rem 1.2rem; font-size: 1rem; cursor: pointer; } .axz_btn-error:hover { background: #bb2d3b; } .axz_btn-confirm { background: #0d6efd; color: #fff; border: none; border-radius: 0.3rem; padding: 0.5rem 1.2rem; font-size: 1rem; cursor: pointer; } .axz_btn-confirm:hover { background: #0b5ed7; } `; document.head.appendChild(style); }, show: function(type, message, title = '', options = {}) { this._initStyles(); this.remove(); // Iconos por tipo const icons = { info: 'ⓘ', success: '✓', warning: '⚠', error: '⛔', confirm: '❓' }; // Colores para botones por tipo const btnClass = { info: 'axz_btn-info', success: 'axz_btn-success', warning: 'axz_btn-warning', error: 'axz_btn-error', confirm: 'axz_btn-confirm' }; // Backdrop const backdrop = document.createElement('div'); backdrop.className = 'axz_modal-backdrop'; // Modal principal const modal = document.createElement('div'); modal.className = `axz_modal axz_modal-${type}`; // Botón cerrar (X) const closeBtnEl = document.createElement('button'); closeBtnEl.className = `axz_modal-close axz_${type}`; closeBtnEl.innerHTML = '×'; closeBtnEl.onclick = () => this.remove(); modal.appendChild(closeBtnEl); // Cabecera const header = document.createElement('div'); header.className = `axz_modal-header axz_${type}`; header.innerHTML = `${icons[type]} ${title || this.defaultTitle(type)}`; modal.appendChild(header); // Contenido const contentDiv = document.createElement('div'); contentDiv.className = 'axz_modal-content'; contentDiv.innerHTML = message; modal.appendChild(contentDiv); // Footer con botones const footer = document.createElement('div'); footer.className = 'axz_modal-footer'; if (type === 'confirm') { const cancelBtn = document.createElement('button'); cancelBtn.className = 'axz_btn-warning'; cancelBtn.textContent = options.cancelText || 'Cancelar'; cancelBtn.onclick = () => this.remove(); footer.appendChild(cancelBtn); const acceptBtn = document.createElement('button'); acceptBtn.className = btnClass.confirm; acceptBtn.textContent = options.acceptText || 'Aceptar'; acceptBtn.onclick = () => { this.remove(); if (typeof options.onAccept === 'function') options.onAccept(); }; footer.appendChild(acceptBtn); } else { const closeFooterBtn = document.createElement('button'); closeFooterBtn.className = btnClass[type]; closeFooterBtn.textContent = options.closeText || 'Cerrar'; closeFooterBtn.onclick = () => this.remove(); footer.appendChild(closeFooterBtn); } modal.appendChild(footer); backdrop.appendChild(modal); document.body.appendChild(backdrop); // Cerrar al hacer click fuera del modal backdrop.addEventListener('click', (e) => { if (e.target === backdrop) this.remove(); }); // Cerrar con ESC const escListener = (e) => { if (e.key === "Escape") { this.remove(); } }; document.addEventListener('keydown', escListener); this._escListener = escListener; }, remove: function() { const backdrop = document.querySelector('.axz_modal-backdrop'); if (backdrop) backdrop.remove(); if (this._escListener) { document.removeEventListener('keydown', this._escListener); this._escListener = null; } }, // Métodos rápidos info: function(msg, title, opts) { this.show('info', msg, title, opts); }, success: function(msg, title, opts) { this.show('success', msg, title, opts); }, warning: function(msg, title, opts) { this.show('warning', msg, title, opts); }, error: function(msg, title, opts) { this.show('error', msg, title, opts); }, confirm: function(msg, title, onAccept, opts={}) { this.show('confirm', msg, title, Object.assign({onAccept}, opts)); }, defaultTitle: function(type) { return { info: 'Información', success: 'Éxito', warning: 'Aviso', error: 'Error', confirm: 'Confirmar' }[type] || ''; } }; // Ejemplo de uso: // axzModal.info('Mensaje informativo', 'Título opcional'); // axzModal.success('¡Todo bien!', 'Éxito'); // axzModal.warning('¿Estás seguro?', 'Aviso'); // axzModal.error('Ha ocurrido un error.', 'Error'); // axzModal.confirm('¿Seguro?', 'Confirmar', function(){ alert('¡Confirmado!'); });