Add install banner
This commit is contained in:
@@ -187,3 +187,34 @@ document.getElementById("logout-btn").addEventListener("click", () => {
|
|||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
navigator.serviceWorker.register("/sw.js").catch(() => {});
|
navigator.serviceWorker.register("/sw.js").catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── PWA install banner ────────────────────────────────────────────────────────
|
||||||
|
const INSTALL_DISMISSED_KEY = "lg_install_dismissed";
|
||||||
|
let _deferredInstallPrompt = null;
|
||||||
|
|
||||||
|
window.addEventListener("beforeinstallprompt", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (sessionStorage.getItem(INSTALL_DISMISSED_KEY)) return;
|
||||||
|
_deferredInstallPrompt = e;
|
||||||
|
document.getElementById("install-banner").classList.remove("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("install-btn").addEventListener("click", async () => {
|
||||||
|
const banner = document.getElementById("install-banner");
|
||||||
|
banner.classList.add("hidden");
|
||||||
|
if (!_deferredInstallPrompt) return;
|
||||||
|
_deferredInstallPrompt.prompt();
|
||||||
|
await _deferredInstallPrompt.userChoice;
|
||||||
|
_deferredInstallPrompt = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("install-dismiss").addEventListener("click", () => {
|
||||||
|
document.getElementById("install-banner").classList.add("hidden");
|
||||||
|
sessionStorage.setItem(INSTALL_DISMISSED_KEY, "1");
|
||||||
|
_deferredInstallPrompt = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("appinstalled", () => {
|
||||||
|
document.getElementById("install-banner").classList.add("hidden");
|
||||||
|
_deferredInstallPrompt = null;
|
||||||
|
});
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<title>Lagomare Gates</title>
|
<title>Lagomare Gates</title>
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/static/logo.svg" />
|
<link rel="icon" type="image/svg+xml" href="/static/logo.svg" />
|
||||||
<link rel="apple-touch-icon" href="/static/logo.svg" />
|
<link rel="apple-touch-icon" href="/static/mobile_icon.png" />
|
||||||
<link rel="stylesheet" href="/static/style.css" />
|
<link rel="stylesheet" href="/static/style.css" />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -143,6 +143,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ── PWA install banner ──────────────────────────────────────────────── -->
|
||||||
|
<div id="install-banner" class="install-banner hidden" role="banner" aria-label="Install app">
|
||||||
|
<div class="install-banner-body">
|
||||||
|
<img src="/static/logo.svg" alt="" class="install-banner-icon" />
|
||||||
|
<div class="install-banner-text">
|
||||||
|
<strong>Add to Home Screen</strong>
|
||||||
|
<span>Install Lagomare Gates for quick access</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="install-banner-actions">
|
||||||
|
<button id="install-dismiss" class="btn btn-ghost" style="font-size:.8rem;padding:.45rem .9rem">Later</button>
|
||||||
|
<button id="install-btn" class="btn btn-primary" style="font-size:.8rem;padding:.45rem .9rem">Install</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/static/app.js"></script>
|
<script src="/static/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -189,3 +189,67 @@ tr:last-child td { border-bottom: none; }
|
|||||||
|
|
||||||
/* ── Error text ────────────────────────────────────────────────────────────── */
|
/* ── Error text ────────────────────────────────────────────────────────────── */
|
||||||
.error-msg { color: var(--red); font-size: .85rem; margin-top: .5rem; }
|
.error-msg { color: var(--red); font-size: .85rem; margin-top: .5rem; }
|
||||||
|
|
||||||
|
/* ── PWA install banner ────────────────────────────────────────────────────── */
|
||||||
|
.install-banner {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1rem;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
max-width: 480px;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
padding: .9rem 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: .75rem;
|
||||||
|
z-index: 9000;
|
||||||
|
animation: banner-in .3s ease;
|
||||||
|
}
|
||||||
|
.install-banner.hidden { display: none !important; }
|
||||||
|
.install-banner-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: .75rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.install-banner-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.install-banner-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: .1rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.install-banner-text strong {
|
||||||
|
font-size: .9rem;
|
||||||
|
font-weight: 700;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.install-banner-text span {
|
||||||
|
font-size: .78rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.install-banner-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: .5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
@keyframes banner-in {
|
||||||
|
from { opacity: 0; transform: translateX(-50%) translateY(1rem); }
|
||||||
|
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user