diff --git a/internal/web/embed_test.go b/internal/web/embed_test.go
index 4194a07..53baec5 100644
--- a/internal/web/embed_test.go
+++ b/internal/web/embed_test.go
@@ -25,6 +25,29 @@ func TestLandingUsesVelarisNotThree(t *testing.T) {
}
}
+func TestLandingIsMobileAndDarkThemeSafe(t *testing.T) {
+ b, err := FS.ReadFile("static/index.html")
+ if err != nil {
+ t.Fatal(err)
+ }
+ html := string(b)
+ if !strings.Contains(html, `name="viewport"`) || !strings.Contains(html, "width=device-width") {
+ t.Fatal("landing is missing a mobile viewport")
+ }
+ if !strings.Contains(html, "color-scheme: dark") {
+ t.Fatal("dark theme is missing color-scheme")
+ }
+ if !strings.Contains(html, `--section: #0c0b10`) {
+ t.Fatal("dark theme is missing a solid section background")
+ }
+ if !strings.Contains(html, `id="landing-menu"`) || !strings.Contains(html, "landing-nav") {
+ t.Fatal("landing is missing a mobile menu")
+ }
+ if !strings.Contains(html, "@media (max-width: 1080px)") || !strings.Contains(html, "@media (max-width: 800px)") {
+ t.Fatal("landing is missing tablet and phone breakpoints")
+ }
+}
+
func TestLandingUsesAppLogo(t *testing.T) {
if _, err := FS.ReadFile("static/assets/syncidian.png"); err != nil {
t.Fatal("web assets must include syncidian.png")
diff --git a/internal/web/static/index.html b/internal/web/static/index.html
index 861c4c9..27cdc38 100644
--- a/internal/web/static/index.html
+++ b/internal/web/static/index.html
@@ -75,6 +75,7 @@
@@ -566,7 +685,8 @@
Syncidian
-
+
+
Privacy
Story
@@ -835,6 +955,34 @@
Setup walkthrough
if (typeof window.gtag !== "function") return;
window.gtag("event", name, params || {});
}
+function closeLandingMenu() {
+ const head = document.querySelector("#landing .site-head");
+ const btn = $("landing-menu");
+ if (!head || !btn) return;
+ head.classList.remove("nav-open");
+ btn.setAttribute("aria-expanded", "false");
+ btn.setAttribute("aria-label", "Open menu");
+ btn.textContent = "Menu";
+}
+function bindLandingMenu() {
+ const btn = $("landing-menu");
+ const head = document.querySelector("#landing .site-head");
+ const nav = $("landing-nav");
+ if (!btn || !head || !nav) return;
+ btn.setAttribute("aria-label", "Open menu");
+ btn.onclick = () => {
+ const open = head.classList.toggle("nav-open");
+ btn.setAttribute("aria-expanded", open ? "true" : "false");
+ btn.setAttribute("aria-label", open ? "Close menu" : "Open menu");
+ btn.textContent = open ? "Close" : "Menu";
+ };
+ nav.querySelectorAll("a").forEach((a) => {
+ a.addEventListener("click", closeLandingMenu);
+ });
+ window.addEventListener("resize", () => {
+ if (window.innerWidth > 1080) closeLandingMenu();
+ });
+}
function bindLandingAnalytics() {
document.querySelectorAll("[data-cta]").forEach((el) => {
el.addEventListener("click", () => {
@@ -1200,6 +1348,7 @@
iOS / iPadOS
async function boot() {
applyTheme();
+ bindLandingMenu();
document.querySelectorAll(".theme-toggle").forEach((b) => { b.onclick = toggleTheme; });
const nerdsBtn = $("nerds-toggle");
if (nerdsBtn) {