initial modularization + templates

This commit is contained in:
2026-03-10 18:40:47 -03:00
parent 3c4b2e148d
commit ef9a9296dd
10 changed files with 841 additions and 782 deletions

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="es" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -9,78 +10,134 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<style>
:root {
--bg: #ebedef; --card-bg: #ffffff; --text-main: #2e3338;
--text-muted: #4f5660; --border: #e3e5e8; --navbar-bg: #ffffff;
--accent: #5865f2; --input-bg: #e3e5e8; --danger: #ed4245;
--bg: #ebedef;
--card-bg: #ffffff;
--text-main: #2e3338;
--text-muted: #4f5660;
--border: #e3e5e8;
--navbar-bg: #ffffff;
--accent: #5865f2;
--input-bg: #e3e5e8;
--danger: #ed4245;
}
[data-theme="dark"] {
--bg: #36393f; --card-bg: #2f3136; --text-main: #dcddde;
--text-muted: #b9bbbe; --border: #202225; --navbar-bg: #202225;
--bg: #36393f;
--card-bg: #2f3136;
--text-main: #dcddde;
--text-muted: #b9bbbe;
--border: #202225;
--navbar-bg: #202225;
--input-bg: #202225;
}
body { background: var(--bg); color: var(--text-main); font-family: "gg sans", "Segoe UI", sans-serif; transition: background 0.2s; }
.navbar { background: var(--navbar-bg) !important; border-bottom: 1px solid var(--border); }
.navbar-brand { color: var(--text-main) !important; font-weight: 700; }
.discord-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.form-control, .form-control:focus { background-color: var(--input-bg) !important; color: var(--text-main) !important; border: 1px solid var(--border) !important; box-shadow: none !important; }
.form-control:focus { border-color: var(--accent) !important; }
.form-control::placeholder { color: var(--text-muted) !important; opacity: 1; }
.table { color: var(--text-main) !important; --bs-table-bg: transparent; --bs-table-border-color: var(--border); }
.table thead th { background: var(--bg); color: var(--text-muted); font-size: 0.75rem; text-transform: uppercase; border-bottom: 1px solid var(--border); }
.table td { border-bottom: 1px solid var(--border); vertical-align: middle; }
.btn-accent { background: var(--accent); color: #fff; border: none; }
.dropdown-menu { background: var(--card-bg); border: 1px solid var(--border); }
.dropdown-item { color: var(--text-main) !important; }
.dropdown-item:hover { background: var(--input-bg); }
[data-theme="dark"] .table { --bs-table-color: var(--text-main); color: var(--text-main) !important; }
[data-theme="dark"] .table thead th { background: #292b2f; color: var(--text-muted); }
[data-theme="dark"] .text-muted { color: var(--text-muted) !important; }
body {
background: var(--bg);
color: var(--text-main);
font-family: "gg sans", "Segoe UI", sans-serif;
transition: background 0.2s;
}
.navbar {
background: var(--navbar-bg) !important;
border-bottom: 1px solid var(--border);
}
.navbar-brand {
color: var(--text-main) !important;
font-weight: 700;
}
.discord-card {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-control,
.form-control:focus {
background-color: var(--input-bg) !important;
color: var(--text-main) !important;
border: 1px solid var(--border) !important;
box-shadow: none !important;
}
.form-control:focus {
border-color: var(--accent) !important;
}
.form-control::placeholder {
color: var(--text-muted) !important;
opacity: 1;
}
.table {
color: var(--text-main) !important;
--bs-table-bg: transparent;
--bs-table-border-color: var(--border);
}
.table thead th {
background: var(--bg);
color: var(--text-muted);
font-size: 0.75rem;
text-transform: uppercase;
border-bottom: 1px solid var(--border);
}
.table td {
border-bottom: 1px solid var(--border);
vertical-align: middle;
}
.btn-accent {
background: var(--accent);
color: #fff;
border: none;
}
.dropdown-menu {
background: var(--card-bg);
border: 1px solid var(--border);
}
.dropdown-item {
color: var(--text-main) !important;
}
.dropdown-item:hover {
background: var(--input-bg);
}
[data-theme="dark"] .table {
--bs-table-color: var(--text-main);
color: var(--text-main) !important;
}
[data-theme="dark"] .table thead th {
background: #292b2f;
color: var(--text-muted);
}
[data-theme="dark"] .text-muted {
color: var(--text-muted) !important;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-md sticky-top px-3 mb-3">
<span class="navbar-brand">SekiPOS <small class="text-danger fw-bold ms-1" style="font-size:0.75rem;"><i class="bi bi-journal-x"></i> Dicom</small></span>
<div class="ms-3 gap-2 d-flex">
<a href="/" class="btn btn-outline-primary btn-sm"><i class="bi bi-box-seam me-1"></i>Inventario</a>
<a href="/checkout" class="btn btn-outline-primary btn-sm"><i class="bi bi-cart-fill me-1"></i>Caja</a>
<a href="/sales" class="btn btn-outline-primary btn-sm"><i class="bi bi-receipt me-1"></i>Ventas</a>
</div>
<div class="ms-auto">
<div class="dropdown">
<button class="btn btn-accent dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-person-circle me-1"></i>
<span class="d-none d-sm-inline">{{ user.username }}</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow">
<li>
<button class="dropdown-item" onclick="toggleTheme()">
<i class="bi bi-moon-stars me-2" id="theme-icon"></i>
<span id="theme-label">Modo Oscuro</span>
</button>
</li>
<li><hr class="dropdown-divider" style="border-color: var(--border);"></li>
<li><a class="dropdown-item text-danger" href="/logout"><i class="bi bi-box-arrow-right me-2"></i>Salir</a></li>
</ul>
</div>
</div>
</nav>
<body>
{% with active_page='dicom' %}{% include 'navbar.html' %}{% endwith %}
<div class="container-fluid px-3">
<div class="row g-3">
<div class="col-md-4">
<div class="discord-card p-3 mb-3">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0 fw-bold">Registrar Movimiento</h5>
<button class="btn btn-sm btn-outline-secondary" onclick="clearDicomForm()" title="Limpiar Formulario">
<button class="btn btn-sm btn-outline-secondary" onclick="clearDicomForm()"
title="Limpiar Formulario">
<i class="bi bi-eraser"></i> Nuevo
</button>
</div>
@@ -94,9 +151,10 @@
</div>
<div class="mb-4">
<label class="small text-muted mb-1">Nota (Opcional)</label>
<input type="text" id="dicom-notes" class="form-control" placeholder="Ej: Pan y bebida" onkeydown="if(event.key === 'Enter') submitDicom('add')">
<input type="text" id="dicom-notes" class="form-control" placeholder="Ej: Pan y bebida"
onkeydown="if(event.key === 'Enter') submitDicom('add')">
</div>
<div class="d-flex flex-column gap-2">
<button class="btn btn-danger py-2 fw-bold" onclick="submitDicom('add')">
<i class="bi bi-cart-plus me-1"></i> Fiar (Sumar Deuda)
@@ -110,9 +168,10 @@
<div class="col-md-8">
<div class="discord-card p-3">
<div class="position-relative mb-3">
<input type="text" id="dicom-search" class="form-control ps-5" placeholder="Buscar cliente por nombre..." onkeyup="filterDicom()">
<input type="text" id="dicom-search" class="form-control ps-5"
placeholder="Buscar cliente por nombre..." onkeyup="filterDicom()">
<i class="bi bi-search position-absolute top-50 start-0 translate-middle-y ms-3 text-muted"></i>
</div>
@@ -135,10 +194,12 @@
<td class="text-muted small">{{ d[3] }}</td>
<td class="text-muted small">{{ d[4] }}</td>
<td class="text-end">
<button class="btn btn-sm btn-outline-secondary" onclick="selectClient('{{ d[1] }}')" title="Seleccionar">
<button class="btn btn-sm btn-outline-secondary"
onclick="selectClient('{{ d[1] }}')" title="Seleccionar">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger ms-1" onclick="forgiveDebt({{ d[0] }}, '{{ d[1] }}')" title="Eliminar Registro">
<button class="btn btn-sm btn-outline-danger ms-1"
onclick="forgiveDebt({{ d[0] }}, '{{ d[1] }}')" title="Eliminar Registro">
<i class="bi bi-trash"></i>
</button>
</td>
@@ -149,26 +210,26 @@
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
const clp = new Intl.NumberFormat('es-CL', { style: 'currency', currency: 'CLP', minimumFractionDigits: 0 });
// Smart color formatting for the debt column
document.querySelectorAll('.price-cell').forEach(td => {
const val = parseFloat(td.getAttribute('data-value'));
td.innerText = clp.format(val);
// Reversing the logic: Negative is debt (red), Positive is credit (green)
if (val < 0) {
td.classList.add('text-danger');
td.classList.add('text-danger');
} else if (val > 0) {
td.classList.add('text-success');
td.classList.add('text-success');
} else {
td.classList.add('text-muted');
td.classList.add('text-muted');
}
});
@@ -224,44 +285,13 @@
async function forgiveDebt(id, name) {
if (!confirm(`¿Estás seguro de que quieres eliminar completamente a ${name} del registro?`)) return;
const res = await fetch(`/api/dicom/${id}`, { method: 'DELETE' });
if (res.ok) window.location.reload();
}
/* ── Theme Management ── */
function applyTheme(t) {
document.documentElement.setAttribute('data-theme', t);
const isDark = t === 'dark';
const themeIcon = document.getElementById('theme-icon');
const themeLabel = document.getElementById('theme-label');
if (themeIcon) themeIcon.className = isDark ? 'bi bi-sun me-2' : 'bi bi-moon-stars me-2';
if (themeLabel) themeLabel.innerText = isDark ? 'Modo Claro' : 'Modo Oscuro';
localStorage.setItem('theme', t);
}
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme');
applyTheme(current === 'dark' ? 'light' : 'dark');
}
(function initTheme() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
applyTheme(savedTheme);
} else {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyTheme(prefersDark ? 'dark' : 'light');
}
})();
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (!localStorage.getItem('theme')) {
applyTheme(e.matches ? 'dark' : 'light');
}
});
</script>
<script src="./static/cookieStuff.js"></script>
<script src="./static/themeStuff.js"></script>
</body>
</html>