Testing PWA install prompt
This commit is contained in:
parent
aca0d2dc4f
commit
c115121aa7
3 changed files with 127 additions and 1 deletions
34
index.html
34
index.html
|
|
@ -49,6 +49,13 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
<!-- Install prompt -->
|
||||||
|
<div class="install-banner" id="install-banner">
|
||||||
|
<span class="install-banner-icon">📲</span>
|
||||||
|
<span id="install-banner-text"></span>
|
||||||
|
<button class="install-banner-close" id="install-banner-close" aria-label="Dismiss">✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Emoji picker -->
|
<!-- Emoji picker -->
|
||||||
<div class="emoji-section">
|
<div class="emoji-section">
|
||||||
<div
|
<div
|
||||||
|
|
@ -244,6 +251,33 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label>Display Mastodon option</label>
|
||||||
|
<div
|
||||||
|
class="theme-toggle"
|
||||||
|
id="mastodon-vis-toggle"
|
||||||
|
role="group"
|
||||||
|
aria-label="Show or hide the Mastodon option"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="theme-btn"
|
||||||
|
data-mastodon-vis="show"
|
||||||
|
type="button"
|
||||||
|
aria-pressed="true"
|
||||||
|
>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="theme-btn"
|
||||||
|
data-mastodon-vis="hide"
|
||||||
|
type="button"
|
||||||
|
aria-pressed="false"
|
||||||
|
>
|
||||||
|
Hide
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>Appearance</label>
|
<label>Appearance</label>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
57
script.js
57
script.js
|
|
@ -1,6 +1,6 @@
|
||||||
// ── State ────────────────────────────────────────────────────────────────────
|
// ── State ────────────────────────────────────────────────────────────────────
|
||||||
let emoji = "💬";
|
let emoji = "💬";
|
||||||
let settings = { username: "", apiKey: "", theme: "auto", mastodonPost: false };
|
let settings = { username: "", apiKey: "", theme: "auto", mastodonPost: false, showMastodon: true };
|
||||||
|
|
||||||
// ── DOM ──────────────────────────────────────────────────────────────────────
|
// ── DOM ──────────────────────────────────────────────────────────────────────
|
||||||
const $ = (id) => document.getElementById(id);
|
const $ = (id) => document.getElementById(id);
|
||||||
|
|
@ -20,7 +20,9 @@ const sApikey = $("s-apikey");
|
||||||
const eyeBtn = $("eye-btn");
|
const eyeBtn = $("eye-btn");
|
||||||
const saveBtn = $("save-btn");
|
const saveBtn = $("save-btn");
|
||||||
const themeToggle = $("theme-toggle");
|
const themeToggle = $("theme-toggle");
|
||||||
|
const mastodonVisToggle = $("mastodon-vis-toggle");
|
||||||
const mastodonToggle = $("mastodon-toggle");
|
const mastodonToggle = $("mastodon-toggle");
|
||||||
|
const mastodonRow = mastodonToggle.closest(".field");
|
||||||
|
|
||||||
// ── Settings ─────────────────────────────────────────────────────────────────
|
// ── Settings ─────────────────────────────────────────────────────────────────
|
||||||
function applyTheme(theme) {
|
function applyTheme(theme) {
|
||||||
|
|
@ -44,12 +46,25 @@ function updateThemeToggle(theme) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyMastodonVisibility(show) {
|
||||||
|
mastodonRow.style.display = show ? "" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMastodonVisToggle(show) {
|
||||||
|
mastodonVisToggle.querySelectorAll(".theme-btn").forEach((btn) => {
|
||||||
|
const active = (btn.dataset.mastodonVis === "show") === show;
|
||||||
|
btn.classList.toggle("active", active);
|
||||||
|
btn.setAttribute("aria-pressed", active ? "true" : "false");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem("spo-settings");
|
const raw = localStorage.getItem("spo-settings");
|
||||||
if (raw) settings = { ...settings, ...JSON.parse(raw) };
|
if (raw) settings = { ...settings, ...JSON.parse(raw) };
|
||||||
} catch {}
|
} catch {}
|
||||||
applyTheme(settings.theme);
|
applyTheme(settings.theme);
|
||||||
|
applyMastodonVisibility(settings.showMastodon ?? true);
|
||||||
updateBadge();
|
updateBadge();
|
||||||
mastodonToggle.checked = settings.mastodonPost ?? false;
|
mastodonToggle.checked = settings.mastodonPost ?? false;
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +95,7 @@ function openModal() {
|
||||||
sUsername.value = settings.username;
|
sUsername.value = settings.username;
|
||||||
sApikey.value = settings.apiKey;
|
sApikey.value = settings.apiKey;
|
||||||
updateThemeToggle(settings.theme);
|
updateThemeToggle(settings.theme);
|
||||||
|
updateMastodonVisToggle(settings.showMastodon ?? true);
|
||||||
overlay.classList.add("open");
|
overlay.classList.add("open");
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
// Focus first empty field
|
// Focus first empty field
|
||||||
|
|
@ -121,6 +137,15 @@ mastodonToggle.addEventListener("change", () => {
|
||||||
try { localStorage.setItem("spo-settings", JSON.stringify(settings)); } catch {}
|
try { localStorage.setItem("spo-settings", JSON.stringify(settings)); } catch {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mastodonVisToggle.addEventListener("click", (e) => {
|
||||||
|
const btn = e.target.closest(".theme-btn");
|
||||||
|
if (!btn) return;
|
||||||
|
const show = btn.dataset.mastodonVis === "show";
|
||||||
|
settings.showMastodon = show;
|
||||||
|
applyMastodonVisibility(show);
|
||||||
|
updateMastodonVisToggle(show);
|
||||||
|
});
|
||||||
|
|
||||||
themeToggle.addEventListener("click", (e) => {
|
themeToggle.addEventListener("click", (e) => {
|
||||||
const btn = e.target.closest(".theme-btn");
|
const btn = e.target.closest(".theme-btn");
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
|
@ -280,6 +305,36 @@ if ("serviceWorker" in navigator) {
|
||||||
navigator.serviceWorker.register("sw.js").catch(() => {});
|
navigator.serviceWorker.register("sw.js").catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Install banner ────────────────────────────────────────────────────────────
|
||||||
|
(function () {
|
||||||
|
const isPWA =
|
||||||
|
window.matchMedia("(display-mode: standalone)").matches ||
|
||||||
|
navigator.standalone === true;
|
||||||
|
if (isPWA) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (localStorage.getItem("spo-install-dismissed")) return;
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
const ua = navigator.userAgent;
|
||||||
|
let msg = null;
|
||||||
|
if (/iPad|iPhone|iPod/.test(ua)) {
|
||||||
|
msg = 'Tap Share ↑ at the bottom of Safari, then "Add to Home Screen" to install this app.';
|
||||||
|
} else if (/Android/.test(ua)) {
|
||||||
|
msg = 'Tap the ⋮ menu in Chrome, then "Add to Home Screen" to install this app.';
|
||||||
|
}
|
||||||
|
if (!msg) return;
|
||||||
|
|
||||||
|
const banner = $("install-banner");
|
||||||
|
$("install-banner-text").textContent = msg;
|
||||||
|
banner.classList.add("visible");
|
||||||
|
|
||||||
|
$("install-banner-close").addEventListener("click", () => {
|
||||||
|
banner.classList.remove("visible");
|
||||||
|
try { localStorage.setItem("spo-install-dismissed", "1"); } catch {}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
// ── Init ──────────────────────────────────────────────────────────────────────
|
// ── Init ──────────────────────────────────────────────────────────────────────
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
|
|
||||||
37
style.css
37
style.css
|
|
@ -608,6 +608,43 @@ input::placeholder {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Install banner ────────────────────────────────────────────────────── */
|
||||||
|
.install-banner {
|
||||||
|
display: none;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: flex-start;
|
||||||
|
background: var(--accent-dim);
|
||||||
|
border: 1.5px solid color-mix(in srgb, var(--accent) 30%, transparent);
|
||||||
|
border-radius: var(--r);
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-banner.visible {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-banner-icon {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-banner-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 2px 0 0;
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Theme segmented control ───────────────────────────────────────────── */
|
/* ── Theme segmented control ───────────────────────────────────────────── */
|
||||||
.theme-toggle {
|
.theme-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue