also looking at this
feat(homepage): say what it takes to run Uplink, before the download button
#62
2 files
+51
-3
| @@ -49,7 +49,23 @@ import release from '../data/release.json' | ||
| 49 | 49 | import { formatCents, PLANS, yearlySavingPercent } from '../../app/Billing/plans' |
| 50 | 50 | |
| 51 | 51 | const downloadUrl = release.url |
| 52 | const downloadMeta = `Version ${release.version}, macOS ${release.minimumMacOS} or later, ${Math.round(release.bytes / 1_000_000)} MB` | |
| 52 | const 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. | |
| 61 | const 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 | ] | |
| 53 | 69 | |
| 54 | 70 | const install = [ |
| 55 | 71 | { 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() | ||
| 63 | 79 | |
| 64 | 80 | const faqs = [ |
| 65 | 81 | { |
| 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', | |
| 66 | 85 | q: 'Does texting yourself work over satellite?', |
| 67 | 86 | 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.', |
| 68 | 87 | }, |
| 69 | 88 | { |
| 89 | id: 'full-disk-access', | |
| 70 | 90 | q: 'Why does it need Full Disk Access?', |
| 71 | 91 | 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.', |
| 72 | 92 | }, |
| 73 | 93 | { |
| 94 | id: 'api-key', | |
| 74 | 95 | q: 'Do I need an API key?', |
| 75 | 96 | 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.', |
| 76 | 97 | }, |
| 77 | 98 | { |
| 99 | id: 'what-it-can-do', | |
| 78 | 100 | q: 'What can it do on my Mac?', |
| 79 | 101 | 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.', |
| 80 | 102 | }, |
| 81 | 103 | { |
| 104 | id: 'cost', | |
| 82 | 105 | q: 'What does it cost?', |
| 83 | 106 | 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.', |
| 84 | 107 | }, |
| 85 | 108 | { |
| 109 | id: 'chatgpt', | |
| 86 | 110 | q: 'Can it answer with ChatGPT instead?', |
| 87 | 111 | a: 'Yes. Choose Codex in the menubar and Uplink answers with your ChatGPT plan instead of Claude. Everything else works the same way.', |
| 88 | 112 | }, |
| 89 | 113 | { |
| 114 | id: 'sleep', | |
| 90 | 115 | q: 'What happens while my Mac sleeps?', |
| 91 | 116 | 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.', |
| 92 | 117 | }, |
| @@ -236,7 +261,22 @@ const faqs = [ | ||
| 236 | 261 | <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"> |
| 237 | 262 | <div> |
| 238 | 263 | <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 | ||
| 240 | 280 | <div class="flex flex-wrap gap-x-5 gap-y-3 items-center mt-8"> |
| 241 | 281 | <a href="" class="u-btn u-btn-primary"> |
| 242 | 282 | <span class="size-4 i-hugeicons-apple" aria-hidden="true"></span> |
| @@ -244,6 +284,10 @@ const faqs = [ | ||
| 244 | 284 | </a> |
| 245 | 285 | <p class="text-sm u-mono u-muted">{{ downloadMeta }}</p> |
| 246 | 286 | </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> | |
| 247 | 291 | |
| 248 | 292 | <ol class="grid gap-7 mt-12"> |
| 249 | 293 | @foreach(install as step) |
| @@ -305,7 +349,7 @@ const faqs = [ | ||
| 305 | 349 | <h2 id="questions-title" class="font-semibold text-3xl tracking-tight md:text-4xl">Questions</h2> |
| 306 | 350 | <div class="mt-10 border-t u-line"> |
| 307 | 351 | @foreach(faqs as faq) |
| 308 | <details class="border-b u-line"> | |
| 352 | <details id="" class="border-b scroll-mt-16 u-line"> | |
| 309 | 353 | <summary class="flex gap-6 items-center justify-between py-5 font-medium text-lg"> |
| 310 | 354 | {{ faq.q }} |
| 311 | 355 | <span class="shrink-0 size-5 i-hugeicons-plus-sign u-chevron u-muted" aria-hidden="true"></span> |