mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
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.
135 lines
4.3 KiB
TypeScript
135 lines
4.3 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* A quick-start, told as one sample per language.
|
|
*
|
|
* Everything here already existed somewhere else on this site and was written
|
|
* out again by hand:
|
|
*
|
|
* the strip @hanzo/ui's `Tabs`, as the package draws it.
|
|
* the frame a labelled bar with @hanzo/ui's `CopyButton`, over the sample
|
|
* the server page highlighted (components/code).
|
|
* the head the eyebrow/heading/lede ladder `SDKSection` beside it sets.
|
|
*
|
|
* WHY THE COPY BUTTON MOVED. It floated over the code at `top-3 right-3`, which
|
|
* covers the first line — the import or the prompt, the part most read. The
|
|
* bar above the sample holds it instead. It also ends a duplicate
|
|
* `id="code-example"` that this file was stamping on one element per tab.
|
|
*
|
|
* `Eyebrow` is deliberately NOT used for the label. That role is 0.2em of
|
|
* tracking in `--neutral-400`; this label is 0.05em in the foreground, which is
|
|
* what `SDKSection` sets, and these two sections read as a pair.
|
|
*/
|
|
|
|
import { motion } from '@/components/motion'
|
|
import { Terminal } from 'lucide-react'
|
|
import type { ReactNode } from 'react'
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger, XStack, YStack } from '@hanzo/ui'
|
|
import { CopyButton } from '@hanzo/ui/product'
|
|
import { Line } from '@/components/type'
|
|
|
|
/** One language's sample: its text for the clipboard, and that text highlighted
|
|
* by the server page (components/code). */
|
|
export interface Example {
|
|
language: string;
|
|
label: string;
|
|
code: string;
|
|
sample: ReactNode;
|
|
description?: string;
|
|
}
|
|
|
|
interface CodeExamplesSectionProps {
|
|
title?: string;
|
|
subtitle?: string;
|
|
examples: Example[];
|
|
}
|
|
|
|
export function CodeExamplesSection({
|
|
title = "Quick Start",
|
|
subtitle = "Pick a language.",
|
|
examples
|
|
}: CodeExamplesSectionProps) {
|
|
const languageIcons: Record<string, string> = {
|
|
python: "🐍",
|
|
javascript: "📜",
|
|
typescript: "📘",
|
|
go: "🐹",
|
|
rust: "🦀",
|
|
curl: "🔗",
|
|
cli: "💻",
|
|
bash: "💻",
|
|
docker: "🐳",
|
|
};
|
|
|
|
return (
|
|
<motion.section
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
>
|
|
<YStack py={64} px={16} $md={{ px: 32 }}>
|
|
<YStack width="100%" maxW={896} mx="auto">
|
|
<XStack items="center" gap={8} mb={8}>
|
|
<Terminal width={20} height={20} color="var(--foreground)" />
|
|
<Line
|
|
size="sm"
|
|
weight="500"
|
|
caps
|
|
>
|
|
Code Examples
|
|
</Line>
|
|
</XStack>
|
|
|
|
<Line
|
|
render="h2"
|
|
size="x2"
|
|
weight="700"
|
|
marginBottom={8}
|
|
$md={{ fontSize: 'var(--text-3xl)', lineHeight: '1.2' }}
|
|
>
|
|
{title}
|
|
</Line>
|
|
<Line render="p" tone="muted" marginBottom={32}>
|
|
{subtitle}
|
|
</Line>
|
|
|
|
<Tabs defaultValue={examples[0]?.language}>
|
|
<TabsList mb="$6">
|
|
{examples.map((example) => (
|
|
<TabsTrigger key={example.language} value={example.language}>
|
|
<span>{languageIcons[example.language.toLowerCase()] || "📄"}</span>
|
|
{example.label}
|
|
</TabsTrigger>
|
|
))}
|
|
</TabsList>
|
|
|
|
{examples.map((example) => (
|
|
<TabsContent key={example.language} value={example.language}>
|
|
{example.description && (
|
|
<Line render="p" size="sm" tone="muted" marginBottom={16}>
|
|
{example.description}
|
|
</Line>
|
|
)}
|
|
|
|
<YStack rounded="$4" borderWidth={1} borderColor="$borderColor" overflow="hidden">
|
|
<XStack items="center" gap="$1" px="$3" py="$1.5" borderBottomWidth={1} borderColor="$borderColor">
|
|
<Line size="xs" tone="muted" fontFamily="$mono">
|
|
{example.label}
|
|
</Line>
|
|
<XStack flex={1} />
|
|
<CopyButton value={example.code} />
|
|
</XStack>
|
|
{example.sample}
|
|
</YStack>
|
|
</TabsContent>
|
|
))}
|
|
</Tabs>
|
|
</YStack>
|
|
</YStack>
|
|
</motion.section>
|
|
);
|
|
}
|
|
|
|
export default CodeExamplesSection;
|