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 = '';
+
+ 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 @@
+