301 lines
12 KiB
JavaScript
301 lines
12 KiB
JavaScript
class PwaInstallBanner extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' });
|
||
this.deferredPrompt = null;
|
||
this.STORAGE_KEY = 'PwaInstallBanner'; // Визначаємо ключ localStorage
|
||
this.isInStandaloneMode = () => ('standalone' in window.navigator && window.navigator.standalone === true);
|
||
this.os = this.detectOS();
|
||
}
|
||
|
||
connectedCallback() {
|
||
// Додаємо стилі та розмітку до Shadow DOM
|
||
this.shadowRoot.innerHTML = this.getStyles() + this.getTemplate();
|
||
|
||
this.elements = {
|
||
backdrop: this.shadowRoot.getElementById('blur-backdrop'),
|
||
installOverlay: this.shadowRoot.getElementById('pwa-install-overlay'),
|
||
iosOverlay: this.shadowRoot.getElementById('pwa-ios-overlay'),
|
||
installButton: this.shadowRoot.getElementById('pwa-install-button'),
|
||
closeButton: this.shadowRoot.getElementById('pwa-close-button'),
|
||
iosCloseButton: this.shadowRoot.getElementById('pwa-ios-close-button'),
|
||
};
|
||
|
||
this.setupListeners();
|
||
this.checkInitialDisplay();
|
||
}
|
||
|
||
// --- Утиліти ---
|
||
|
||
detectOS() {
|
||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
|
||
return 'iOS';
|
||
}
|
||
// ... (можна додати Android, Windows, але для PWA нас цікавить в першу чергу iOS)
|
||
return 'Other';
|
||
}
|
||
|
||
shouldShowBanner() {
|
||
return localStorage.getItem(this.STORAGE_KEY) !== 'false';
|
||
}
|
||
|
||
checkInitialDisplay() {
|
||
if (!this.shouldShowBanner()) {
|
||
return; // Не показуємо, якщо localStorage = 'false'
|
||
}
|
||
|
||
// Логіка для iOS
|
||
if (this.os === 'iOS' && !this.isInStandaloneMode()) {
|
||
// Затримка відображення, як у вихідному коді
|
||
setTimeout(() => {
|
||
this.openPopup(this.elements.iosOverlay);
|
||
}, 1000);
|
||
}
|
||
}
|
||
|
||
openPopup(overlayElement) {
|
||
this.elements.backdrop.classList.remove('pwa-hidden');
|
||
overlayElement.classList.remove('pwa-hidden');
|
||
document.body.classList.add('modal-open');
|
||
}
|
||
|
||
closePopup = () => {
|
||
this.elements.installOverlay.classList.add('pwa-hidden');
|
||
this.elements.iosOverlay.classList.add('pwa-hidden');
|
||
this.elements.backdrop.classList.add('pwa-hidden');
|
||
document.body.classList.remove('modal-open');
|
||
this.deferredPrompt = null;
|
||
}
|
||
|
||
// --- Обробники подій ---
|
||
|
||
setupListeners() {
|
||
window.addEventListener("beforeinstallprompt", this.handleBeforeInstallPrompt);
|
||
|
||
// Обробники кнопок
|
||
this.elements.installButton.addEventListener("click", this.handleInstallClick);
|
||
this.elements.closeButton.addEventListener("click", this.closePopup);
|
||
this.elements.iosCloseButton.addEventListener('click', this.closePopup);
|
||
}
|
||
|
||
handleBeforeInstallPrompt = (e) => {
|
||
// Вихідний код перевіряв localStorage, але для простоти прикладу я її пропускаю.
|
||
if (!this.shouldShowBanner()) {
|
||
return; // Не показуємо, якщо localStorage = 'false'
|
||
}
|
||
|
||
e.preventDefault();
|
||
this.deferredPrompt = e;
|
||
|
||
// Показуємо стандартний банер, якщо доступно і не в режимі iOS
|
||
if (this.os !== 'iOS') {
|
||
this.openPopup(this.elements.installOverlay);
|
||
}
|
||
}
|
||
|
||
handleInstallClick = async () => {
|
||
if (!this.deferredPrompt) return;
|
||
|
||
this.deferredPrompt.prompt();
|
||
const { outcome } = await this.deferredPrompt.userChoice;
|
||
console.log(`[APP] Результат встановлення PWA: ${outcome}`);
|
||
|
||
this.closePopup();
|
||
}
|
||
|
||
// --- Шаблон (Template) та Стилі (Styles) ---
|
||
|
||
getTemplate() {
|
||
// HTML розмітка з вихідного коду
|
||
return `
|
||
<div id="blur-backdrop" class="pwa-hidden"></div>
|
||
<div id="pwa-install-overlay" class="pwa-overlay pwa-hidden">
|
||
<div class="popup">
|
||
<h2>Встановити застосунок?</h2>
|
||
<p>Додайте його на головний екран для швидкого доступу.</p>
|
||
<div>
|
||
<button id="pwa-install-button">Встановити</button>
|
||
<button id="pwa-close-button">Пізніше</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="pwa-ios-overlay" class="pwa-overlay pwa-hidden">
|
||
<div class="popup">
|
||
<h2>Встановлення застосунку</h2>
|
||
<p>Щоб встановити застосунок, виконайте наступні кроки:</p>
|
||
|
||
<ol>
|
||
<li>1. Відкрийте посилання в браузері Safari.</li>
|
||
<li>
|
||
2. Натисніть кнопку
|
||
<span>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
|
||
<path
|
||
d="M 14.984375 1 A 1.0001 1.0001 0 0 0 14.292969 1.2929688 L 10.292969 5.2929688 A 1.0001 1.0001 0 1 0 11.707031 6.7070312 L 14 4.4140625 L 14 17 A 1.0001 1.0001 0 1 0 16 17 L 16 4.4140625 L 18.292969 6.7070312 A 1.0001 1.0001 0 1 0 19.707031 5.2929688 L 15.707031 1.2929688 A 1.0001 1.0001 0 0 0 14.984375 1 z M 9 9 C 7.3550302 9 6 10.35503 6 12 L 6 24 C 6 25.64497 7.3550302 27 9 27 L 21 27 C 22.64497 27 24 25.64497 24 24 L 24 12 C 24 10.35503 22.64497 9 21 9 L 19 9 L 19 11 L 21 11 C 21.56503 11 22 11.43497 22 12 L 22 24 C 22 24.56503 21.56503 25 21 25 L 9 25 C 8.4349698 25 8 24.56503 8 24 L 8 12 C 8 11.43497 8.4349698 11 9 11 L 11 11 L 11 9 L 9 9 z"
|
||
/>
|
||
</svg>
|
||
</span>
|
||
в нижній частині екрана Safari.
|
||
</li>
|
||
<li>
|
||
3. У меню, що з’явиться, виберіть
|
||
<span>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||
<path
|
||
d="M 6 3 C 4.3550302 3 3 4.3550302 3 6 L 3 18 C 3 19.64497 4.3550302 21 6 21 L 18 21 C 19.64497 21 21 19.64497 21 18 L 21 6 C 21 4.3550302 19.64497 3 18 3 L 6 3 z M 6 5 L 18 5 C 18.56503 5 19 5.4349698 19 6 L 19 18 C 19 18.56503 18.56503 19 18 19 L 6 19 C 5.4349698 19 5 18.56503 5 18 L 5 6 C 5 5.4349698 5.4349698 5 6 5 z M 11.984375 6.9863281 A 1.0001 1.0001 0 0 0 11 8 L 11 11 L 8 11 A 1.0001 1.0001 0 1 0 8 13 L 11 13 L 11 16 A 1.0001 1.0001 0 1 0 13 16 L 13 13 L 16 13 A 1.0001 1.0001 0 1 0 16 11 L 13 11 L 13 8 A 1.0001 1.0001 0 0 0 11.984375 6.9863281 z"
|
||
/>
|
||
</svg>
|
||
</span>
|
||
«На Початковий екран».
|
||
</li>
|
||
</ol>
|
||
<div>
|
||
<button id="pwa-ios-close-button">Зрозуміло</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
getStyles() {
|
||
// CSS стилі, які були у вихідному коді, але адаптовані для Shadow DOM
|
||
// Примітки:
|
||
// 1. Змінні CSS (наприклад, --ColorThemes0) мають бути визначені в основному документі
|
||
// або передані через властивості, інакше вони не працюватимуть в Shadow DOM.
|
||
// Я залишаю їх як є, припускаючи, що вони глобально доступні.
|
||
// 2. Стилі для body.modal-open потрібно додати в основний CSS.
|
||
|
||
return `
|
||
<style>
|
||
#blur-backdrop {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
backdrop-filter: blur(8px);
|
||
z-index: 9998;
|
||
}
|
||
|
||
.pwa-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.pwa-overlay>.popup {
|
||
background: var(--ColorThemes0, #ffffff); /* Fallback */
|
||
padding: 24px 32px;
|
||
border-radius: var(--border-radius, 15px);
|
||
max-width: 90%;
|
||
width: 320px;
|
||
text-align: center;
|
||
font-family: sans-serif;
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||
animation: fadeIn 0.3s ease-out;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.pwa-overlay>.popup h2 {
|
||
margin-bottom: 12px;
|
||
color: var(--ColorThemes3, #333);
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.pwa-overlay>.popup p {
|
||
margin-bottom: 10px;
|
||
color: var(--ColorThemes3, #333);
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.pwa-overlay>.popup ol {
|
||
text-align: justify;
|
||
font-size: var(--FontSize4, 15px);
|
||
margin-bottom: 10px;
|
||
max-width: 290px;
|
||
padding-left: 0; /* Виправлення відступу списку */
|
||
}
|
||
|
||
.pwa-overlay>.popup li {
|
||
list-style-type: none;
|
||
font-size: var(--FontSize3, 14px);
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.pwa-overlay>.popup li span {
|
||
vertical-align: middle;
|
||
display: inline-block;
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
.pwa-overlay>.popup li span svg {
|
||
fill: var(--PrimaryColor, #007bff);
|
||
}
|
||
|
||
.pwa-overlay>.popup>div {
|
||
margin-top: 10px;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.pwa-overlay>.popup>div>button {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: calc(var(--border-radius, 15px) - 8px);
|
||
cursor: pointer;
|
||
font-size: var(--FontSize3, 14px);
|
||
}
|
||
|
||
#pwa-install-button {
|
||
background-color: var(--PrimaryColor, #007bff);
|
||
color: var(--PrimaryColorText, #ffffff);
|
||
}
|
||
|
||
#pwa-close-button,
|
||
#pwa-ios-close-button {
|
||
background-color: #ccc;
|
||
color: #333;
|
||
}
|
||
|
||
.pwa-hidden {
|
||
display: none !important; /* Важливо для скриптів */
|
||
}
|
||
|
||
@media (max-width: 450px) {
|
||
.pwa-overlay>.popup {
|
||
padding: 17px 10px;
|
||
}
|
||
|
||
.pwa-overlay>.popup h2 {
|
||
font-size: 22px;
|
||
}
|
||
|
||
.pwa-overlay>.popup p {
|
||
font-size: var(--FontSize4, 15px);
|
||
}
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
</style>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Реєстрація веб-компонента
|
||
customElements.define('pwa-install-banner', PwaInstallBanner); |