Post

PWA

Create a popup for installing the PWA & Customize Site Manifest

PWA

Wait 4 seconds for the popup

1
<script src="/assets/js/pwa-popup.js" defer></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
document.addEventListener("DOMContentLoaded", () => {
  let deferredPrompt; // Store the install prompt event
  let popupDisplayed = false; // Ensure the popup shows only once

  // Create the popup dynamically
  const popup = document.createElement("div");
  popup.id = "install-pwa-popup";
  popup.innerHTML = `
    <div id="popup-content">
      <p id="popup-message">Use web-app for a better experience!</p>
      <div id="popup-buttons">
      <button id="install-pwa-yes">Install</button>
      <button id="install-pwa-no">Close</button>
      </div>
    </div>
  `;
  document.body.appendChild(popup);

  // Style the popup
  const popupStyles = `
  #install-pwa-popup {
    position: fixed;
    top: 90px;
    left: 50%;
    transform: translate(-50%, -50%); /* Center the popup */
    background: #b7b7c710;
    color: white;
    width: 100vw;
    padding: 10px; /* Minimal padding */
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    display: none;
    z-index: 1000;
  }
  
  #install-pwa-popup.show {
    display: block;
  }
  
  #popup-content {
    display: flex;
    flex-direction: column; /* Arrange items vertically */
    align-items: center; /* Center horizontally */
    justify-content: center; /* Center vertically */
    gap: 5px; /* Minimal spacing between items */
    width: auto; /* Ensure the content stays centered */
    max-width: 500px; /* Set a max width for the content */
    margin: 0 auto; /* Center content horizontally within the popup */
  }
  
  #popup-message {
    font-weight: bold;
    font-size: 20px;
  }
  
  #install-pwa-popup button {
    padding: 5px 10px; /* Minimal button padding */
    border: none;
    border-radius: 5px;
    cursor: pointer;
  }
  
  #install-pwa-yes {
    background-color: #4caf50;
    color: white;
  }
  
  #install-pwa-no {
    background-color: #f44336;
    color: white;
  }
  
  `;
  const styleSheet = document.createElement("style");
  // styleSheet.type = "text/css";
  styleSheet.innerText = popupStyles;
  document.head.appendChild(styleSheet);

  // Listen for the beforeinstallprompt event
  window.addEventListener("beforeinstallprompt", (e) => {
    e.preventDefault();
    deferredPrompt = e;

    // Show the popup after 4 seconds
    setTimeout(() => {
      if (!popupDisplayed && !window.matchMedia("(display-mode: standalone)").matches) {
        popup.classList.add("show"); // Show the popup by sliding it down
        popupDisplayed = true;
      }
    }, 4000); // 4-second delay
  });

  // Handle the Install button click
  document.getElementById("install-pwa-yes").addEventListener("click", async () => {
    if (deferredPrompt) {
      deferredPrompt.prompt();
      const choiceResult = await deferredPrompt.userChoice;
      if (choiceResult.outcome === "accepted") {
        console.log("User accepted the install prompt");
      } else {
        console.log("User dismissed the install prompt");
      }
      deferredPrompt = null; // Clear the event
    }
    popup.classList.remove("show"); // Hide the popup
  });

  // Handle the Close button click
  document.getElementById("install-pwa-no").addEventListener("click", () => {
    popup.classList.remove("show"); // Hide the popup
  });

  // Hide popup if app is installed
  window.addEventListener("appinstalled", () => {
    console.log("PWA installed");
    popup.classList.remove("show");
  });
});

Install to check manifest mods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

---
layout: compress
---

{% assign favicon_path = "/assets/img/favicons" | relative_url %}

{
  "name": "{{ site.title }}",
  "short_name": "{{ site.title }}",
  "id": "{{ site.title | slugify }}",
  "scope": "/",
  "description": "{{ site.description }}",
  "start_url": "{{ '/index.html' | relative_url }}",
  "theme_color": "#2a1e6b",
  "background_color": "#ffffff",
  "display_override": ["window-control-overlay", "fullscreen", "minimal-ui"],
  "display": "standalone",
  "orientation": "natural",
  "icons": [
    {
      "src": "{{ favicon_path }}/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "{{ favicon_path }}/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }],
    "screenshots": [
    {
      "src": "home.png",
      "sizes": "1366x768",
      "type": "image/png",
      "form_factor": "wide",
      "label": "Home screen showing main navigation and featured content"
    },
    {
      "src": "dash.png",
      "sizes": "1366x768",
      "type": "image/png",
      "form_factor": "wide",
      "label": "Dashboard view with blog and TOC"
    },
    {
      "src": "blog.png",
      "sizes": "411x670",
      "type": "image/png",
      "form_factor": "narrow",
      "label": "Blog Screen Mobile View"
    },
    {
      "src": "toc.png",
      "sizes": "411x670",
      "type": "image/png",
      "form_factor": "narrow",
      "label": "Blog screen showing toc mobile view"
    },
    {
      "src": "dash-m.png",
      "sizes": "411x670",
      "type": "image/png",
      "platform": "android",
      "label": "visible on android"
    }],
    "shortcuts": [
    {
      "name": "Home",
      "short_name": "Home",
      "url": "{{ '/index.html' | relative_url }}",
      "icons": [
        {
          "src": "{{ favicon_path }}/android-chrome-192x192.png",
          "sizes": "192x192",
          "type": "image/png"
        }
      ]
    },
    {
      "name": "Tools",
      "short_name": "Tools",
      "url": "{{ '/tools' | relative_url }}",
      "icons": [
        {
          "src": "{{ favicon_path }}/android-chrome-192x192.png",
          "sizes": "192x192",
          "type": "image/png"
        }
      ]
    }
  ]
}

To disable the update popup

1
<script src="/assets/js/auto-update.js" defer></script>
1
2
3
4
5
const toast = document.getElementById('notification');
toast.addEventListener('shown.bs.toast', () => {
    const button = toast.querySelector('.toast-body>button');
    button?.click();
});
This post is licensed under CC BY 4.0 by the author.