From 7969f7897a7f47df73bd0fd008ee1ea65964eb57 Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Fri, 25 Sep 2026 22:11:44 +0800 Subject: [PATCH 1/2] Make Mac App download prominent on homepage Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- .../site/scripts/analytics-client.js | 5 ++ apps/presentation/site/src/App.tsx | 45 ++++++++----- apps/presentation/site/src/styles.css | 63 ++++++++++++++++++- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/apps/presentation/site/scripts/analytics-client.js b/apps/presentation/site/scripts/analytics-client.js index 9fe63a89a7..8fed980743 100644 --- a/apps/presentation/site/scripts/analytics-client.js +++ b/apps/presentation/site/scripts/analytics-client.js @@ -125,6 +125,11 @@ const anchor = target?.closest("a[href]"); if (!anchor) return; const url = new URL(anchor.href); + if (marked === "desktop_download" && url.hostname === "github.com" && + url.pathname === "/loopx-project/loopx/releases/latest/download/LoopX.app.zip") { + event("desktop_download", { platform: "macos", artifact: "app_zip" }); + return; + } if (url.hostname === "github.com" && /^\/(?:loopx-project|huangruiteng)\/loopx(?:\/|$)/.test(url.pathname)) { event("github_click", { destination: url.pathname.includes("packages/dsh-loopx-plugin") ? "dsh_plugin" : "repository" }); } else if (url.origin === location.origin && url.pathname.startsWith("/loopx/docs/") && url.pathname !== location.pathname) { diff --git a/apps/presentation/site/src/App.tsx b/apps/presentation/site/src/App.tsx index 960df9ba75..ec8c4a17e5 100644 --- a/apps/presentation/site/src/App.tsx +++ b/apps/presentation/site/src/App.tsx @@ -5,6 +5,7 @@ import { ChevronRight, Clipboard, Code2, + Download, ExternalLink, FileCheck2, GitBranch, @@ -60,6 +61,9 @@ cd /path/to/your-project loopx connect loopx status`; +const macAppDownloadUrl = "https://github.com/loopx-project/loopx/releases/latest/download/LoopX.app.zip"; +const macAppGuideUrl = "https://github.com/loopx-project/loopx/blob/main/apps/desktop/loopx-control-plane/README.md"; + const content = { en: { nav: ["Product", "Workflow", "Learn"], @@ -71,6 +75,12 @@ const content = { }, body: "Turn complex work into durable goals, coordinated tasks, and reviewable results. LoopX keeps your agents moving across sessions. You keep the judgment.", copy: "Get started", + mac: { + download: "Download for Mac", + compact: "Mac App", + note: "Apple Silicon preview (.app.zip) · Python 3.11+ required.", + guide: "Install and first launch", + }, setup: { eyebrow: "Set up LoopX", title: "Choose how you want to start.", @@ -184,6 +194,12 @@ const content = { }, body: "把复杂工作变成持久的目标、协同的任务和可审查的成果。跨越会话,Agent 接着做;关键判断,始终由你掌握。", copy: "开始使用", + mac: { + download: "下载 Mac App", + compact: "Mac App", + note: "Apple Silicon 预览版(.app.zip)· 需要 Python 3.11+。", + guide: "安装与首次启动", + }, setup: { eyebrow: "设置 LoopX", title: "选择你的开始方式。", @@ -303,14 +319,6 @@ function ProductMark() { ); } -function GitHubIcon() { - return ( - - ); -} - function StatusPill({ tone, children, @@ -795,6 +803,7 @@ export function App() { {language === "zh" ? "探索" : "Explore"} Blog Docs + GitHub
- - - GitHub + + - + {copy.demo}
-

{language === "en" ? "Open source. Runs locally. Works with your agents." : "开源 · 本地运行 · 接入你正在使用的 Agent"}

+

+ {copy.mac.note}{" "} + {copy.mac.guide} +

diff --git a/apps/presentation/site/src/styles.css b/apps/presentation/site/src/styles.css index 0c0ed4328b..6435692214 100644 --- a/apps/presentation/site/src/styles.css +++ b/apps/presentation/site/src/styles.css @@ -160,7 +160,7 @@ button { font-size: 13px; } -.github-button { +.header-download { display: inline-flex; align-items: center; gap: 8px; @@ -174,11 +174,15 @@ button { transition: background 160ms ease, transform 160ms ease; } -.github-button:hover { +.header-download:hover { background: #333; transform: translateY(-1px); } +.header-download-compact { + display: none; +} + .menu-button { display: none; width: 40px; @@ -307,6 +311,15 @@ body[data-language="zh"] .hero h1 { line-height: 1.7; } +.hero-footnote a { + display: inline-flex; + align-items: center; + gap: 3px; + color: var(--ink); + text-decoration: underline; + text-underline-offset: 3px; +} + .hero-system { position: relative; z-index: 3; @@ -371,6 +384,32 @@ body[data-language="zh"] .hero h1 { margin-top: 32px; } +.hero-demo { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + min-height: 44px; + padding: 0 8px; + color: var(--body); + font-size: 13px; + font-weight: 500; +} + +.hero-demo:hover { + color: var(--ink); + text-decoration: underline; + text-underline-offset: 4px; +} + +.header-download:focus-visible, +.hero-actions a:focus-visible, +.hero-actions button:focus-visible, +.hero-footnote a:focus-visible { + outline: 2px solid var(--blue); + outline-offset: 3px; +} + .button { display: inline-flex; align-items: center; @@ -1768,10 +1807,18 @@ body.dialog-open { height: 64px; } - .github-button { + .header-download { + padding: 0 12px; + } + + .header-download-full { display: none; } + .header-download-compact { + display: inline; + } + .hero { min-height: 0; padding: 48px 0 56px; @@ -1794,6 +1841,10 @@ body.dialog-open { flex-direction: column; } + .hero-demo { + align-self: flex-start; + } + .button { width: 100%; } @@ -2019,6 +2070,12 @@ body.dialog-open { } } +@media (max-width: 359px) { + .header-download { + display: none; + } +} + @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; From f0d5ab3fd428e1d7ea9713131e9ea532b69a818d Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Fri, 25 Sep 2026 22:12:26 +0800 Subject: [PATCH 2/2] Document and verify Mac download entry Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- apps/presentation/site/README.md | 10 +++++++--- apps/presentation/site/scripts/analytics-smoke.mjs | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/presentation/site/README.md b/apps/presentation/site/README.md index 08462a4c63..22cb3a5c88 100644 --- a/apps/presentation/site/README.md +++ b/apps/presentation/site/README.md @@ -46,11 +46,14 @@ Keep source-document exports, private references, and unreviewed media outside the public tree. Follow `docs/development/design.md` and obtain first-screen review before changing the Blog or its homepage entry. -The first-run CTA opens one setup dialog with a recommended Agent path and a +The header and primary homepage CTA download the latest Apple Silicon Mac App +preview through the release's stable `LoopX.app.zip` asset name. The homepage +states the Python 3.11+ prerequisite and links to the desktop first-launch guide. +The adjacent first-run CTA opens one setup dialog with an Agent path and a manual Shell path. The Agent option copies the localized, public-safe setup contract; the Shell option copies the commands shown in the terminal section. -The `See in action` CTA scrolls to the public evidence showcase and restarts the -Issue Fix replay. +The `See in action` link scrolls to the public evidence showcase and restarts +the Issue Fix replay. The homepage control-plane diagrams are synthetic UI. Finite, tabbed terminal replays summarize two public README trajectories; they are curated projections, @@ -122,6 +125,7 @@ in tests; production collection still needs a real post-deployment check. | `page_view` | A canonical public page was opened; hash and locale-only changes do not add views. | | `setup_open` | Opened the homepage setup dialog. | | `setup_copy` | Successfully copied an Agent prompt or Shell setup command (`setup_method`). | +| `desktop_download` | Clicked an official Mac App download link (`platform`, `artifact`); this records intent, not a completed download. | | `showcase_open` | Followed the homepage demonstration CTA. | | `github_click` | Clicked a repository or DSH plugin link (`destination`). | | `docs_open` | Followed a link into documentation. | diff --git a/apps/presentation/site/scripts/analytics-smoke.mjs b/apps/presentation/site/scripts/analytics-smoke.mjs index 60c021758d..be66748f7c 100644 --- a/apps/presentation/site/scripts/analytics-smoke.mjs +++ b/apps/presentation/site/scripts/analytics-smoke.mjs @@ -94,11 +94,15 @@ try { window.dispatchEvent(new CustomEvent("loopx:setup-copy", { detail: "never-send-this" })); }); await page.getByRole("button", { name: "Close setup", exact: true }).click(); + await page.evaluate(() => document.querySelector(".hero-download")?.addEventListener("click", (event) => event.preventDefault())); + await page.locator(".hero-download").click(); await page.locator(".language-toggle").click(); const rows = await page.evaluate(() => window.dataLayer.map((args) => [...args])); assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "page_view").length, 1); assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "setup_open").length, 1); assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "setup_copy").length, 1); + assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "desktop_download").length, 1); + assert.equal(rows.filter((r) => r[0] === "event" && r[1] === "github_click").length, 0, "Mac download is not a repository visit"); assert(!JSON.stringify(rows).includes("never-send-this") && !JSON.stringify(rows).includes("private-task")); assert.equal(rows.find((r) => r[0] === "config")[2].allow_google_signals, false); await page.evaluate(() => {