quantvat / src /templates /includes /partials /pwa_prompt.html
heisbuba's picture
Update src/templates/includes/partials/pwa_prompt.html
848ca11 verified
<script>
// PWA Install Injector
(function() {
'use strict';
const performInjection = () => {
let deferredPrompt = null;
const lastDismissed = localStorage.getItem('pwa_dismissed_at');
const cooldown = 3 * 24 * 60 * 60 * 1000;
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
if (isStandalone || (lastDismissed && (Date.now() - lastDismissed < cooldown))) {
return;
}
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
setTimeout(injectPwaResources, 2000);
});
if (isIOS) {
setTimeout(injectPwaResources, 2000);
}
/**
* Injects CSS and HTML UI components into the DOM
*/
function injectPwaResources() {
if (document.getElementById('pwa-mini-banner')) return;
const style = document.createElement('style');
style.id = 'pwa-dynamic-styles';
style.textContent = `
.pwa-sticky-bar {
position: fixed; bottom: 24px; left: 50%;
transform: translateX(-50%) translateY(150%);
width: calc(100% - 32px); max-width: 400px;
z-index: 9999; opacity: 0; pointer-events: none;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.4s;
}
.pwa-sticky-bar.visible { transform: translateX(-50%) translateY(0); opacity: 1; pointer-events: auto; }
.pwa-bar-content {
background: rgba(30, 37, 42, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
border: 1px solid var(--border); border-radius: 24px;
padding: 10px 16px; display: flex; align-items: center;
justify-content: space-between; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
}
.pwa-bar-info { display: flex; align-items: center; gap: 12px; }
.pwa-bar-icon {
width: 42px; height: 42px; background: var(--accent-green);
border-radius: 12px; display: flex; align-items: center;
justify-content: center; font-size: 1.3rem;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
}
.pwa-bar-text strong { color: var(--text-white); font-size: 0.9rem; display: block; line-height: 1.2; }
.pwa-bar-text span { color: var(--text-gray); font-size: 0.75rem; }
.btn-pwa-add {
background: var(--accent-green); color: #000; border: none;
padding: 8px 18px; border-radius: 14px; font-weight: 800;
font-size: 0.75rem; text-transform: uppercase; cursor: pointer;
transition: transform 0.2s;
}
.btn-pwa-add:active { transform: scale(0.95); }
.btn-pwa-close {
background: transparent; color: var(--text-gray);
border: none; font-size: 1.5rem; cursor: pointer;
line-height: 1; padding: 0 4px;
}
`;
document.head.appendChild(style);
const pwaWrapper = document.createElement('div');
pwaWrapper.id = 'pwa-mini-banner';
pwaWrapper.className = 'pwa-sticky-bar';
pwaWrapper.innerHTML = `
<div class="pwa-bar-content">
<div class="pwa-bar-info">
<span class="pwa-bar-icon"><svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="512" height="512" rx="120" fill="#151a1e"/>
<path d="M380 380L430 430" stroke="#ffffff" stroke-width="32" stroke-linecap="round"/>
<circle cx="256" cy="256" r="160" stroke="#ffffff" stroke-width="32"/>
<rect x="190" y="270" width="30" height="60" rx="4" fill="#10b981"/>
<rect x="241" y="230" width="30" height="100" rx="4" fill="#10b981"/>
<rect x="292" y="190" width="30" height="140" rx="4" fill="#10b981"/>
</svg></span>
<div class="pwa-bar-text">
<strong>QuantVAT App</strong>
<span>Install for instant access</span>
</div>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<button id="btn-pwa-install" class="btn-pwa-add">${isIOS ? 'Show' : 'Add'}</button>
<button id="btn-pwa-close-trigger" class="btn-pwa-close">×</button>
</div>
</div>
`;
document.body.appendChild(pwaWrapper);
setTimeout(() => pwaWrapper.classList.add('visible'), 100);
document.getElementById('btn-pwa-install').addEventListener('click', async () => {
if (isIOS) {
alert("To install: Tap the 'Share' icon and select 'Add to Home Screen'.");
return;
}
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
deferredPrompt = null;
pwaWrapper.classList.remove('visible');
setTimeout(() => { pwaWrapper.remove(); style.remove(); }, 600);
});
document.getElementById('btn-pwa-close-trigger').addEventListener('click', () => {
pwaWrapper.classList.remove('visible');
localStorage.setItem('pwa_dismissed_at', Date.now());
setTimeout(() => {
pwaWrapper.remove();
style.remove();
}, 600);
});
}
};
if ('requestIdleCallback' in window) {
window.requestIdleCallback(performInjection);
} else {
window.addEventListener('load', performInjection);
}
})();
</script>