From 5162692902a47356b2168a4fefe95fc7f4cf0f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 9 Oct 2026 01:02:15 -0400 Subject: [PATCH] Site: source archives, macOS 15 open steps, contrast test in both themes (R2.1) --- site/e2e/night.spec.ts | 46 ++++++++++++++++++++++-------------------- site/e2e/text.spec.ts | 8 +++++--- site/src/main.ts | 15 +++++++++----- site/src/text.ts | 6 ++++-- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/site/e2e/night.spec.ts b/site/e2e/night.spec.ts index 0a2fb13..8082d94 100644 --- a/site/e2e/night.spec.ts +++ b/site/e2e/night.spec.ts @@ -61,29 +61,31 @@ test("the lamp turns the page dark in a wave", async ({ page }) => { await expect(page.locator("html")).toHaveCSS("background-color", "rgb(37, 37, 37)"); }); -test("dark text keeps 4.5:1 against the page", async ({ page }) => { - await page.emulateMedia({ colorScheme: "dark" }); - await open(page); - const worst = await page.evaluate(() => { - const parse = (c: string) => c.match(/[\d.]+/g)!.slice(0, 3).map(Number); - const lum = (c: string) => { - const [r, g, b] = parse(c).map((v) => { - const s = v / 255; - return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4; - }); - return 0.2126 * r + 0.7152 * g + 0.0722 * b; - }; - const page = lum(getComputedStyle(document.documentElement).backgroundColor); - const ratios = [...document.querySelectorAll("h1, h2, h3, p, a, li, button")] - .filter((el) => el.textContent?.trim() && getComputedStyle(el).color !== "rgba(0, 0, 0, 0)") - .map((el) => { - const text = lum(getComputedStyle(el).color); - return { ratio: (Math.max(text, page) + 0.05) / (Math.min(text, page) + 0.05), text: el.textContent }; - }); - return ratios.sort((a, b) => a.ratio - b.ratio)[0]; - }); - expect(worst.ratio, String(worst.text)).toBeGreaterThanOrEqual(4.5); +for (const scheme of ["light", "dark"] as const) { + test(`${scheme} text and links keep 4.5:1 against the page`, async ({ page }) => { + await page.emulateMedia({ colorScheme: scheme }); + await open(page); + const worst = await page.evaluate(() => { + const parse = (c: string) => c.match(/[\d.]+/g)!.slice(0, 3).map(Number); + const lum = (c: string) => { + const [r, g, b] = parse(c).map((v) => { + const s = v / 255; + return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4; + }); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + }; + const page = lum(getComputedStyle(document.documentElement).backgroundColor); + const ratios = [...document.querySelectorAll("h1, h2, h3, p, a, li, button")] + .filter((el) => el.textContent?.trim() && getComputedStyle(el).color !== "rgba(0, 0, 0, 0)") + .map((el) => { + const text = lum(getComputedStyle(el).color); + return { ratio: (Math.max(text, page) + 0.05) / (Math.min(text, page) + 0.05), text: el.textContent }; + }); + return ratios.sort((a, b) => a.ratio - b.ratio)[0]; + }); + expect(worst.ratio, String(worst.text)).toBeGreaterThanOrEqual(4.5); }); +} test("the system scheme sets the first theme; the lamp's choice stays", async ({ page }) => { await page.emulateMedia({ colorScheme: "dark" }); diff --git a/site/e2e/text.spec.ts b/site/e2e/text.spec.ts index 5ff9c16..240cc9c 100644 --- a/site/e2e/text.spec.ts +++ b/site/e2e/text.spec.ts @@ -4,6 +4,7 @@ import { TEXT, type Key, type Lang } from "../src/text.ts"; const REPO = "https://github.com/ZacharyZhang-NY/ElyOffice"; const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"]; const dmg = (app: string) => `${REPO}/releases/download/v0.1.0/${app}-0.1.0-arm64.dmg`; +const tarball = (kind: string) => `${REPO}/releases/download/v0.1.0/ElyOffice-0.1.0-${kind}.tar.gz`; test.use({ reducedMotion: "reduce" }); @@ -84,11 +85,12 @@ test.describe("English locale", () => { for (const [i, app] of APPS.entries()) { await expect(page.locator(".tour .get").nth(i)).toHaveAttribute("href", dmg(app)); } - await expect(page.locator("#download ul a")).toHaveText([...APPS, TEXT.en.source]); + await expect(page.locator("#download ul a")).toHaveText([...APPS, TEXT.en.source, TEXT.en.upstream]); for (const [i, app] of APPS.entries()) { await expect(page.locator("#download ul a").nth(i)).toHaveAttribute("href", dmg(app)); } - await expect(page.locator("[data-t=source]")).toHaveAttribute("href", REPO); + await expect(page.locator("[data-t=source]")).toHaveAttribute("href", tarball("source")); + await expect(page.locator("[data-t=upstream]")).toHaveAttribute("href", tarball("upstream-source")); await expect(page.locator(".hero > a")).toHaveText("GitHub"); await expect(page.locator(".hero > a")).toHaveAttribute("href", REPO); }); @@ -97,7 +99,7 @@ test.describe("English locale", () => { await page.goto("/"); const hrefs = await page.locator("a[href^='http']").evaluateAll((as) => as.map((a) => (a as HTMLAnchorElement).href)); const unique = [...new Set(hrefs)]; - expect(unique.sort()).toEqual([REPO, ...APPS.map(dmg)].sort()); + expect(unique.sort()).toEqual([REPO, ...APPS.map(dmg), tarball("source"), tarball("upstream-source")].sort()); for (const url of unique) { const res = await request.head(url); expect(res.status(), url).toBeLessThan(400); diff --git a/site/src/main.ts b/site/src/main.ts index 1a21842..a725457 100644 --- a/site/src/main.ts +++ b/site/src/main.ts @@ -42,11 +42,16 @@ for (const name of APPS) { li.append(a); list.append(li); } -const source = said("a", "source"); -source.href = REPO; -const li = document.createElement("li"); -li.append(source); -list.append(li); +for (const [key, file] of [ + ["source", "ElyOffice-0.1.0-source.tar.gz"], + ["upstream", "ElyOffice-0.1.0-upstream-source.tar.gz"], +] as const) { + const a = said("a", key); + a.href = `${RELEASE}/${file}`; + const li = document.createElement("li"); + li.append(a); + list.append(li); +} footer.append(version, said("p", "platforms"), said("p", "needs"), said("p", "unsigned"), list); const toggle = said("button", "other"); diff --git a/site/src/text.ts b/site/src/text.ts index 93722d3..a18a9ab 100644 --- a/site/src/text.ts +++ b/site/src/text.ts @@ -15,8 +15,9 @@ const en = { download: "Download", platforms: "Out now for macOS. Windows and Linux are coming soon.", needs: "macOS 14 or later, Apple silicon.", - unsigned: "Not notarized. The first time, Control-click the app and choose Open.", + unsigned: "Not notarized. If macOS blocks the app, open System Settings › Privacy & Security and click Open Anyway.", source: "Source code", + upstream: "Upstream source", shot: "screenshot", other: "中文", roads: "Drag a file down the road.", @@ -52,8 +53,9 @@ const zh: typeof en = { download: "下载", platforms: "macOS 版已发布。Windows 与 Linux 版即将推出。", needs: "macOS 14 或更新,Apple 芯片。", - unsigned: "未经公证。第一次打开时,按住 Control 点按应用,选“打开”。", + unsigned: "未经公证。macOS 拦下应用时,打开“系统设置 › 隐私与安全性”,点“仍要打开”。", source: "源代码", + upstream: "上游源码", shot: "截图", other: "English", roads: "把文件沿着路拖过去。",