diff --git a/site/e2e/text.spec.ts b/site/e2e/text.spec.ts index 7bcde1f..a0dc75c 100644 --- a/site/e2e/text.spec.ts +++ b/site/e2e/text.spec.ts @@ -23,7 +23,8 @@ const keyed = (page: Page) => /** Asserts every keyed element reads in `lang`. */ async function reads(page: Page, lang: Lang) { await expect(page.locator("html")).toHaveAttribute("lang", lang === "zh" ? "zh-CN" : "en"); - await expect(page.locator("[data-t=count]")).toBeVisible(); + await expect(page.locator("[data-t=count]")).toHaveCount(2); + for (const c of await page.locator("[data-t=count]").all()) await expect(c).toBeVisible(); const found = await keyed(page); expect(found.length).toBeGreaterThan(0); for (const [key, text] of found) { @@ -94,13 +95,13 @@ test.describe("English locale", () => { expect(files).toEqual([]); }); - test("the download area names the newest version and all downloads", async ({ page }) => { + test("the hero and download area name the newest version and all downloads", async ({ page }) => { await page.goto("/"); await expect(page.locator("#download h2")).toHaveText(`Ely Office ${VERSION}`); - const count = page.locator("#download [data-t=count]"); - await expect(count).toHaveText("12,345 downloads so far."); + const counts = page.locator("[data-t=count]"); + await expect(counts).toHaveText(["12,345 downloads so far.", "12,345 downloads so far."]); await page.locator(".lang").click(); - await expect(count).toHaveText("已下载 12,345 次。"); + await expect(counts).toHaveText(["已下载 12,345 次。", "已下载 12,345 次。"]); }); test("a failed version read shows as an error", async ({ page }) => { @@ -109,7 +110,7 @@ test.describe("English locale", () => { await expect.poll(() => errors.length).toBe(1); expect(errors[0]).toContain("Gitea answered 500"); await expect(page.locator("#download h2")).toHaveText("Ely Office"); - await expect(page.locator("#download [data-t=count]")).toBeHidden(); + for (const c of await page.locator("[data-t=count]").all()) await expect(c).toBeHidden(); errors = []; }); @@ -145,6 +146,26 @@ test.describe("English locale", () => { }); }); +test("the hero links share one baseline in either language", async ({ browser }) => { + for (const locale of ["en-US", "zh-CN"]) { + const page = await browser.newPage({ locale, reducedMotion: "reduce" }); + await page.goto("/"); + const lines = await page.locator(".hero .links a").evaluateAll((as) => + as.map((a) => { + const mark = document.createElement("span"); + mark.style.display = "inline-block"; + a.prepend(mark); + const y = mark.getBoundingClientRect().bottom; + mark.remove(); + return y; + }), + ); + expect(lines).toHaveLength(2); + expect(Math.abs(lines[0] - lines[1]), locale).toBeLessThan(0.5); + await page.close(); + } +}); + test("the download area tells how to open an unnotarized app", async ({ browser }) => { for (const [locale, words] of [ ["en-US", ["System Settings", "Privacy & Security", "Open Anyway"]], diff --git a/site/src/main.ts b/site/src/main.ts index c6a4410..ddad563 100644 --- a/site/src/main.ts +++ b/site/src/main.ts @@ -18,15 +18,16 @@ if (!app) throw new Error("index.html has no #app"); const hero = document.createElement("header"); const title = document.createElement("h1"); title.textContent = "Ely Office"; -const source = document.createElement("a"); +const source = said("a", "source"); source.href = REPO; -source.textContent = "Source"; const download = said("a", "get"); download.href = RELEASES; const links = document.createElement("div"); links.className = "links"; links.append(download, source); -hero.append(title, said("p", "tagline"), said("p", "platforms"), links); +const heroCount = said("p", "count"); +heroCount.hidden = true; +hero.append(title, said("p", "tagline"), said("p", "platforms"), heroCount, links); const { section, host, svg } = tour(hero); rhythm(host, svg); @@ -60,7 +61,9 @@ say(lang); reveal([shelf]); void latest().then(({ version: v, downloads }) => { version.textContent = `Ely Office ${v}`; - count.dataset.n = String(downloads); - count.textContent = word(lang, "count", downloads); - count.hidden = false; + for (const el of [heroCount, count]) { + el.dataset.n = String(downloads); + el.textContent = word(lang, "count", downloads); + el.hidden = false; + } }); diff --git a/site/src/style.css b/site/src/style.css index c4ec1c7..75341f3 100644 --- a/site/src/style.css +++ b/site/src/style.css @@ -62,6 +62,7 @@ button:focus-visible { .hero .links { display: flex; + align-items: baseline; gap: 1.5rem; } diff --git a/site/src/text.ts b/site/src/text.ts index e9a821c..3796a0f 100644 --- a/site/src/text.ts +++ b/site/src/text.ts @@ -18,6 +18,7 @@ const en = { unsigned: "Not notarized. If macOS blocks the app, open System Settings › Privacy & Security and click Open Anyway.", get: "Download", count: "{n} downloads so far.", + source: "Source", other: "中文", roads: "Drag a file down the road.", fileDoc: "ElyDoc file", @@ -55,6 +56,7 @@ const zh: typeof en = { unsigned: "未经公证。macOS 拦下应用时,打开“系统设置 › 隐私与安全性”,点“仍要打开”。", get: "前往下载", count: "已下载 {n} 次。", + source: "源码", other: "English", roads: "把文件沿着路拖过去。", fileDoc: "ElyDoc 文件",