commit d7fb767d7f16f9df8c78e31343b64ca4c47d4a3b
parent 52d80906421fb0134a39cf252b4e37b88b4b214a
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 11:16:28 -0400
homepage: the hero links to the hub when homepage.json names it
"Search all archives" beside Download the source / Read the setup guide,
pointing at homepage.json's siteUrl (the hub's URL, the field the hub build
reads); absent on a build with no hub. marketing.spec checks that a present
link is absolute.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/homepage/app/page.tsx b/homepage/app/page.tsx
@@ -3,6 +3,7 @@ import { RecentAdditions } from "./components/RecentAdditions";
import { KpiHeader } from "./components/KpiHeader";
import { ArchiveCards } from "./components/ArchiveCards";
import { loadSummary } from "./lib/summary";
+import { currentHomepage } from "./lib/homepage";
// The project's front page. Its ONE job: make a visitor understand what
// Archilyzer is and download it.
@@ -38,6 +39,11 @@ export default function Home() {
const hours = summary?.totals.hoursArchived ?? null;
const gone = summary?.availability?.byState.deleted ?? 0;
const counted = summary?.availability?.counted ?? 0;
+ // The operator's hub — one search over every published archive — is a
+ // separate app on its own Pages project; homepage.json's siteUrl is its
+ // address (the same field the hub's own build reads). No URL, no link: a
+ // source-only build has no hub to point at.
+ const hubUrl = currentHomepage().siteUrl ?? null;
return (
<>
@@ -87,6 +93,14 @@ export default function Home() {
>
Read the setup guide →
</Link>
+ {hubUrl && (
+ <a
+ href={hubUrl}
+ className="inline-flex items-center gap-2 border border-[var(--border-strong)] px-6 py-3 font-mono text-xs uppercase tracking-[0.16em] text-[var(--foreground)] rounded-[var(--radius)] hover:border-[var(--brand)] hover:text-[var(--brand)] transition-colors"
+ >
+ Search all archives
+ </a>
+ )}
</div>
{/* The rail: real acquisitions, real states. The signature object. */}
diff --git a/homepage/e2e/marketing.spec.ts b/homepage/e2e/marketing.spec.ts
@@ -22,6 +22,18 @@ test("says what it is and offers the source", async ({ page }) => {
).toHaveAttribute("href", "/docs/install/");
});
+// The hub is a separate app on its own Pages project, linked from the hero
+// when homepage.json names its URL. Data-dependent like the rail below, so the
+// assertion is conditional the same way: absent is a legal state (a
+// source-only build has no hub), but PRESENT means an absolute link off-site —
+// never a relative path into this site, which has no search.
+test("the hub link, when there is one, leaves for the hub", async ({ page }) => {
+ const hub = page.getByRole("link", { name: /search all archives/i });
+ if ((await hub.count()) === 0) return;
+ await expect(hub).toHaveCount(1);
+ await expect(hub).toHaveAttribute("href", /^https?:\/\/[^/]/);
+});
+
test("the trust block states what it isn't", async ({ page }) => {
// The cheapest, highest-value block on the page — every claim in it is
// simply true, and each one pre-empts a wrong assumption.