Files
hanzo.ai/components/realtime/Integration.tsx
zeekay 11265a21fd Highlight every code sample with shiki in the code theme
Code on hanzo.ai was plain monospace: 285 blocks across 200 pages, one of
them hand-inked in four greys. components/code now renders each sample
at build with shiki and @hanzo/ui's codeTheme (Dracula dark, GitHub
Light light), every colour written as light-dark() so the page's
color-scheme picks it, on the theme's own ground. The page ships the
coloured spans and no highlighter; e2e/gates/code.spec.ts holds both.

A client page that shows code is split into a server page.tsx that owns
the sample and a client view.tsx that takes the highlighted node:
ProductLanding's code.source, the blockchain pages' codeExamples, the
models kit Sample, the guest-key card, realtime, analytics, payments,
sdks and the rest. Transcripts, agent prompts and ASCII diagrams are not
code and keep their markup.

Takes @hanzo/ui 8.27.83 for codeTheme and @hanzo/design 0.5.35 with it,
regenerates app/gui.css for the new theme keys, and lowers the raw-colour
allowance to 58: the samples' literal inks are gone.
2026-10-05 01:31:58 -07:00

133 lines
5.1 KiB
TypeScript

'use client'
import React, { type ReactNode } from "react";
import { motion } from "@/components/motion";
import { Code as Glyph, ArrowRight } from "lucide-react";
import { View, YStack, XStack } from '@hanzo/ui'
import { Grid } from '@hanzo/ui/grid'
import { Line } from '@/components/type'
import { DOCS } from '@/components/home/nav-data'
import { Action, Lede, Title } from '@hanzo/ui/marketing'
// Define a proper type for the presence event
interface PresenceEvent {
action: 'join' | 'leave';
userData: {
name: string;
[key: string]: string | number | boolean;
};
}
/** A step's number, on its disc. */
const STEP = {
width: 24,
height: 24,
marginTop: 2,
borderRadius: 'var(--radius-full)',
backgroundColor: 'color-mix(in oklab, var(--primary) 10%, transparent)',
} as const
/** `wire` is the protocol sample, highlighted by the server page. */
const Integration = ({ wire }: { wire: ReactNode }) => {
return (
<YStack
render="section"
py={80}
px={16}
$sm={{ px: 24 }}
$lg={{ px: 32 }}
>
<YStack width="100%" maxW={1280} mx="auto">
<View
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5 }} />}
display="block"
mb={48}
$platform-web={{ textAlign: 'center' }}
>
<Title quiet mb={16}>
Three calls, then it is live
</Title>
<Lede maxW={768} mx="auto" mt="$3.5">
Mint a grant, spend it to open the stream, say what you want to hear about
</Lede>
</View>
<Grid columns={{ min: 420, max: 2 }} gap={40} items="center">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<Line render="h3" size="x2" weight="600" display="block" marginBottom={16}>The handshake, in full</Line>
<Line render="p" tone="soft" display="block" marginBottom={24}>
There is no hidden protocol here. A grant is minted on a normal
authenticated request, the stream spends it once, and the client
id that comes back is how you tell the server which collections
and records you want. The SDK does all three for you; the raw
calls are there if you would rather do it yourself.
</Line>
<YStack gap={16} mb={32}>
<XStack items="flex-start" gap={12}>
<XStack {...STEP} items="center" justify="center">
<Line size="sm" weight="700">1</Line>
</XStack>
<YStack flex={1} minW={0}>
<Line render="h4" weight="500" marginBottom={4}>Mint a grant</Line>
<Line render="p" size="sm" tone="muted">One authenticated request returns a string good for thirty seconds and exactly one stream</Line>
</YStack>
</XStack>
<XStack items="flex-start" gap={12}>
<XStack {...STEP} items="center" justify="center">
<Line size="sm" weight="700">2</Line>
</XStack>
<YStack flex={1} minW={0}>
<Line render="h4" weight="500" marginBottom={4}>Open the stream, name your topics</Line>
<Line render="p" size="sm" tone="muted">Spend the grant, take the client id it hands back, then post the collections and records you care about</Line>
</YStack>
</XStack>
<XStack items="flex-start" gap={12}>
<XStack {...STEP} items="center" justify="center">
<Line size="sm" weight="700">3</Line>
</XStack>
<YStack flex={1} minW={0}>
<Line render="h4" weight="500" marginBottom={4}>Write a record</Line>
<Line render="p" size="sm" tone="muted">Any create, update or delete reaches everyone watching whose rule lets them see it</Line>
</YStack>
</XStack>
</YStack>
<Action href={DOCS} fill>
View Documentation <ArrowRight width={16} height={16} />
</Action>
</motion.div>
<View
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5, delay: 0.3 }} />}
display="block"
p={24}
rounded="var(--radius-xl)"
borderWidth={1}
borderColor="var(--neutral-800)"
bg="var(--surface-card-quiet)"
>
<XStack items="center" gap={8} mb={16}>
<Glyph width={20} height={20} color="var(--foreground)" />
<Line tone="soft">The wire, without the SDK</Line>
</XStack>
<View maxH={400} overflowX="auto" overflowY="auto" rounded="var(--radius-lg)">
{wire}
</View>
</View>
</Grid>
</YStack>
</YStack>
);
};
export default Integration;