mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
327 lines
11 KiB
TypeScript
327 lines
11 KiB
TypeScript
'use client'
|
|
|
|
import React from "react";
|
|
import { motion } from "@/components/motion";
|
|
import Link from "next/link";
|
|
import {
|
|
Shield,
|
|
Zap,
|
|
Database,
|
|
Key,
|
|
HardDrive,
|
|
Activity,
|
|
Webhook,
|
|
Terminal,
|
|
Server,
|
|
Lock,
|
|
Users,
|
|
FileJson,
|
|
Clock,
|
|
ChevronRight
|
|
} from "lucide-react";
|
|
import { View, YStack, XStack } from '@hanzo/ui'
|
|
import { Grid } from '@hanzo/ui/grid'
|
|
import { Words } from '@/components/marketing/band'
|
|
import { Line } from '@/components/type'
|
|
import { Action, Chip, Lede, Title, Leaf } from '@hanzo/ui/marketing'
|
|
|
|
/** What a card's name comes up to on approach: full ink. */
|
|
const LIFT = { color: 'var(--text-primary)' } as const
|
|
|
|
interface Service {
|
|
name: string;
|
|
description: string;
|
|
icon: React.ElementType;
|
|
href?: string;
|
|
}
|
|
|
|
const CORE_SERVICES: Service[] = [
|
|
{
|
|
name: "Auth & IAM",
|
|
description: "Authentication, SSO, OAuth, JWT, and sovereign user management out of the box",
|
|
icon: Shield,
|
|
href: "/iam",
|
|
},
|
|
{
|
|
name: "Serverless Functions",
|
|
description: "Serverless functions with automatic scaling and edge deployment",
|
|
icon: Zap,
|
|
href: "/functions",
|
|
},
|
|
{
|
|
name: "Database & Datastore",
|
|
description: "High-performance SQL, vector search, and real-time subscriptions",
|
|
icon: Database,
|
|
href: "/datastore",
|
|
},
|
|
{
|
|
name: "Object Storage",
|
|
description: "S3-compatible distributed object storage with global CDN integration",
|
|
icon: HardDrive,
|
|
href: "/s3",
|
|
},
|
|
{
|
|
name: "Realtime Sync",
|
|
description: "WebSockets, presence, and live state replication for collaborative apps",
|
|
icon: Activity,
|
|
href: "/realtime",
|
|
},
|
|
{
|
|
name: "Secrets & KMS",
|
|
description: "Hardware-backed secret management, envelope encryption, and key rotation",
|
|
icon: Key,
|
|
href: "/kms",
|
|
},
|
|
];
|
|
|
|
const ADDITIONAL_SERVICES: Service[] = [
|
|
{
|
|
name: "API Gateway",
|
|
description: "Rate limiting, auth verification, and intelligent request routing",
|
|
icon: Server,
|
|
href: "/gateway",
|
|
},
|
|
{
|
|
name: "Background Tasks",
|
|
description: "Scheduled cron jobs and durable task queues with retry logic",
|
|
icon: Clock,
|
|
href: "/tasks",
|
|
},
|
|
{
|
|
name: "PubSub & Webhooks",
|
|
description: "Event-driven messaging and real-time webhook delivery",
|
|
icon: Webhook,
|
|
href: "/pubsub",
|
|
},
|
|
{
|
|
name: "Observability & O11y",
|
|
description: "OpenTelemetry traces, metrics, structured logs, and audit trails",
|
|
icon: Users,
|
|
href: "/o11y",
|
|
},
|
|
{
|
|
name: "Edge Network",
|
|
description: "Global edge compute, smart routing, and low-latency cache",
|
|
icon: FileJson,
|
|
href: "/edge",
|
|
},
|
|
{
|
|
name: "Vector & Search",
|
|
description: "Hybrid keyword and dense vector search with sub-millisecond retrieval",
|
|
icon: Lock,
|
|
href: "/products/memory",
|
|
},
|
|
];
|
|
|
|
/** The band's own ground: the page fading into the next section. */
|
|
const FADE = 'linear-gradient(to bottom, var(--background), color-mix(in oklab, var(--neutral-900) 30%, transparent))'
|
|
|
|
/** A group's heading over its grid. */
|
|
const GROUP = { fontSize: '$4', lineHeight: 'calc(1.75 / 1.125)', weight: '600', color: 'var(--foreground)', mb: 24 } as const
|
|
|
|
/** A line of the CLI transcript, and the prompt that opens a command. */
|
|
function Out({ mt, children }: { mt?: number; children: React.ReactNode }) {
|
|
return <Words render="div" mt={mt} color="var(--muted-foreground)">{children}</Words>
|
|
}
|
|
const PROMPT = <Words color="var(--foreground)">$</Words>
|
|
|
|
/** The eyebrow badge — `Chip`'s outline with this page's tinted fill. */
|
|
const BADGE = { self: "center", mb: 16, px: 12, py: 4, fontSize: "$1", lineHeight: "calc(1 / 0.75)", fontWeight: "500", bg: "color-mix(in srgb, var(--primary) 15%, transparent)", color: "var(--primary)" } as const
|
|
|
|
/**
|
|
* A core service tile. `Leaf` is the card that IS a link — its edge lifts on
|
|
* approach, which is the one thing a style attribute cannot say. Padding and
|
|
* both edges are its declared knobs, so a caller states three custom properties
|
|
* rather than a `group`/`group-hover:` pair.
|
|
*/
|
|
const leaf = (href?: string) =>
|
|
({
|
|
p: 24,
|
|
borderColor: 'var(--border)',
|
|
hoverStyle: { borderColor: href ? 'var(--white-30)' : 'var(--border)' },
|
|
rounded: 'var(--radius-xl)',
|
|
bg: 'color-mix(in oklab, var(--secondary) 50%, transparent)',
|
|
}) as const
|
|
|
|
const PaaSCapabilities = () => {
|
|
return (
|
|
<YStack
|
|
render="section"
|
|
py={96}
|
|
px={16}
|
|
$md={{ px: 32 }}
|
|
background={FADE}
|
|
>
|
|
<YStack width="100%" maxW={1152} mx="auto">
|
|
{/* Section header */}
|
|
<YStack
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
|
|
mb={64}
|
|
$platform-web={{ textAlign: 'center' }}
|
|
>
|
|
<Chip {...BADGE}>
|
|
<Terminal width={14} height={14} />
|
|
Platform-as-a-Service
|
|
</Chip>
|
|
<Title quiet mb={16}>
|
|
The services an app needs anyway
|
|
</Title>
|
|
<Lede maxW={672} mx="auto" mt="$3.5">
|
|
Platform ships your code. These are the pieces it lands next to.
|
|
Deploy each one beside your app, or reach it on Hanzo Cloud.
|
|
</Lede>
|
|
</YStack>
|
|
|
|
{/* Core services */}
|
|
<YStack mb={48}>
|
|
<Words render={<motion.h3 initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />} {...GROUP}>
|
|
Core Services
|
|
</Words>
|
|
<Grid columns={{ min: 300, max: 3 }} gap={16}>
|
|
{CORE_SERVICES.map((service, index) => {
|
|
const Icon = service.icon;
|
|
const content = (
|
|
<Leaf
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: index * 0.05 }} />}
|
|
{...leaf(service.href)}
|
|
>
|
|
<XStack items="flex-start" gap={16}>
|
|
<XStack
|
|
width={40}
|
|
height={40}
|
|
items="center"
|
|
justify="center"
|
|
shrink={0}
|
|
rounded="var(--radius-lg)"
|
|
background="color-mix(in srgb, var(--primary) 15%, transparent)"
|
|
>
|
|
<Icon width={20} height={20} />
|
|
</XStack>
|
|
<YStack flex={1} minW={0}>
|
|
<Line render="h4" weight="500" display="block" marginBottom={4} $group-hover={LIFT}>{service.name}</Line>
|
|
<Line render="p" size="sm" tone="muted" display="block">{service.description}</Line>
|
|
</YStack>
|
|
</XStack>
|
|
</Leaf>
|
|
);
|
|
|
|
return service.href ? (
|
|
<Link key={service.name} href={service.href || "#"}>
|
|
{content}
|
|
</Link>
|
|
) : (
|
|
<div key={service.name}>{content}</div>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</YStack>
|
|
|
|
{/* Additional services */}
|
|
<YStack mb={48}>
|
|
<Words render={<motion.h3 initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />} {...GROUP}>
|
|
Additional Services
|
|
</Words>
|
|
<Grid columns={{ min: 300, max: 3 }} gap={16}>
|
|
{ADDITIONAL_SERVICES.map((service, index) => {
|
|
const Icon = service.icon;
|
|
const cardContent = (
|
|
<Leaf
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: index * 0.05 }} />}
|
|
{...leaf(service.href)}
|
|
>
|
|
<XStack items="center" gap={12}>
|
|
<Icon width={16} height={16} color="var(--primary)" />
|
|
<div>
|
|
<Line size="sm" weight="500" $group-hover={LIFT}>{service.name}</Line>
|
|
<Line size="xs" tone="muted" display="block" marginTop={2}>{service.description}</Line>
|
|
</div>
|
|
</XStack>
|
|
</Leaf>
|
|
);
|
|
|
|
return service.href ? (
|
|
<Link key={service.name} href={service.href}>
|
|
{cardContent}
|
|
</Link>
|
|
) : (
|
|
<div key={service.name}>{cardContent}</div>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</YStack>
|
|
|
|
{/* CLI showcase */}
|
|
<View
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
|
|
display="block"
|
|
rounded="var(--radius-xl)"
|
|
borderWidth={1}
|
|
borderColor="var(--border)"
|
|
background="color-mix(in oklab, var(--secondary) 80%, transparent)"
|
|
overflow="hidden"
|
|
>
|
|
<XStack items="center" gap={12} px={16} py={12} borderBottomWidth={1} borderColor="var(--border)">
|
|
<XStack gap={6}>
|
|
<YStack width={12} height={12} rounded="var(--radius-full)" bg="$raised" />
|
|
<YStack width={12} height={12} rounded="var(--radius-full)" bg="$raised" />
|
|
<YStack width={12} height={12} rounded="var(--radius-full)" bg="$raised" />
|
|
</XStack>
|
|
<Line size="xs" tone="muted" fontFamily="$mono">hanzo platform</Line>
|
|
</XStack>
|
|
<Words render="div" display="flex" flexDirection="column" p={24} fontFamily="$mono" fontSize="$2" lineHeight="calc(1.25 / 0.875)">
|
|
<YStack gap={12}>
|
|
<Out>{PROMPT} hanzo init my-app</Out>
|
|
<Out>✓ Created project configuration</Out>
|
|
<Out>✓ Initialized Auth, Database, Storage</Out>
|
|
<Out>✓ Generated TypeScript types</Out>
|
|
<Out mt={16}>{PROMPT} hanzo dev</Out>
|
|
<Out>Starting local development server...</Out>
|
|
<XStack items="center" gap={8}>
|
|
<YStack width={8} height={8} rounded="var(--radius-full)" bg="var(--primary)" />
|
|
<Line color="var(--foreground)">
|
|
Platform running at http://localhost:8000
|
|
</Line>
|
|
</XStack>
|
|
<Out mt={16}>{PROMPT} hanzo serve cloud</Out>
|
|
<Out>Deploying to production...</Out>
|
|
<XStack items="center" gap={8}>
|
|
<YStack width={8} height={8} rounded="var(--radius-full)" bg="var(--primary)" />
|
|
<Line color="var(--foreground)">
|
|
Live at https://my-app.hanzo.app
|
|
</Line>
|
|
</XStack>
|
|
</YStack>
|
|
</Words>
|
|
</View>
|
|
|
|
{/* Bottom CTA */}
|
|
<XStack
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} />}
|
|
flexWrap="wrap"
|
|
justify="center"
|
|
gap={16}
|
|
mt={48}
|
|
>
|
|
<Action
|
|
href="https://docs.hanzo.ai/docs/cli/platform"
|
|
target="_blank"
|
|
rel="noreferrer noopener"
|
|
fill
|
|
>
|
|
Read the docs
|
|
<ChevronRight width={16} height={16} />
|
|
</Action>
|
|
<Action
|
|
href="/cloud"
|
|
>
|
|
Explore Cloud
|
|
<ChevronRight width={16} height={16} />
|
|
</Action>
|
|
</XStack>
|
|
</YStack>
|
|
</YStack>
|
|
);
|
|
};
|
|
|
|
export default PaaSCapabilities;
|