Skip to content

Commit 23cf205

Browse files
authored
Add files via upload
1 parent c122c27 commit 23cf205

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,125 @@
1+
<script>
2+
// PWA Install Injector
3+
(function() {
4+
'use strict';
5+
const performInjection = () => {
6+
let deferredPrompt = null;
7+
const lastDismissed = localStorage.getItem('pwa_dismissed_at');
8+
const cooldown = 3 * 24 * 60 * 60 * 1000;
9+
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
110

11+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
12+
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
13+
14+
if (isStandalone || (lastDismissed && (Date.now() - lastDismissed < cooldown))) {
15+
return;
16+
}
17+
18+
window.addEventListener('beforeinstallprompt', (e) => {
19+
e.preventDefault();
20+
deferredPrompt = e;
21+
setTimeout(injectPwaResources, 2000);
22+
});
23+
24+
if (isIOS) {
25+
setTimeout(injectPwaResources, 2000);
26+
}
27+
28+
/**
29+
* Injects CSS and HTML UI components into the DOM
30+
*/
31+
function injectPwaResources() {
32+
if (document.getElementById('pwa-mini-banner')) return;
33+
34+
const style = document.createElement('style');
35+
style.id = 'pwa-dynamic-styles';
36+
style.textContent = `
37+
.pwa-sticky-bar {
38+
position: fixed; bottom: 24px; left: 50%;
39+
transform: translateX(-50%) translateY(150%);
40+
width: calc(100% - 32px); max-width: 400px;
41+
z-index: 9999; opacity: 0; pointer-events: none;
42+
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.4s;
43+
}
44+
.pwa-sticky-bar.visible { transform: translateX(-50%) translateY(0); opacity: 1; pointer-events: auto; }
45+
.pwa-bar-content {
46+
background: rgba(30, 37, 42, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
47+
border: 1px solid var(--border); border-radius: 24px;
48+
padding: 10px 16px; display: flex; align-items: center;
49+
justify-content: space-between; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
50+
}
51+
.pwa-bar-info { display: flex; align-items: center; gap: 12px; }
52+
.pwa-bar-icon {
53+
width: 42px; height: 42px; background: var(--accent-green);
54+
border-radius: 12px; display: flex; align-items: center;
55+
justify-content: center; font-size: 1.3rem;
56+
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
57+
}
58+
.pwa-bar-text strong { color: var(--text-white); font-size: 0.9rem; display: block; line-height: 1.2; }
59+
.pwa-bar-text span { color: var(--text-gray); font-size: 0.75rem; }
60+
.btn-pwa-add {
61+
background: var(--accent-green); color: #000; border: none;
62+
padding: 8px 18px; border-radius: 14px; font-weight: 800;
63+
font-size: 0.75rem; text-transform: uppercase; cursor: pointer;
64+
transition: transform 0.2s;
65+
}
66+
.btn-pwa-add:active { transform: scale(0.95); }
67+
.btn-pwa-close {
68+
background: transparent; color: var(--text-gray);
69+
border: none; font-size: 1.5rem; cursor: pointer;
70+
line-height: 1; padding: 0 4px;
71+
}
72+
`;
73+
document.head.appendChild(style);
74+
75+
const pwaWrapper = document.createElement('div');
76+
pwaWrapper.id = 'pwa-mini-banner';
77+
pwaWrapper.className = 'pwa-sticky-bar';
78+
pwaWrapper.innerHTML = `
79+
<div class="pwa-bar-content">
80+
<div class="pwa-bar-info">
81+
<span class="pwa-bar-icon">📊</span>
82+
<div class="pwa-bar-text">
83+
<strong>QuantVAT App</strong>
84+
<span>Install for instant access</span>
85+
</div>
86+
</div>
87+
<div style="display: flex; align-items: center; gap: 8px;">
88+
<button id="btn-pwa-install" class="btn-pwa-add">${isIOS ? 'Show' : 'Add'}</button>
89+
<button id="btn-pwa-close-trigger" class="btn-pwa-close">×</button>
90+
</div>
91+
</div>
92+
`;
93+
document.body.appendChild(pwaWrapper);
94+
setTimeout(() => pwaWrapper.classList.add('visible'), 100);
95+
96+
document.getElementById('btn-pwa-install').addEventListener('click', async () => {
97+
if (isIOS) {
98+
alert("To install: Tap the 'Share' icon and select 'Add to Home Screen'.");
99+
return;
100+
}
101+
if (!deferredPrompt) return;
102+
pwaWrapper.classList.remove('visible');
103+
deferredPrompt.prompt();
104+
await deferredPrompt.userChoice;
105+
deferredPrompt = null;
106+
});
107+
108+
document.getElementById('btn-pwa-close-trigger').addEventListener('click', () => {
109+
pwaWrapper.classList.remove('visible');
110+
localStorage.setItem('pwa_dismissed_at', Date.now());
111+
setTimeout(() => {
112+
pwaWrapper.remove();
113+
style.remove();
114+
}, 600);
115+
});
116+
}
117+
};
118+
119+
if ('requestIdleCallback' in window) {
120+
window.requestIdleCallback(performInjection);
121+
} else {
122+
window.addEventListener('load', performInjection);
123+
}
124+
})();
125+
</script>

0 commit comments

Comments
 (0)