From eb107e2778531e52d662bc55df17a655931cd8d5 Mon Sep 17 00:00:00 2001 From: consultoria-as Date: Tue, 26 May 2026 08:45:56 +0000 Subject: [PATCH] feat(ui): PWA splash screen, animated logo, dynamic favicon, manifest shortcuts, splash-loader.js --- pos/static/js/splash-loader.js | 131 ++++++++++++++++++++++++ pos/static/pwa/manifest.json | 18 +++- pos/templates/accounting.html | 4 +- pos/templates/catalog.html | 4 +- pos/templates/config.html | 4 +- pos/templates/customers.html | 4 +- pos/templates/dashboard.html | 4 +- pos/templates/diagrams.html | 4 +- pos/templates/fleet.html | 4 +- pos/templates/inventory.html | 4 +- pos/templates/invoicing.html | 4 +- pos/templates/marketplace.html | 1 + pos/templates/marketplace_external.html | 4 +- pos/templates/pos.html | 4 +- pos/templates/quotations.html | 3 +- pos/templates/reports.html | 4 +- pos/templates/whatsapp.html | 4 +- 17 files changed, 187 insertions(+), 18 deletions(-) create mode 100644 pos/static/js/splash-loader.js diff --git a/pos/static/js/splash-loader.js b/pos/static/js/splash-loader.js new file mode 100644 index 0000000..7c6b7be --- /dev/null +++ b/pos/static/js/splash-loader.js @@ -0,0 +1,131 @@ +/** + * splash-loader.js — PWA splash screen + dynamic favicon + * Show an animated splash while the app loads, then fade out. + * Also provides dynamic favicon updates for notifications / offline states. + */ +(function() { + 'use strict'; + + // ─── Create splash element ────────────────────────────────────────────── + var splash = document.createElement('div'); + splash.id = 'nx-splash'; + splash.style.cssText = 'position:fixed;inset:0;z-index:99999;' + + 'background:linear-gradient(135deg,#0d0d0d 0%,#1a1205 100%);' + + 'display:flex;flex-direction:column;align-items:center;justify-content:center;' + + 'transition:opacity 0.5s ease,visibility 0.5s ease;'; + + // Logo SVG (animated) + var logoSvg = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + 'N' + + ''; + + var title = '
Nexus
'; + var subtitle = '
Autoparts POS
'; + var spinner = '
'; + + splash.innerHTML = logoSvg + title + subtitle + spinner; + + // Inject keyframes if not present + if (!document.getElementById('nx-splash-styles')) { + var style = document.createElement('style'); + style.id = 'nx-splash-styles'; + style.textContent = '@keyframes nxDraw { to { stroke-dashoffset:0; } } @keyframes nxFadeIn { from { opacity:0;transform:translateY(8px); } to { opacity:1;transform:translateY(0); } }'; + document.head.appendChild(style); + } + + document.body.appendChild(splash); + + // Hide splash when DOM is ready + minimum display time + var minDisplay = 800; + var startTime = Date.now(); + + function hideSplash() { + var elapsed = Date.now() - startTime; + var remaining = Math.max(0, minDisplay - elapsed); + setTimeout(function() { + splash.style.opacity = '0'; + splash.style.visibility = 'hidden'; + setTimeout(function() { splash.remove(); }, 500); + }, remaining); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', hideSplash); + } else { + hideSplash(); + } + + // ─── Dynamic Favicon ──────────────────────────────────────────────────── + window.NexusFavicon = { + canvas: null, + ctx: null, + link: null, + baseColor: '#F5A623', + + init: function() { + this.canvas = document.createElement('canvas'); + this.canvas.width = 64; + this.canvas.height = 64; + this.ctx = this.canvas.getContext('2d'); + this.link = document.querySelector('link[rel*="icon"]') || document.createElement('link'); + this.link.rel = 'shortcut icon'; + this.link.type = 'image/png'; + document.head.appendChild(this.link); + this.setNormal(); + }, + + draw: function(color, badge) { + var ctx = this.ctx; + var c = this.canvas; + ctx.clearRect(0, 0, 64, 64); + + // Background circle + ctx.beginPath(); + ctx.arc(32, 32, 30, 0, Math.PI * 2); + ctx.fillStyle = color || this.baseColor; + ctx.fill(); + + // Letter N + ctx.fillStyle = '#0d0d0d'; + ctx.font = 'bold 36px system-ui,sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText('N', 32, 33); + + // Badge dot + if (badge) { + ctx.beginPath(); + ctx.arc(52, 12, 10, 0, Math.PI * 2); + ctx.fillStyle = '#ef4444'; + ctx.fill(); + ctx.fillStyle = '#fff'; + ctx.font = 'bold 11px system-ui,sans-serif'; + ctx.fillText(badge > 9 ? '9+' : String(badge), 52, 13); + } + + this.link.href = c.toDataURL('image/png'); + }, + + setNormal: function() { this.draw(this.baseColor); }, + setOffline: function() { this.draw('#666'); }, + setNotify: function(count) { this.draw(this.baseColor, count); }, + }; + + // Auto-init favicon + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { NexusFavicon.init(); }); + } else { + NexusFavicon.init(); + } + + // Update favicon on online/offline + window.addEventListener('online', function() { if (window.NexusFavicon) NexusFavicon.setNormal(); }); + window.addEventListener('offline', function() { if (window.NexusFavicon) NexusFavicon.setOffline(); }); +})(); diff --git a/pos/static/pwa/manifest.json b/pos/static/pwa/manifest.json index faa8969..3c8b2cb 100644 --- a/pos/static/pwa/manifest.json +++ b/pos/static/pwa/manifest.json @@ -1,13 +1,23 @@ { - "name": "Nexus POS", + "name": "Nexus Autoparts POS", "short_name": "NexusPOS", "description": "Sistema de Punto de Venta para Refaccionarias", "start_url": "/pos/login", "display": "standalone", + "orientation": "portrait", "background_color": "#0d0d0d", "theme_color": "#F5A623", + "categories": ["business", "productivity"], "icons": [ - {"src": "/pos/static/pwa/icon-192.png", "sizes": "192x192", "type": "image/png"}, - {"src": "/pos/static/pwa/icon-512.png", "sizes": "512x512", "type": "image/png"} - ] + {"src": "/pos/static/pwa/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable"}, + {"src": "/pos/static/pwa/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable"} + ], + "shortcuts": [ + {"name": "Nueva Venta", "short_name": "Venta", "description": "Abrir punto de venta", "url": "/pos/sale", "icons": [{"src": "/pos/static/pwa/icon-192.png", "sizes": "192x192"}]}, + {"name": "Inventario", "short_name": "Stock", "description": "Ver inventario", "url": "/pos/inventory", "icons": [{"src": "/pos/static/pwa/icon-192.png", "sizes": "192x192"}]}, + {"name": "Dashboard", "short_name": "Dashboard", "description": "Ver resumen", "url": "/pos/dashboard", "icons": [{"src": "/pos/static/pwa/icon-192.png", "sizes": "192x192"}]} + ], + "screenshots": [], + "related_applications": [], + "prefer_related_applications": false } diff --git a/pos/templates/accounting.html b/pos/templates/accounting.html index b23d655..aafd0ba 100644 --- a/pos/templates/accounting.html +++ b/pos/templates/accounting.html @@ -13,6 +13,7 @@ + @@ -490,7 +491,8 @@ - + > diff --git a/pos/templates/catalog.html b/pos/templates/catalog.html index c3418dc..434aacb 100644 --- a/pos/templates/catalog.html +++ b/pos/templates/catalog.html @@ -14,6 +14,7 @@ + @@ -286,7 +287,8 @@ - + > diff --git a/pos/templates/config.html b/pos/templates/config.html index 1a42110..9e15331 100644 --- a/pos/templates/config.html +++ b/pos/templates/config.html @@ -13,6 +13,7 @@ + @@ -741,7 +742,8 @@ - + > diff --git a/pos/templates/customers.html b/pos/templates/customers.html index 08b1df0..4366db7 100644 --- a/pos/templates/customers.html +++ b/pos/templates/customers.html @@ -13,6 +13,7 @@ + @@ -621,7 +622,8 @@ - + > diff --git a/pos/templates/dashboard.html b/pos/templates/dashboard.html index 4f07767..f05db51 100644 --- a/pos/templates/dashboard.html +++ b/pos/templates/dashboard.html @@ -13,6 +13,7 @@ + @@ -489,7 +490,8 @@ - + > diff --git a/pos/templates/diagrams.html b/pos/templates/diagrams.html index 1ddb020..741bbae 100644 --- a/pos/templates/diagrams.html +++ b/pos/templates/diagrams.html @@ -14,6 +14,7 @@ + @@ -150,7 +151,8 @@ - + > diff --git a/pos/templates/fleet.html b/pos/templates/fleet.html index 902f30d..482644d 100644 --- a/pos/templates/fleet.html +++ b/pos/templates/fleet.html @@ -13,6 +13,7 @@ + @@ -303,7 +304,8 @@ - +> diff --git a/pos/templates/inventory.html b/pos/templates/inventory.html index aa4b4e0..15c2181 100644 --- a/pos/templates/inventory.html +++ b/pos/templates/inventory.html @@ -13,6 +13,7 @@ + @@ -915,7 +916,8 @@ - + > diff --git a/pos/templates/invoicing.html b/pos/templates/invoicing.html index ec72173..f987a55 100644 --- a/pos/templates/invoicing.html +++ b/pos/templates/invoicing.html @@ -13,6 +13,7 @@ + @@ -1052,7 +1053,8 @@ - + > diff --git a/pos/templates/marketplace.html b/pos/templates/marketplace.html index 52340d8..db399ce 100644 --- a/pos/templates/marketplace.html +++ b/pos/templates/marketplace.html @@ -13,6 +13,7 @@ + diff --git a/pos/templates/marketplace_external.html b/pos/templates/marketplace_external.html index 3e92aa6..e54f1f0 100644 --- a/pos/templates/marketplace_external.html +++ b/pos/templates/marketplace_external.html @@ -14,6 +14,7 @@ +