#!/usr/bin/env python3 """Shared page-shell helpers for inline HTML templates.""" PAGE_LINKS = ( ("search", "Search", "/"), ("config", "Config", "/config"), ("watchlist", "Watchlist", "/watchlist"), ) BROWSER_API_HELPER = r""" async function api(path, options = {}) { const headers = new Headers(options.headers || {}); if (options.body && !headers.has("Content-Type")) { headers.set("Content-Type", "application/json"); } const response = await fetch(path, { ...options, headers }); const raw = await response.text(); let data = {}; if (raw) { try { data = JSON.parse(raw); } catch (_error) { data = { error: raw }; } } if (!response.ok) throw new Error(data.error || response.statusText || "Request failed"); return data; } """ BROWSER_POLL_HELPER = r""" function startSerialPoll(callback, intervalMs) { let inFlight = false; let active = true; let timer = null; const stop = () => { active = false; if (timer !== null) { window.clearTimeout(timer); timer = null; } }; const tick = async () => { if (!active || inFlight) { if (active) timer = window.setTimeout(tick, intervalMs); return; } inFlight = true; try { await callback(); } finally { inFlight = false; if (active) timer = window.setTimeout(tick, intervalMs); } }; window.addEventListener("pagehide", stop, { once: true }); window.addEventListener("beforeunload", stop, { once: true }); timer = window.setTimeout(tick, intervalMs); return { stop }; } """ def render_sidebar_brand(note, badge, badge_id=""): badge_attr = f' id="{badge_id}"' if badge_id else "" return ( '
{note}
\n" "