Bloqueantes POS: modal-pago, ticket-termico, banner-cliente, fkeys-footer, columnas-costo-margen Componentes nuevos: calculadora-cambio, panel-deslizante, badge-cfdi, arbol-colapsable, tarjeta-metrica, grafica-barras, selector-periodo, etiqueta-codigo-barras Estados: estado-vacio, banner-offline, modal-confirmacion Páginas actualizadas: facturación, contabilidad, dashboard, configuración, reportes
478 lines
17 KiB
HTML
478 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="es" data-theme="industrial">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Nexus Autoparts — Modal de Confirmación</title>
|
||
<link rel="stylesheet" href="../tokens/tokens.css">
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body {
|
||
font-family: var(--font-body); background: var(--color-bg-base);
|
||
color: var(--color-text-primary); padding: var(--space-8);
|
||
transition: var(--transition-normal);
|
||
}
|
||
.theme-switcher {
|
||
position: sticky; top: 0; z-index: calc(var(--z-modal) + 10);
|
||
display: flex; gap: var(--space-2);
|
||
padding: var(--space-3) var(--space-4);
|
||
background: var(--color-bg-elevated);
|
||
border-bottom: 1px solid var(--color-border);
|
||
margin: calc(-1 * var(--space-8)); margin-bottom: var(--space-8);
|
||
}
|
||
.theme-switcher button {
|
||
padding: var(--space-2) var(--space-4);
|
||
border: 1px solid var(--color-border);
|
||
background: var(--color-bg-base); color: var(--color-text-primary);
|
||
border-radius: var(--radius-md); cursor: pointer;
|
||
font-family: var(--font-body); font-size: var(--text-body-sm);
|
||
transition: var(--transition-fast);
|
||
}
|
||
.theme-switcher button.active {
|
||
background: var(--color-primary); color: var(--color-text-inverse);
|
||
border-color: var(--color-primary);
|
||
}
|
||
h1 { font-family: var(--font-heading); font-size: var(--text-h2);
|
||
font-weight: var(--heading-weight-primary); margin-bottom: var(--space-2);
|
||
color: var(--color-text-accent); }
|
||
.subtitle { color: var(--color-text-muted); font-size: var(--text-body); margin-bottom: var(--space-8); }
|
||
section { margin-bottom: var(--space-10); }
|
||
section > h2 {
|
||
font-family: var(--font-heading); font-size: var(--text-h4);
|
||
font-weight: var(--heading-weight-secondary); color: var(--color-text-secondary);
|
||
margin-bottom: var(--space-4); padding-bottom: var(--space-2);
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
|
||
/* === Modal Component === */
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
@keyframes scaleIn {
|
||
from { opacity: 0; transform: translate(-50%, -50%) scale(0.92); }
|
||
to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
||
}
|
||
|
||
@keyframes fadeOut {
|
||
from { opacity: 1; }
|
||
to { opacity: 0; }
|
||
}
|
||
|
||
@keyframes scaleOut {
|
||
from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
||
to { opacity: 0; transform: translate(-50%, -50%) scale(0.92); }
|
||
}
|
||
|
||
.modal-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: var(--overlay-backdrop, rgba(0, 0, 0, 0.6));
|
||
z-index: var(--z-modal, 1000);
|
||
display: none;
|
||
animation: fadeIn 0.2s ease-out forwards;
|
||
}
|
||
|
||
.modal-overlay.active {
|
||
display: block;
|
||
}
|
||
|
||
.modal-overlay.closing {
|
||
animation: fadeOut 0.2s ease-in forwards;
|
||
}
|
||
|
||
.modal-dialog {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
z-index: calc(var(--z-modal, 1000) + 1);
|
||
background: var(--color-bg-elevated);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-xl);
|
||
box-shadow: var(--shadow-xl);
|
||
width: 90%;
|
||
max-width: 420px;
|
||
padding: var(--space-6);
|
||
text-align: center;
|
||
display: none;
|
||
animation: scaleIn 0.25s ease-out forwards;
|
||
}
|
||
|
||
.modal-dialog.active {
|
||
display: block;
|
||
}
|
||
|
||
.modal-dialog.closing {
|
||
animation: scaleOut 0.2s ease-in forwards;
|
||
}
|
||
|
||
.modal__icon {
|
||
width: 56px;
|
||
height: 56px;
|
||
border-radius: var(--radius-full);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 26px;
|
||
margin: 0 auto var(--space-4);
|
||
}
|
||
|
||
.modal__icon--warning {
|
||
background: var(--color-warning-light);
|
||
}
|
||
|
||
.modal__icon--info {
|
||
background: var(--color-primary-muted);
|
||
}
|
||
|
||
.modal__icon--danger {
|
||
background: var(--color-error-light);
|
||
}
|
||
|
||
.modal__title {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-h4);
|
||
font-weight: var(--heading-weight-primary);
|
||
color: var(--color-text-primary);
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
.modal__desc {
|
||
font-size: var(--text-body-sm);
|
||
color: var(--color-text-muted);
|
||
line-height: 1.6;
|
||
margin-bottom: var(--space-6);
|
||
padding: 0 var(--space-2);
|
||
}
|
||
|
||
.modal__actions {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal__btn {
|
||
flex: 1;
|
||
max-width: 180px;
|
||
padding: var(--space-3) var(--space-4);
|
||
font-family: var(--font-body);
|
||
font-size: var(--text-body-sm);
|
||
font-weight: 600;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: var(--transition-fast);
|
||
border: 1px solid transparent;
|
||
}
|
||
|
||
.modal__btn--secondary {
|
||
background: var(--btn-secondary-bg);
|
||
color: var(--btn-secondary-text);
|
||
border-color: var(--btn-secondary-border);
|
||
}
|
||
|
||
.modal__btn--secondary:hover {
|
||
background: var(--btn-secondary-bg-hover);
|
||
}
|
||
|
||
.modal__btn--primary {
|
||
background: var(--btn-primary-bg);
|
||
color: var(--btn-primary-text);
|
||
border-color: var(--btn-primary-border);
|
||
}
|
||
|
||
.modal__btn--primary:hover {
|
||
background: var(--btn-primary-bg-hover);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.modal__btn--danger {
|
||
background: var(--btn-danger-bg);
|
||
color: var(--btn-danger-text);
|
||
border-color: var(--btn-danger-bg);
|
||
}
|
||
|
||
.modal__btn--danger:hover {
|
||
opacity: 0.9;
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* === Demo trigger buttons === */
|
||
.trigger-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||
gap: var(--space-4);
|
||
}
|
||
|
||
.trigger-card {
|
||
background: var(--color-surface-1);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-5);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.trigger-card__label {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-body-sm);
|
||
color: var(--color-text-muted);
|
||
background: var(--color-bg-overlay);
|
||
padding: var(--space-1) var(--space-3);
|
||
border-radius: var(--radius-full);
|
||
}
|
||
|
||
.trigger-card__desc {
|
||
font-size: var(--text-body-sm);
|
||
color: var(--color-text-muted);
|
||
text-align: center;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.trigger-btn {
|
||
padding: var(--space-3) var(--space-5);
|
||
font-family: var(--font-body);
|
||
font-size: var(--text-body-sm);
|
||
font-weight: 600;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: var(--transition-fast);
|
||
border: 1px solid var(--color-border);
|
||
background: var(--color-bg-elevated);
|
||
color: var(--color-text-primary);
|
||
}
|
||
|
||
.trigger-btn:hover {
|
||
background: var(--color-surface-2);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.trigger-btn--warning { border-color: var(--color-warning); }
|
||
.trigger-btn--primary { border-color: var(--color-primary); }
|
||
.trigger-btn--danger { border-color: var(--color-error); }
|
||
|
||
/* === Static previews === */
|
||
.static-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
|
||
gap: var(--space-6);
|
||
}
|
||
|
||
.static-preview {
|
||
background: var(--color-surface-1);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-5);
|
||
}
|
||
|
||
.static-preview .variant-label {
|
||
font-family: var(--font-mono);
|
||
font-size: var(--text-body-sm);
|
||
color: var(--color-text-muted);
|
||
background: var(--color-bg-overlay);
|
||
padding: var(--space-1) var(--space-3);
|
||
border-radius: var(--radius-full);
|
||
display: inline-block;
|
||
margin-bottom: var(--space-4);
|
||
}
|
||
|
||
.static-modal {
|
||
background: var(--color-bg-elevated);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-xl);
|
||
box-shadow: var(--shadow-lg);
|
||
padding: var(--space-6);
|
||
text-align: center;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="theme-switcher">
|
||
<button class="active" onclick="document.documentElement.dataset.theme='industrial'; this.classList.add('active'); this.nextElementSibling.classList.remove('active')">🔧 Industrial</button>
|
||
<button onclick="document.documentElement.dataset.theme='modern'; this.classList.add('active'); this.previousElementSibling.classList.remove('active')">⚡ Moderno</button>
|
||
</div>
|
||
<h1>Modal de Confirmación</h1>
|
||
<p class="subtitle">Diálogos modales para confirmar acciones destructivas o importantes del sistema POS.</p>
|
||
|
||
<!-- ========== Interactive triggers ========== -->
|
||
<section>
|
||
<h2>Demo interactivo — Abrir modales</h2>
|
||
<div class="trigger-grid">
|
||
|
||
<div class="trigger-card">
|
||
<span class="trigger-card__label">a) Cancelar venta</span>
|
||
<p class="trigger-card__desc">Confirma antes de descartar una venta en curso</p>
|
||
<button class="trigger-btn trigger-btn--warning" onclick="openModal('cancelar-venta')">Abrir modal</button>
|
||
</div>
|
||
|
||
<div class="trigger-card">
|
||
<span class="trigger-card__label">b) Cerrar caja</span>
|
||
<p class="trigger-card__desc">Genera corte de caja al final del turno</p>
|
||
<button class="trigger-btn trigger-btn--primary" onclick="openModal('cerrar-caja')">Abrir modal</button>
|
||
</div>
|
||
|
||
<div class="trigger-card">
|
||
<span class="trigger-card__label">c) Ajustar stock</span>
|
||
<p class="trigger-card__desc">Ajusta inventario de múltiples artículos</p>
|
||
<button class="trigger-btn trigger-btn--warning" onclick="openModal('ajustar-stock')">Abrir modal</button>
|
||
</div>
|
||
|
||
<div class="trigger-card">
|
||
<span class="trigger-card__label">d) Cerrar periodo</span>
|
||
<p class="trigger-card__desc">Cierra periodo fiscal contable</p>
|
||
<button class="trigger-btn trigger-btn--danger" onclick="openModal('cerrar-periodo')">Abrir modal</button>
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ========== Static previews ========== -->
|
||
<section>
|
||
<h2>Variantes estáticas</h2>
|
||
<div class="static-grid">
|
||
|
||
<div class="static-preview">
|
||
<span class="variant-label">a) Cancelar venta</span>
|
||
<div class="static-modal">
|
||
<div class="modal__icon modal__icon--warning">⚠️</div>
|
||
<div class="modal__title">¿Cancelar venta?</div>
|
||
<div class="modal__desc">Se perderán los artículos agregados al ticket actual.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary">No, continuar</button>
|
||
<button class="modal__btn modal__btn--danger">Sí, cancelar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="static-preview">
|
||
<span class="variant-label">b) Cerrar caja</span>
|
||
<div class="static-modal">
|
||
<div class="modal__icon modal__icon--info">ℹ️</div>
|
||
<div class="modal__title">¿Cerrar caja?</div>
|
||
<div class="modal__desc">Se generará el corte de caja con total <strong style="color: var(--color-text-primary);">$15,800.00</strong></div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary">Cancelar</button>
|
||
<button class="modal__btn modal__btn--primary">Cerrar caja</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="static-preview">
|
||
<span class="variant-label">c) Ajustar stock</span>
|
||
<div class="static-modal">
|
||
<div class="modal__icon modal__icon--warning">⚠️</div>
|
||
<div class="modal__title">¿Ajustar stock?</div>
|
||
<div class="modal__desc">Se ajustarán <strong style="color: var(--color-text-primary);">5 artículos</strong> del inventario. Esta acción no se puede deshacer.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary">Cancelar</button>
|
||
<button class="modal__btn modal__btn--primary">Ajustar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="static-preview">
|
||
<span class="variant-label">d) Cerrar periodo fiscal</span>
|
||
<div class="static-modal">
|
||
<div class="modal__icon modal__icon--danger">🛑</div>
|
||
<div class="modal__title">¿Cerrar periodo fiscal?</div>
|
||
<div class="modal__desc">Se cerrará el periodo <strong style="color: var(--color-text-primary);">Marzo 2026</strong>. No podrás registrar pólizas en este periodo.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary">Cancelar</button>
|
||
<button class="modal__btn modal__btn--danger">Cerrar periodo</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ========== Actual Modal Overlays (hidden by default) ========== -->
|
||
|
||
<!-- a) Cancelar venta -->
|
||
<div class="modal-overlay" id="overlay-cancelar-venta" onclick="if(event.target===this) closeModal('cancelar-venta')"></div>
|
||
<div class="modal-dialog" id="modal-cancelar-venta">
|
||
<div class="modal__icon modal__icon--warning">⚠️</div>
|
||
<div class="modal__title">¿Cancelar venta?</div>
|
||
<div class="modal__desc">Se perderán los artículos agregados al ticket actual.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary" onclick="closeModal('cancelar-venta')">No, continuar</button>
|
||
<button class="modal__btn modal__btn--danger" onclick="closeModal('cancelar-venta')">Sí, cancelar</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- b) Cerrar caja -->
|
||
<div class="modal-overlay" id="overlay-cerrar-caja" onclick="if(event.target===this) closeModal('cerrar-caja')"></div>
|
||
<div class="modal-dialog" id="modal-cerrar-caja">
|
||
<div class="modal__icon modal__icon--info">ℹ️</div>
|
||
<div class="modal__title">¿Cerrar caja?</div>
|
||
<div class="modal__desc">Se generará el corte de caja con total <strong style="color: var(--color-text-primary);">$15,800.00</strong></div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary" onclick="closeModal('cerrar-caja')">Cancelar</button>
|
||
<button class="modal__btn modal__btn--primary" onclick="closeModal('cerrar-caja')">Cerrar caja</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- c) Ajustar stock -->
|
||
<div class="modal-overlay" id="overlay-ajustar-stock" onclick="if(event.target===this) closeModal('ajustar-stock')"></div>
|
||
<div class="modal-dialog" id="modal-ajustar-stock">
|
||
<div class="modal__icon modal__icon--warning">⚠️</div>
|
||
<div class="modal__title">¿Ajustar stock?</div>
|
||
<div class="modal__desc">Se ajustarán <strong style="color: var(--color-text-primary);">5 artículos</strong> del inventario. Esta acción no se puede deshacer.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary" onclick="closeModal('ajustar-stock')">Cancelar</button>
|
||
<button class="modal__btn modal__btn--primary" onclick="closeModal('ajustar-stock')">Ajustar</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- d) Cerrar periodo fiscal -->
|
||
<div class="modal-overlay" id="overlay-cerrar-periodo" onclick="if(event.target===this) closeModal('cerrar-periodo')"></div>
|
||
<div class="modal-dialog" id="modal-cerrar-periodo">
|
||
<div class="modal__icon modal__icon--danger">🛑</div>
|
||
<div class="modal__title">¿Cerrar periodo fiscal?</div>
|
||
<div class="modal__desc">Se cerrará el periodo <strong style="color: var(--color-text-primary);">Marzo 2026</strong>. No podrás registrar pólizas en este periodo.</div>
|
||
<div class="modal__actions">
|
||
<button class="modal__btn modal__btn--secondary" onclick="closeModal('cerrar-periodo')">Cancelar</button>
|
||
<button class="modal__btn modal__btn--danger" onclick="closeModal('cerrar-periodo')">Cerrar periodo</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function openModal(id) {
|
||
const overlay = document.getElementById('overlay-' + id);
|
||
const dialog = document.getElementById('modal-' + id);
|
||
overlay.classList.remove('closing');
|
||
dialog.classList.remove('closing');
|
||
overlay.classList.add('active');
|
||
dialog.classList.add('active');
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
|
||
function closeModal(id) {
|
||
const overlay = document.getElementById('overlay-' + id);
|
||
const dialog = document.getElementById('modal-' + id);
|
||
overlay.classList.add('closing');
|
||
dialog.classList.add('closing');
|
||
setTimeout(() => {
|
||
overlay.classList.remove('active', 'closing');
|
||
dialog.classList.remove('active', 'closing');
|
||
document.body.style.overflow = '';
|
||
}, 200);
|
||
}
|
||
|
||
// Close on Escape key
|
||
document.addEventListener('keydown', (e) => {
|
||
if (e.key === 'Escape') {
|
||
document.querySelectorAll('.modal-overlay.active').forEach(overlay => {
|
||
const id = overlay.id.replace('overlay-', '');
|
||
closeModal(id);
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|