document.getElementById(id);
@@ -20,7 +20,9 @@ const sApikey = $("s-apikey");
const eyeBtn = $("eye-btn");
const saveBtn = $("save-btn");
const themeToggle = $("theme-toggle");
+const mastodonVisToggle = $("mastodon-vis-toggle");
const mastodonToggle = $("mastodon-toggle");
+const mastodonRow = mastodonToggle.closest(".field");
// ── Settings ─────────────────────────────────────────────────────────────────
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() {
try {
const raw = localStorage.getItem("spo-settings");
if (raw) settings = { ...settings, ...JSON.parse(raw) };
} catch {}
applyTheme(settings.theme);
+ applyMastodonVisibility(settings.showMastodon ?? true);
updateBadge();
mastodonToggle.checked = settings.mastodonPost ?? false;
}
@@ -80,6 +95,7 @@ function openModal() {
sUsername.value = settings.username;
sApikey.value = settings.apiKey;
updateThemeToggle(settings.theme);
+ updateMastodonVisToggle(settings.showMastodon ?? true);
overlay.classList.add("open");
document.body.style.overflow = "hidden";
// Focus first empty field
@@ -121,6 +137,15 @@ mastodonToggle.addEventListener("change", () => {
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) => {
const btn = e.target.closest(".theme-btn");
if (!btn) return;
@@ -280,6 +305,36 @@ if ("serviceWorker" in navigator) {
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 ──────────────────────────────────────────────────────────────────────
loadSettings();
diff --git a/style.css b/style.css
index 66d9e33..d644ea4 100644
--- a/style.css
+++ b/style.css
@@ -608,6 +608,43 @@ input::placeholder {
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-toggle {
display: flex;