From 991bfb78ad8a36b3de66a9ec55e795a90ccaa686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Tue, 13 Oct 2026 13:52:35 -0400 Subject: [PATCH] Site: download and Gitea icons on the hero links [skip ci] The Gitea mark is its logo's two cup paths in the link color. Co-Authored-By: Claude Opus 5.5 --- site/e2e/text.spec.ts | 11 ++++++++++- site/src/icons.ts | 18 ++++++++++++++++++ site/src/main.ts | 7 +++---- site/src/style.css | 7 +++++++ 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 site/src/icons.ts diff --git a/site/e2e/text.spec.ts b/site/e2e/text.spec.ts index a0dc75c..8df5c61 100644 --- a/site/e2e/text.spec.ts +++ b/site/e2e/text.spec.ts @@ -68,6 +68,15 @@ test.describe("English locale", () => { await expect(lang).toHaveCSS("opacity", "1"); }); + test("the hero links keep their icons in either language", async ({ page }) => { + await page.goto("/"); + const icons = page.locator(".hero .links a > svg[aria-hidden=true]"); + await expect(icons).toHaveCount(2); + await page.locator(".lang").click(); + await expect(icons).toHaveCount(2); + await expect(page.locator(".hero .links a")).toHaveText(["前往下载", "源码"]); + }); + test("the language button switches every text and back", async ({ page }) => { await page.goto("/"); const lang = page.locator(".lang"); @@ -88,7 +97,7 @@ test.describe("English locale", () => { await expect(page.locator("#download [data-t=get]")).toHaveAttribute("href", RELEASES); await expect(page.locator(".hero .links a").last()).toHaveText("Source"); await expect(page.locator(".hero .links a").last()).toHaveAttribute("href", REPO); - await expect(page.locator(".hero [data-t=get]")).toHaveAttribute("href", RELEASES); + await expect(page.locator(".hero .links a").first()).toHaveAttribute("href", RELEASES); const files = await page.locator("a[href]").evaluateAll((as) => as.map((a) => (a as HTMLAnchorElement).href).filter((h) => /\.(dmg|tar\.gz|zip|exe|AppImage)$/.test(h)), ); diff --git a/site/src/icons.ts b/site/src/icons.ts new file mode 100644 index 0000000..7af811f --- /dev/null +++ b/site/src/icons.ts @@ -0,0 +1,18 @@ +// Link icons, drawn in the link's color. +import { said, type Key } from "./text.ts"; + +const ICONS = { + download: ``, + gitea: ``, +}; + +/** A link with `icon` before its keyed text. */ +export function iconLink(icon: keyof typeof ICONS, key: Key, href: string): HTMLAnchorElement { + const a = document.createElement("a"); + a.href = href; + a.className = "icon"; + a.innerHTML = ICONS[icon]; + a.firstElementChild!.setAttribute("aria-hidden", "true"); + a.append(said("span", key)); + return a; +} diff --git a/site/src/main.ts b/site/src/main.ts index ddad563..1fd28fa 100644 --- a/site/src/main.ts +++ b/site/src/main.ts @@ -9,6 +9,7 @@ import { playground } from "./play.ts"; import { film } from "./film.ts"; import { said, speak, word, type Lang } from "./text.ts"; import { RELEASES, latest } from "./release.ts"; +import { iconLink } from "./icons.ts"; const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice"; @@ -18,10 +19,8 @@ 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 = said("a", "source"); -source.href = REPO; -const download = said("a", "get"); -download.href = RELEASES; +const source = iconLink("gitea", "source", REPO); +const download = iconLink("download", "get", RELEASES); const links = document.createElement("div"); links.className = "links"; links.append(download, source); diff --git a/site/src/style.css b/site/src/style.css index 75341f3..99811d9 100644 --- a/site/src/style.css +++ b/site/src/style.css @@ -66,6 +66,13 @@ button:focus-visible { gap: 1.5rem; } +a.icon svg { + height: 1em; + width: auto; + margin-inline-end: 0.35em; + vertical-align: -0.125em; +} + .stage { display: block; max-width: 100%;