Додані повідомлення та перепрацьована структура застосунку та api
This commit is contained in:
301
web/lib/customElements/pwaInstallBanner.js
Normal file
301
web/lib/customElements/pwaInstallBanner.js
Normal file
@@ -0,0 +1,301 @@
|
||||
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);
|
||||
Reference in New Issue
Block a user