Files
hanzo.ai/components/zap/ZapCTA.tsx
zeekay 398528b569 Every call to action reads in sentence case: Get API key, Explore GitHub examples, Read the docs
/zen, /dev, /gen, /kata and /enso opened on "Get API Key", "Explore
GitHub Examples →" and "Read the Docs →", while the closing call under
them, the header and every other button on the site say "Read the docs"
and "Try Hanzo". Fifteen files' labels now match; enso.spec.ts finds the
key link by its new name.
2026-10-18 16:49:48 -07:00

102 lines
3.8 KiB
TypeScript

'use client'
/**
* NO TAILWIND. The two washes are siblings of the measure rather than children
* of it — each is sized against the SECTION, so a `Band` (which centres its
* children on a measure) is the wrong frame here and the section is stated
* outright, the same way `components/operator/OperativeHero` states its own.
*
* Type is the roles in `app/globals.css`: `pill`, `title`, `lede`, `action`.
*/
import React from "react";
import { motion } from "@/components/motion";
import { ArrowRight, Zap, BookOpen } from "lucide-react"
import { Github } from "@/components/brand"
import { Box, XStack, YStack } from '@hanzo/ui'
import { Words } from '@/components/marketing/band'
import { Action, Chip, Lede, Title } from '@hanzo/ui/marketing'
const WASH = {
position: 'absolute',
width: 384,
height: 384,
rounded: 'var(--radius-full)',
background: 'color-mix(in oklab, var(--pure-white) 5%, transparent)',
filter: 'blur(64px)',
} as const
/** The ink the badge and the second line share: the foreground at 70%. */
const SOFT = 'color-mix(in oklab, var(--foreground) 70%, transparent)'
/** `Chip` leaves the padding and the fill to its caller. */
const BADGE = { self: "center", mb: 32, px: 16, py: 8, borderColor: "var(--border)", bg: "color-mix(in oklab, var(--pure-white) 5%, transparent)" } as const
const FILLED = { px: 32, py: 16, bg: "color-mix(in oklab, var(--pure-white) 10%, transparent)", color: "var(--primary-foreground)" } as const
const OUTLINED = { px: 32, py: 16, borderColor: "var(--border)" } as const
const ZapCTA = () => {
return (
<YStack
render="section"
position="relative"
overflow="hidden"
py={80}
px={16}
$sm={{ px: 24 }}
$lg={{ px: 32 }}
>
{/* Background decorations */}
<Box {...WASH} t={0} l="25%" />
<Box {...WASH} b={0} r="25%" />
<Box position="relative" z="var(--z-raised)" width="100%" maxW={896} mx="auto" $platform-web={{ textAlign: 'center' }}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
>
<Chip {...BADGE}>
<Zap width={16} height={16} color={SOFT} />
<Words fontSize="$2" lineHeight="1.4286" weight="500" color={SOFT}>Go · Rust · TypeScript</Words>
</Chip>
<Title quiet mb={24} color="var(--foreground)">
Point one agent at it
</Title>
<Lede mb={32} maxW={672} mx="auto" mt="$3.5">
Start the daemon, add the MCP servers you already run, change one address in your agent.
<br />
<Words color={SOFT}>Nothing else about your setup has to move.</Words>
</Lede>
<XStack flexWrap="wrap" justify="center" gap={16}>
<Action href="https://zap-proto.dev/docs" {...FILLED}>
<BookOpen width={20} height={20} />
Read the docs
<ArrowRight width={16} height={16} />
</Action>
<Action href="https://github.com/zap-proto/spec" {...OUTLINED}>
<Github width={20} height={20} />
View on GitHub
</Action>
</XStack>
<Words render="p" mt={48} mx="auto" maxW={576} fontSize="$1" lineHeight="1.3333" color="var(--muted-foreground)">
What ZAP saves depends on your workload, your payload size and your topology. The claim here is
about mechanism, not about a number: a reader that walks the buffer in place does no parsing and no
allocation, and shared backends run one process where per-agent sidecars run many. Measure it on
your own traffic — we have not published a benchmark and will not quote one we cannot show you.
</Words>
</motion.div>
</Box>
</YStack>
);
};
export default ZapCTA;