Cambios implementados: 1. Lazy loading de imágenes: - catalog.js: loading="lazy" decoding="async" en part cards y detail panel - inventory.js: lazy loading en imagen de detalle de item 2. Minificación de assets: - scripts/minify-assets.sh: minifica JS (terser) y CSS para POS y Dashboard - 25 archivos .min.js + 5 .min.css generados en pos/static/ - 14 archivos .min.js + 8 .min.css generados en dashboard/ 3. Nginx auto-serve minified: - try_files $1.min.js antes de servir .js original - try_files $1.min.css antes de servir .css original - Transparente para los templates HTML (cero cambios en HTML) 4. Cache warming script: - scripts/warm_vehicle_cache.py: pobla Redis con vehicle info por batches - Mitiga DISTINCT ON + 4 JOINs sobre 2B filas - Corre en background, procesa ~1.5M parts Tests: 73/73 pasando
1 line
12 KiB
JavaScript
1 line
12 KiB
JavaScript
!function(){"use strict";var e="function"==typeof window.t?window.t:function(e){return e},r=window.POS_USER||{},a=r.name||"Usuario",t=r.roleLabel||"",o=r.initials||"?",i=window.location.pathname,n=localStorage.getItem("pos_theme")||"industrial",s=localStorage.getItem("pos_lang")||"es",l=[{label:e("nav_main"),items:[{name:e("dashboard"),href:"/pos/dashboard",icon:'<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>'},{name:e("pos"),href:"/pos/sale",icon:'<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>'},{name:e("catalog"),href:"/pos/catalog",icon:'<path d="M4 6h16M4 10h16M4 14h16M4 18h16"/>'},{name:e("inventory"),href:"/pos/inventory",icon:'<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/>'}]},{label:e("nav_management"),items:[{name:e("customers"),href:"/pos/customers",icon:'<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/>'},{name:"Cotizaciones",href:"/pos/quotations",icon:'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="15" x2="15" y2="15"/><line x1="12" y1="12" x2="12" y2="18"/>'},{name:"Marketplace",href:"/pos/marketplace",icon:'<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>'},{name:e("invoicing"),href:"/pos/invoicing",icon:'<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/>'},{name:e("accounting"),href:"/pos/accounting",icon:'<line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>'},{name:e("reports"),href:"/pos/reports",icon:'<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>'},{name:e("fleet"),href:"/pos/fleet",icon:'<path d="M1 13h22M1 13l2-6h6l2 6M9 7h6l2 6M15 13l2-6M5 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM19 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/>'},{name:e("whatsapp"),href:"/pos/whatsapp",icon:'<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>'}]},{label:e("nav_system"),items:[{name:e("config"),href:"/pos/config",icon:'<circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/>'}]}];var d="";l.forEach((function(e){d+='<div class="nav-section-label">'+e.label+"</div>",e.items.forEach((function(e){var r=i===e.href;d+='<a class="nav-item'+(r?" is-active":"")+'" href="'+e.href+'"'+(r?' aria-current="page"':"")+">"+('<svg class="nav-item__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">'+e.icon+"</svg><span>")+e.name+"</span></a>"}))}));var c='<div class="sidebar__theme-toggle"><button class="theme-toggle-btn'+("industrial"===n?" is-active":"")+'" onclick="posSetTheme(\'industrial\');updateThemeButtons()" title="'+e("dark_theme")+'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg></button><button class="theme-toggle-btn'+("modern"===n?" is-active":"")+'" onclick="posSetTheme(\'modern\');updateThemeButtons()" title="'+e("light_theme")+'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div>',p='<div class="sidebar__lang-toggle"><button class="lang-toggle-btn'+("es"===s?" is-active":"")+'" onclick="setLang(\'es\')" title="Espanol"><span class="lang-flag">MX</span> ES</button><button class="lang-toggle-btn'+("en"===s?" is-active":"")+'" onclick="setLang(\'en\')" title="English"><span class="lang-flag">US</span> EN</button></div>';window.updateThemeButtons=function(){var e=localStorage.getItem("pos_theme")||"industrial";document.querySelectorAll(".theme-toggle-btn").forEach((function(r,a){r.classList.toggle("is-active",0===a?"industrial"===e:"modern"===e)}))};var g='<div class="sidebar__brand"> <div class="brand-logo">NA</div> <div class="brand-name"> <span class="brand-name__primary">Nexus</span> <span class="brand-name__sub">Autoparts POS</span> </div></div><nav class="sidebar__nav">'+d+"</nav>"+c+p+'<div class="sidebar__footer"> <div class="sidebar__user-avatar">'+o+'</div> <div class="sidebar__user-info"> <div class="sidebar__user-name">'+a+'</div> <div class="sidebar__user-role">'+t+'</div> </div> <button class="sidebar__logout-btn" onclick="posLogout()" title="'+e("logout")+'"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg> </button></div>',m=document.createElement("style");m.textContent=[".pos-sidebar{position:fixed;top:0;left:0;bottom:0;width:260px;display:flex;flex-direction:column;background:var(--color-bg-elevated);border-right:1px solid var(--color-border);z-index:100;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb,#444) var(--scrollbar-track,#222);font-family:var(--font-body)}",".pos-sidebar::-webkit-scrollbar{width:4px}",".pos-sidebar::-webkit-scrollbar-track{background:var(--scrollbar-track,#222)}",".pos-sidebar::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb,#444);border-radius:99px}",".sidebar__brand{display:flex;align-items:center;gap:var(--space-3,12px);padding:var(--space-4,16px) var(--space-4,16px) var(--space-3,12px);border-bottom:1px solid var(--color-border);flex-shrink:0}",".brand-logo{width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:var(--color-primary);color:var(--color-text-inverse,#fff);font-family:var(--font-heading);font-weight:800;font-size:1rem;letter-spacing:-0.04em;flex-shrink:0}",'[data-theme="industrial"] .brand-logo{clip-path:polygon(0 0,calc(100% - 9px) 0,100% 9px,100% 100%,0 100%)}','[data-theme="modern"] .brand-logo{border-radius:var(--radius-md,8px)}',".brand-name__primary{font-family:var(--font-heading);font-weight:800;font-size:0.9375rem;letter-spacing:var(--tracking-wide,0.02em);text-transform:uppercase;color:var(--color-text-primary);line-height:1}",".brand-name__sub{font-size:var(--text-caption,0.75rem);color:var(--color-text-muted);letter-spacing:var(--tracking-wider,0.04em);text-transform:uppercase;margin-top:2px}",".sidebar__nav{flex:1;padding:var(--space-3,12px) 0}",".nav-section-label{padding:var(--space-3,12px) var(--space-4,16px) var(--space-1,4px);font-size:0.6875rem;font-weight:600;letter-spacing:var(--tracking-widest,0.08em);text-transform:uppercase;color:var(--color-text-muted)}",".nav-item{display:flex;align-items:center;gap:var(--space-3,12px);padding:var(--space-2,8px) var(--space-4,16px);color:var(--color-text-secondary);text-decoration:none;font-size:var(--text-body-sm,0.875rem);font-weight:400;border-left:3px solid transparent;transition:all 0.15s;cursor:pointer}",".nav-item:hover{background:var(--color-surface-2,rgba(255,255,255,0.04));color:var(--color-text-primary)}",".nav-item.is-active{background:var(--color-primary-muted,rgba(245,166,35,0.12));color:var(--color-primary);border-left-color:var(--color-primary);font-weight:600}",".nav-item__icon{width:18px;height:18px;flex-shrink:0;opacity:0.7}",".nav-item.is-active .nav-item__icon{opacity:1}",".sidebar__theme-toggle,.sidebar__lang-toggle{display:flex;gap:4px;padding:8px 16px;border-top:1px solid var(--color-border)}",".theme-toggle-btn,.lang-toggle-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:6px;border:1px solid var(--color-border);border-radius:var(--radius-sm,4px);background:none;color:var(--color-text-muted);cursor:pointer;transition:all 0.15s;font-size:0.75rem}",".theme-toggle-btn:hover,.lang-toggle-btn:hover{color:var(--color-text-primary);background:var(--color-surface-2,rgba(255,255,255,0.04))}",".theme-toggle-btn.is-active,.lang-toggle-btn.is-active{background:var(--color-primary-muted,rgba(245,166,35,0.12));color:var(--color-primary);border-color:var(--color-primary)}",".lang-flag{font-weight:700;font-size:0.625rem;letter-spacing:0.04em}",".sidebar__footer{padding:var(--space-3,12px) var(--space-4,16px);border-top:1px solid var(--color-border);display:flex;align-items:center;gap:var(--space-2,8px)}",".sidebar__user-avatar{width:28px;height:28px;border-radius:50%;background:var(--color-primary);color:var(--color-text-inverse,#fff);display:flex;align-items:center;justify-content:center;font-size:0.6875rem;font-weight:700;flex-shrink:0}",".sidebar__user-info{flex:1;overflow:hidden}",".sidebar__user-name{font-size:var(--text-body-sm,0.875rem);font-weight:600;color:var(--color-text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",".sidebar__user-role{font-size:var(--text-caption,0.75rem);color:var(--color-text-muted)}",".sidebar__logout-btn{background:none;border:1px solid var(--color-border);border-radius:var(--radius-sm,4px);padding:4px 6px;cursor:pointer;color:var(--color-text-muted);transition:all 0.15s;display:flex;align-items:center}",".sidebar__logout-btn:hover{color:var(--color-error,#F85149);border-color:var(--color-error,#F85149)}",".pos-main-offset{margin-left:260px}","@media(max-width:768px){.pos-sidebar{width:56px}.brand-name,.nav-item span,.sidebar__user-info,.nav-section-label,.sidebar__theme-toggle,.sidebar__lang-toggle{display:none}.sidebar__brand{justify-content:center;padding:12px 8px}.sidebar__footer{flex-direction:column;padding:8px}.pos-main-offset{margin-left:56px}}"].join("\n"),document.head.appendChild(m);var v=document.querySelector("aside.sidebar, .sidebar, #sidebar");if(v)v.className="pos-sidebar",v.innerHTML=g,v.removeAttribute("style");else{var b=document.createElement("aside");b.className="pos-sidebar",b.innerHTML=g,document.body.insertBefore(b,document.body.firstChild)}var x=document.querySelector("main, .main-content, #mainContent, .main, .page-content");x&&x.classList.add("pos-main-offset");var h=document.querySelector(".pos-sidebar, .sidebar, #sidebar"),u=document.getElementById("sidebar-overlay");!u&&h&&((u=document.createElement("div")).id="sidebar-overlay",u.className="sidebar-overlay",u.addEventListener("click",(function(){_()})),h.parentNode.insertBefore(u,h));var f=document.getElementById("hamburger-btn");function y(){if(h){var e=h.classList.contains("open");h.classList.toggle("open",!e),u&&u.classList.toggle("open",!e),document.body.style.overflow=e?"":"hidden"}}function _(){h&&h.classList.remove("open"),u&&u.classList.remove("open"),document.body.style.overflow=""}f||((f=document.createElement("button")).id="hamburger-btn",f.className="hamburger-btn",f.setAttribute("aria-label","Menú"),f.innerHTML='<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>',f.style.cssText="display:none;position:fixed;top:10px;left:10px;z-index:"+(parseInt(getComputedStyle(document.documentElement).getPropertyValue("--z-modal")||1050)+2)+";background:var(--glass-bg-strong);backdrop-filter:blur(12px);border:1px solid var(--glass-border);border-radius:var(--radius-md);padding:8px;cursor:pointer;color:var(--color-text-primary);box-shadow:0 2px 8px rgba(0,0,0,0.2);",f.addEventListener("click",(function(){y()})),document.body.appendChild(f)),window.addEventListener("resize",(function(){window.innerWidth>=1024&&_()})),window.toggleSidebar=y,window.closeSidebar=_}(); |