/** * Sistema de modales centralizado para reemplazar alert() nativos * Uso: * import { modal } from './lib/modal.js'; * modal.success("Guardado correctamente"); * modal.error("Error: " + e.message); * modal.info("Información importante"); * modal.warn("Advertencia"); * const ok = await modal.confirm("¿Estás seguro?"); */ const STYLES = ` .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(15, 23, 42, 0.45); backdrop-filter: blur(2px); display: flex; align-items: center; justify-content: center; z-index: 10000; animation: fadeIn 0.15s ease-out; font-family: var(--font-sans, system-ui); } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideIn { from { transform: translateY(-12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal-box { background: var(--panel, #ffffff); border-radius: var(--r-lg, 12px); padding: 24px; min-width: 320px; max-width: 480px; box-shadow: var(--shadow-lg, 0 12px 28px rgba(15,23,42,.10)); border: 1px solid var(--border, #e2e8f0); animation: slideIn 0.2s ease-out; } .modal-header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; } .modal-icon { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 700; flex-shrink: 0; } .modal-icon.success { background: var(--ok-soft, #d1fae5); color: var(--ok, #10b981); } .modal-icon.error { background: var(--err-soft, #fee2e2); color: var(--err, #ef4444); } .modal-icon.warn { background: var(--warn-soft, #fef3c7); color: var(--warn, #f59e0b); } .modal-icon.info { background: var(--accent-soft, #e0f2fe); color: var(--accent, #0ea5e9); } .modal-icon.confirm { background: var(--accent-soft, #e0f2fe); color: var(--accent-hover, #0284c7); } .modal-title { font-size: 16px; font-weight: 600; color: var(--text, #0f172a); margin: 0; letter-spacing: -0.01em; } .modal-message { color: var(--text-dim, #475569); font-size: 14px; line-height: 1.5; margin-bottom: 20px; word-break: break-word; } .modal-buttons { display: flex; gap: 8px; justify-content: flex-end; } .modal-btn { padding: 8px 16px; border-radius: var(--r-md, 10px); font-size: 13px; font-weight: 500; cursor: pointer; border: 1px solid transparent; transition: all 0.15s; font-family: inherit; } .modal-btn:focus-visible { outline: none; box-shadow: var(--focus-ring, 0 0 0 3px rgba(14,165,233,.3)); } .modal-btn.primary { background: var(--accent, #0ea5e9); color: var(--text-on-acc, #fff); } .modal-btn.primary:hover { background: var(--accent-hover, #0284c7); } .modal-btn.secondary { background: var(--panel, #fff); color: var(--text, #0f172a); border-color: var(--border-hi, #cbd5e1); } .modal-btn.secondary:hover { border-color: var(--accent, #0ea5e9); color: var(--accent-hover, #0284c7); } .modal-btn.danger { background: var(--err, #ef4444); color: #fff; } .modal-btn.danger:hover { filter: brightness(0.95); } `; // Inyectar estilos una sola vez let stylesInjected = false; function injectStyles() { if (stylesInjected) return; const style = document.createElement("style"); style.textContent = STYLES; document.head.appendChild(style); stylesInjected = true; } const ICONS = { success: "✓", error: "✕", warn: "!", info: "i", confirm: "?", }; const TITLES = { success: "Éxito", error: "Error", warn: "Advertencia", info: "Información", confirm: "Confirmar", }; function createModal({ type, message, showCancel = false, confirmText = "Aceptar", cancelText = "Cancelar" }) { injectStyles(); return new Promise((resolve) => { const overlay = document.createElement("div"); overlay.className = "modal-overlay"; const box = document.createElement("div"); box.className = "modal-box"; box.innerHTML = `