feat(design): add 16 new components + update 5 pages (ronda 2)
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
This commit is contained in:
477
docs/design/design-system/components/modal-confirmacion.html
Normal file
477
docs/design/design-system/components/modal-confirmacion.html
Normal file
@@ -0,0 +1,477 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user