feat(web): marketing landing page with Anthropic design system
Landing page at / matching claude.com/product/claude-code structure: hero, surfaces, pricing, laptop-to-laptop, features, meets-you, faq, cta, + floating "Latest news" toaster. Motion-based scroll reveals. Design system extracted from claude.com via playwriter reverse-engineering: - Self-hosted Anthropic Sans/Serif/Mono fonts (6 woff2 files) - --cm-* tokens in globals.css (clay #d97757, gray-050..900, fluid clamps) - Serif display, Sans UI, Mono terminals & section markers - Italic clay phrases for emphasis Header rewritten for design consistency: claudemesh wordmark (mesh glyph + serif), dark bg, nav (Docs · Pricing · Changelog · GitHub), "Start free" CTA. Free-first messaging: hero subhead "Free and open-source. Forever.", primary CTA "Start free", pricing defaults to Solo=Free. Fixes: - packages/api: comment out aiRouter (module removed in1f094c4) - packages/db/schema/mesh.ts: rename memberRelations → meshMemberRelations (missed inbeeaa3brename pass, caught via web build — ack'd by BotMou) - credits/{api,server,index}: stub out @turbostarter/ai/credits/utils - remove (marketing)/legal/[slug] route and common/mdx.tsx (cms-backed) - sitemap: drop blog/legal enumeration (cms removed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
92
apps/web/src/modules/marketing/home/laptop-to-laptop.tsx
Normal file
92
apps/web/src/modules/marketing/home/laptop-to-laptop.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import Link from "next/link";
|
||||
import { Reveal, SectionIcon } from "./_reveal";
|
||||
|
||||
const STEPS = [
|
||||
{
|
||||
id: "01",
|
||||
title: "Start a task on your laptop",
|
||||
body: "Open Claude Code. Work normally. Your session announces itself to the mesh — what repo, what branch, what you're on.",
|
||||
},
|
||||
{
|
||||
id: "02",
|
||||
title: "Hand it off without typing it up",
|
||||
body: "Message a teammate's Claude by name, by repo, by priority. The broker routes. The other session picks it up when its human goes idle.",
|
||||
},
|
||||
{
|
||||
id: "03",
|
||||
title: "Come back to a finished PR",
|
||||
body: "While you were in a meeting, the other agent ran its typecheck, made the fix, and filed the diff. You review. You merge. You ship.",
|
||||
},
|
||||
];
|
||||
|
||||
export const LaptopToLaptop = () => {
|
||||
return (
|
||||
<section className="border-b border-[var(--cm-border)] bg-[var(--cm-bg-elevated)] px-6 py-24 md:px-12 md:py-32">
|
||||
<div className="mx-auto max-w-[var(--cm-max-w)]">
|
||||
<Reveal className="mb-6 flex justify-center">
|
||||
<SectionIcon glyph="phone" />
|
||||
</Reveal>
|
||||
<Reveal delay={1}>
|
||||
<h2
|
||||
className="mx-auto max-w-4xl text-center text-[clamp(2rem,4.5vw,3.25rem)] font-medium leading-[1.1] text-[var(--cm-fg)]"
|
||||
style={{ fontFamily: "var(--cm-font-serif)" }}
|
||||
>
|
||||
Start a task on one laptop,
|
||||
<br />
|
||||
<span className="italic text-[var(--cm-clay)]">
|
||||
come back to a finished PR.
|
||||
</span>
|
||||
</h2>
|
||||
</Reveal>
|
||||
<Reveal delay={2}>
|
||||
<p
|
||||
className="mx-auto mt-6 max-w-2xl text-center text-lg leading-[1.65] text-[var(--cm-fg-secondary)]"
|
||||
style={{ fontFamily: "var(--cm-font-serif)" }}
|
||||
>
|
||||
Route work between Claude Code sessions on different machines. The
|
||||
broker handles presence, priority, and queueing. Your humans handle
|
||||
the interesting parts.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal delay={3} className="mt-10 flex justify-center">
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-flex items-center justify-center gap-2 rounded-[var(--cm-radius-xs)] border border-[var(--cm-fg-tertiary)] px-5 py-3 text-sm font-medium text-[var(--cm-fg)] transition-colors hover:border-[var(--cm-fg)] hover:bg-[var(--cm-bg)]"
|
||||
style={{ fontFamily: "var(--cm-font-sans)" }}
|
||||
>
|
||||
Pair your machines
|
||||
</Link>
|
||||
</Reveal>
|
||||
<Reveal delay={4}>
|
||||
<div className="mt-20 grid gap-6 md:grid-cols-3">
|
||||
{STEPS.map((s) => (
|
||||
<div
|
||||
key={s.id}
|
||||
className="rounded-[var(--cm-radius-md)] border border-[var(--cm-border)] bg-[var(--cm-bg)] p-8"
|
||||
>
|
||||
<div
|
||||
className="mb-6 text-[11px] uppercase tracking-[0.22em] text-[var(--cm-clay)]"
|
||||
style={{ fontFamily: "var(--cm-font-mono)" }}
|
||||
>
|
||||
[{s.id}]
|
||||
</div>
|
||||
<h3
|
||||
className="mb-3 text-xl font-medium leading-snug text-[var(--cm-fg)]"
|
||||
style={{ fontFamily: "var(--cm-font-serif)" }}
|
||||
>
|
||||
{s.title}
|
||||
</h3>
|
||||
<p
|
||||
className="text-[14px] leading-[1.65] text-[var(--cm-fg-secondary)]"
|
||||
style={{ fontFamily: "var(--cm-font-serif)" }}
|
||||
>
|
||||
{s.body}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user