/** * sidebar.js — Shared sidebar matching the design system style * Replaces existing sidebar in each page with a consistent, themed version. * Uses i18n t() for all labels when available. */ (function() { 'use strict'; // i18n helper — falls back to raw string if i18n.js not loaded var _t = typeof window.t === 'function' ? window.t : function(k) { return k; }; var u = window.POS_USER || {}; var name = u.name || 'Usuario'; var roleLabel = u.roleLabel || ''; var initials = u.initials || '?'; var currentPath = window.location.pathname; var currentTheme = localStorage.getItem('pos_theme') || 'industrial'; var currentLang = localStorage.getItem('pos_lang') || 'es'; var navSections = [ { label: _t('nav_main'), items: [ { name: _t('dashboard'), href: '/pos/dashboard', icon: '' }, { name: _t('pos'), href: '/pos/sale', icon: '' }, { name: _t('catalog'), href: '/pos/catalog', icon: '' }, { name: _t('inventory'), href: '/pos/inventory', icon: '' }, ]}, { label: _t('nav_management'), items: [ { name: _t('customers'), href: '/pos/customers', icon: '' }, { name: 'Cotizaciones', href: '/pos/quotations', icon: '' }, { name: 'Marketplace', href: '/pos/marketplace', icon: '' }, { name: _t('invoicing'), href: '/pos/invoicing', icon: '' }, { name: _t('accounting'), href: '/pos/accounting', icon: '' }, { name: _t('reports'), href: '/pos/reports', icon: '' }, { name: _t('fleet'), href: '/pos/fleet', icon: '' }, { name: _t('whatsapp'), href: '/pos/whatsapp', icon: '' }, ]}, { label: _t('nav_system'), items: [ { name: _t('config'), href: '/pos/config', icon: '' }, ]}, ]; function svgIcon(paths) { return '' + paths + ''; } // Build nav HTML var navHtml = ''; navSections.forEach(function(sec) { navHtml += ''; sec.items.forEach(function(item) { var active = currentPath === item.href; navHtml += '' + svgIcon(item.icon) + '' + item.name + ''; }); }); // Theme toggle buttons var themeHtml = ''; // Language toggle buttons var langHtml = ''; window.updateThemeButtons = function() { var t = localStorage.getItem('pos_theme') || 'industrial'; document.querySelectorAll('.theme-toggle-btn').forEach(function(b, i) { b.classList.toggle('is-active', i === 0 ? t === 'industrial' : t === 'modern'); }); }; var sidebarHtml = '' + '' + '' + themeHtml + langHtml + ''; // CSS matching the design system var css = document.createElement('style'); css.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(css); // Replace existing sidebar var existing = document.querySelector('aside.sidebar, .sidebar, #sidebar'); if (existing) { existing.className = 'pos-sidebar'; existing.innerHTML = sidebarHtml; existing.removeAttribute('style'); } else { var el = document.createElement('aside'); el.className = 'pos-sidebar'; el.innerHTML = sidebarHtml; document.body.insertBefore(el, document.body.firstChild); } // Offset main content var main = document.querySelector('main, .main-content, #mainContent, .main, .page-content'); if (main) main.classList.add('pos-main-offset'); // ── Tablet/mobile: sidebar toggle + overlay ───────────────────── // Creates a hamburger button + overlay for screens < 1024px. // The CSS in pos-glass.css hides the sidebar by default on tablets // and shows it as a slide-in drawer when .open is added. var sidebar = document.querySelector('.pos-sidebar, .sidebar, #sidebar'); var overlay = document.getElementById('sidebar-overlay'); // Create overlay if it doesn't exist if (!overlay && sidebar) { overlay = document.createElement('div'); overlay.id = 'sidebar-overlay'; overlay.className = 'sidebar-overlay'; overlay.addEventListener('click', function () { closeSidebar(); }); sidebar.parentNode.insertBefore(overlay, sidebar); } // Create hamburger button if it doesn't exist var hamburger = document.getElementById('hamburger-btn'); if (!hamburger) { hamburger = document.createElement('button'); hamburger.id = 'hamburger-btn'; hamburger.className = 'hamburger-btn'; hamburger.setAttribute('aria-label', 'Menú'); hamburger.innerHTML = ''; hamburger.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);'; hamburger.addEventListener('click', function () { toggleSidebar(); }); document.body.appendChild(hamburger); } function toggleSidebar() { if (!sidebar) return; var isOpen = sidebar.classList.contains('open'); sidebar.classList.toggle('open', !isOpen); if (overlay) overlay.classList.toggle('open', !isOpen); document.body.style.overflow = isOpen ? '' : 'hidden'; } function closeSidebar() { if (sidebar) sidebar.classList.remove('open'); if (overlay) overlay.classList.remove('open'); document.body.style.overflow = ''; } // Auto-close sidebar on window resize to desktop window.addEventListener('resize', function () { if (window.innerWidth >= 1024) closeSidebar(); }); // Expose globally so inline onclick handlers and page-specific JS can call them window.toggleSidebar = toggleSidebar; window.closeSidebar = closeSidebar; })();