ReviewOS

also looking at this

stacks/uplink

feat(homepage): say what it takes to run Uplink, before the download button

#62
Merged glennmichael123 wants to merge feat/what-you-need into main
2 files +51 -3
resources/partials/site-nav.stxmodified+4-0
Changes to resources/partials/site-nav.stx
@@ -20,6 +20,10 @@ const navDownloadUrl = release.url
2020 <a href="/pricing" class="hover:opacity-80 u-muted">Pricing</a>
2121 @endif
2222 <a href="/#questions" class="hidden md:inline hover:opacity-80 u-muted">Questions</a>
23 <a href="https://github.com/stacksjs/uplink" class="hidden sm:inline-flex gap-1.5 items-center hover:opacity-80 u-muted" rel="noopener">
24 <span class="size-4 i-hugeicons-github" aria-hidden="true"></span>
25 <span class="sr-only md:not-sr-only">GitHub</span>
26 </a>
2327 <a href="" class="u-btn u-btn-primary" style="padding: .5rem 1rem"><span>Download<span class="hidden sm:inline"> for Mac</span></span></a>
2428 </div>
2529 </nav>
resources/views/index.stxmodified+47-3
Changes to resources/views/index.stx
@@ -49,7 +49,23 @@ import release from '../data/release.json'
4949import { formatCents, PLANS, yearlySavingPercent } from '../../app/Billing/plans'
5050
5151const downloadUrl = release.url
52const downloadMeta = `Version ${release.version}, macOS ${release.minimumMacOS} or later, ${Math.round(release.bytes / 1_000_000)} MB`
52const downloadMeta = `Version ${release.version}, ${Math.round(release.bytes / 1_000_000)} MB`
53
54// Everything it takes to run Uplink, in the order someone would hit it. These
55// were spread over a caption, a hero line, two collapsed FAQ answers and an
56// install step below the button, so the one thing a visitor needs before
57// paying took five places to assemble.
58//
59// Apple Silicon is not a preference: `lipo -archs` on the shipped 0.1.4 DMG
60// reports `arm64` alone, so an Intel Mac cannot open it at all.
61const requirements = [
62 { need: 'An Apple Silicon Mac', detail: 'M1 or later. The app is arm64 only.' },
63 { need: `macOS ${release.minimumMacOS} or later`, detail: 'Signed and notarized, so it opens like any other app.' },
64 { need: 'Claude Code or Codex', detail: 'On the plan you already have, Claude or ChatGPT. No API key.' },
65 { need: 'Full Disk Access', detail: 'Only for Uplink, so it can read Messages. Not for your terminal.' },
66 { need: 'Permission to control Messages', detail: 'Asked once, so it can text the answer back.' },
67 { need: 'A Mac that stays awake', detail: 'A laptop with its lid closed sleeps unless it is on power with a display attached.' },
68]
5369
5470const install = [
5571 { verb: 'Install', body: 'Open the download and drag Uplink to Applications. It is signed and notarized by Apple, so it opens like any other app.' },
@@ -63,30 +79,39 @@ const yearlySaving = yearlySavingPercent()
6379
6480const faqs = [
6581 {
82 // Linked from the download section, which states the qualification in one
83 // sentence and sends anyone who wants the rest here.
84 id: 'satellite',
6685 q: 'Does texting yourself work over satellite?',
6786 a: 'It depends on how your iPhone routes a message to your own number, so try it once before you rely on it. If it does not arrive, sign the Mac into a second Apple ID and text that instead.',
6887 },
6988 {
89 id: 'full-disk-access',
7090 q: 'Why does it need Full Disk Access?',
7191 a: 'Messages keeps your texts in a database macOS protects. Uplink reads it to notice texts from the handles you allow, and ignores every other conversation.',
7292 },
7393 {
94 id: 'api-key',
7495 q: 'Do I need an API key?',
7596 a: 'No. Uplink runs the CLI you already pay for: Claude Code on a Claude plan, which signs in through your browser and keeps its token in your Keychain, or Codex on a ChatGPT plan, which keeps its own credentials and leaves Uplink holding nothing.',
7697 },
7798 {
99 id: 'what-it-can-do',
78100 q: 'What can it do on my Mac?',
79101 a: 'Anything the agent can: search the web, read and edit files, run your tests. That is why only one-to-one chats with handles you allow can reach it.',
80102 },
81103 {
104 id: 'cost',
82105 q: 'What does it cost?',
83106 a: '$1.99 a month, $19.99 a year, or $29.99 once. That is for Uplink itself; the answers run on the plan you already have, Claude or ChatGPT, and nothing is charged per text.',
84107 },
85108 {
109 id: 'chatgpt',
86110 q: 'Can it answer with ChatGPT instead?',
87111 a: 'Yes. Choose Codex in the menubar and Uplink answers with your ChatGPT plan instead of Claude. Everything else works the same way.',
88112 },
89113 {
114 id: 'sleep',
90115 q: 'What happens while my Mac sleeps?',
91116 a: 'Nothing, so Uplink keeps it from idle-sleeping while it runs. A laptop with its lid closed still sleeps unless it is on power with a display attached.',
92117 },
@@ -236,7 +261,22 @@ const faqs = [
236261 <div class="grid gap-12 items-center lg:gap-16 lg:grid-cols-[1.1fr_0.9fr] mx-auto px-4 py-20 sm:px-6 lg:py-28 max-w-6xl">
237262 <div>
238263 <h2 id="download-title" class="font-semibold text-3xl tracking-tight md:text-4xl">Download Uplink for Mac.</h2>
239 <p class="mt-4 max-w-[52ch] u-muted">A menubar app. You need Claude Code on a Claude plan, or Codex on a ChatGPT plan; Uplink takes care of the rest.</p>
264 <p class="mt-4 max-w-[52ch] u-muted">A menubar app. Uplink takes care of the rest.</p>
265
266 <ul class="grid gap-3 mt-8">
267 @foreach(requirements as requirement)
268 <li class="flex gap-3 items-baseline">
269 <span class="shrink-0 size-4 translate-y-0.5 i-hugeicons-checkmark-circle-02 u-accent" aria-hidden="true"></span>
270 <span class="max-w-[52ch]"><span class="font-medium">{{ requirement.need }}</span> <span class="u-muted">{{ requirement.detail }}</span></span>
271 </li>
272 @endforeach
273 </ul>
274
275 <p class="mt-4 max-w-[52ch] text-sm u-muted">
276 Texting yourself over satellite depends on how your iPhone routes a message to your own number, so
277 <a href="#satellite" class="underline underline-offset-4 hover:opacity-80">try it once before you rely on it</a>.
278 </p>
279
240280 <div class="flex flex-wrap gap-x-5 gap-y-3 items-center mt-8">
241281 <a href="" class="u-btn u-btn-primary">
242282 <span class="size-4 i-hugeicons-apple" aria-hidden="true"></span>
@@ -244,6 +284,10 @@ const faqs = [
244284 </a>
245285 <p class="text-sm u-mono u-muted">{{ downloadMeta }}</p>
246286 </div>
287 <p class="mt-3 text-sm u-muted">
288 Open source, <a href="https://github.com/stacksjs/uplink/blob/main/LICENSE.md" class="underline underline-offset-4 hover:opacity-80">MIT licensed</a>.
289 <a href="https://github.com/stacksjs/uplink/releases" class="underline underline-offset-4 hover:opacity-80">Every release</a> is listed on GitHub.
290 </p>
247291
248292 <ol class="grid gap-7 mt-12">
249293 @foreach(install as step)
@@ -305,7 +349,7 @@ const faqs = [
305349 <h2 id="questions-title" class="font-semibold text-3xl tracking-tight md:text-4xl">Questions</h2>
306350 <div class="mt-10 border-t u-line">
307351 @foreach(faqs as faq)
308 <details class="border-b u-line">
352 <details id="" class="border-b scroll-mt-16 u-line">
309353 <summary class="flex gap-6 items-center justify-between py-5 font-medium text-lg">
310354 {{ faq.q }}
311355 <span class="shrink-0 size-5 i-hugeicons-plus-sign u-chevron u-muted" aria-hidden="true"></span>