feat(gaze): add Gaze subdomain landing page with direct download

Move the Gaze marketing home from the legacy /marketing/gaze route to
a dedicated gaze subdomain landing page (src/routes/gaze). The new page
adds a richer hero, feature highlights, and a direct .dmg download flow
that resolves a signed S3 URL via the tRPC downloads.getDownloadUrl
endpoint.

Extract the download-resolution logic into a shared, testable
downloadAsset helper (src/lib/download-asset) so current and future
subdomain landing pages (InputHalo, Lineage, …) share one code path.
The helper is pure over an injected DownloadApi + redirect sink, keeping
it unit-testable without importing solid-js / CSRF cookie code.

Replace the old marketing/gaze route with a permanent 308 redirect to
https://gaze.freno.me so existing inbound links keep resolving to the
canonical home.

Add unit tests covering the tRPC call shape, redirect sink, and error
handling.
This commit is contained in:
2026-07-23 12:15:04 -04:00
parent 6fdbbbbe2b
commit f2ff75e6df
4 changed files with 359 additions and 56 deletions

View File

@@ -1,57 +1,21 @@
import { PageHead } from "~/components/PageHead";
import DownloadOnAppStoreDark from "~/components/icons/DownloadOnAppStoreDark";
import { useDarkMode } from "~/context/darkMode";
export default function GazeMarketing() {
const { isDark } = useDarkMode();
return (
<>
<PageHead
title="Gaze - Eye Health Reminder"
description="A macOS menu bar app that helps you remember to take breaks and rest your eyes. Download Gaze today."
/>
<div class="relative h-full">
<div class="fixed inset-0 z-0 overflow-hidden brightness-75">
<img
src="/look-away.png"
alt="background"
class="h-full w-full object-cover select-none"
style={{
"pointer-events": "none"
}}
/>
</div>
<div class="relative z-10 flex h-full flex-col items-center justify-center text-white backdrop-blur">
<div>
<img
src={
isDark()
? "/Gaze Exports/Gaze-iOS-Dark-1024x1024@1x.png"
: "/Gaze Exports/Gaze-iOS-Default-1024x1024@1x.png"
}
alt="Gaze App Icon"
height={128}
width={128}
class="object-cover object-center"
/>
</div>
<h1 class="py-4 text-center text-5xl font-bold">Gaze</h1>
<p class="text-text mb-8 text-xl">
Eye and posture health reminder for macOS
</p>
<div class="flex space-x-4">
<a
class="my-auto transition-all duration-200 ease-out active:scale-95"
href="https://apps.apple.com"
target="_blank"
rel="noopener noreferrer"
>
<DownloadOnAppStoreDark size={50} />
</a>
</div>
</div>
</div>
</>
);
/**
* Legacy `/marketing/gaze` route — redirected (task 05) to the new Gaze
* subdomain landing page at `gaze.freno.me`.
*
* Kept as a permanent 308 redirect so existing inbound links keep resolving
* to the canonical Gaze marketing home.
*
* Implemented as a thrown `Response` (rather than `@solidjs/router`'s
* `redirect()`) because the target is a *cross-origin* absolute URL; throwing
* a `Response` from a SolidStart page component propagates as the actual HTTP
* response, with no router base-path rewriting.
*/
export default function GazeMarketingRedirect(): never {
throw new Response(null, {
status: 308,
headers: {
Location: "https://gaze.freno.me",
"Cache-Control": "public, max-age=86400"
}
});
}