diff --git a/index.html b/index.html
index b68d535..a60e88f 100644
--- a/index.html
+++ b/index.html
@@ -191,6 +191,17 @@
});
}
+ // ── PWA Install Logic ──────────────────────────────────────────
+ window.deferredPrompt = null;
+
+ window.addEventListener('beforeinstallprompt', (e) => {
+ // Prevent automatic prompt
+ e.preventDefault();
+ window.deferredPrompt = e;
+ // Dispatch a custom event so sections can update their UI
+ window.dispatchEvent(new Event('pwa-installable'));
+ });
+
// ── Check Web Bluetooth availability ──────────────────────────
if (!navigator.bluetooth) {
setTimeout(() => {
diff --git a/web/js/sections/home.js b/web/js/sections/home.js
index ebff574..89bdfbb 100644
--- a/web/js/sections/home.js
+++ b/web/js/sections/home.js
@@ -116,9 +116,37 @@ const HomeSection = {
};
BLE.on('connected', update);
BLE.on('disconnected', update);
+
+ // PWA Install Logic
+ const pwaCard = container.querySelector('#home-pwa-install-card');
+ const pwaBtn = container.querySelector('#home-btn-install-pwa');
+
+ const checkPwaStatus = () => {
+ if (window.deferredPrompt && pwaCard) {
+ pwaCard.style.display = 'block';
+ }
+ };
+
+ // Check initially in case the event fired before we mounted
+ checkPwaStatus();
+
+ window.addEventListener('pwa-installable', checkPwaStatus);
+
+ if (pwaBtn) {
+ pwaBtn.addEventListener('click', async () => {
+ if (!window.deferredPrompt) return;
+ window.deferredPrompt.prompt();
+ const { outcome } = await window.deferredPrompt.userChoice;
+ console.log(`User response to the install prompt: ${outcome}`);
+ window.deferredPrompt = null;
+ pwaCard.style.display = 'none';
+ });
+ }
+
this._cleanup = [
() => BLE.off('connected', update),
() => BLE.off('disconnected', update),
+ () => window.removeEventListener('pwa-installable', checkPwaStatus),
];
},