mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Inline style objects became gui props (Box for a div, View or Text rendering the element for the rest, since Box styles only a div), raw colours and sizes became the design's tokens, the brand swatches read @hanzo/design's own values, and the project and creation hues moved to palette.json, which is data. The newsletter's subscribe button is the standard filled Action. connect-steps.tsx, which nothing imports, is deleted with the brand constants nobody read. Pages compared before and after at 1440x900 and 390x844: blockchain, brand, directory, projects, settings, unsubscribe identical; founder 0.03% of pixels; buying specialist's title snaps from 28 to the ramp's 26px and the newsletter's button is now filled. Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
85 lines
3.6 KiB
TypeScript
85 lines
3.6 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* The connector wall — every tool Hanzo works with, drawn as its own mark.
|
|
*
|
|
* The marks are white PNGs on a dark surface, which is the whole reason they
|
|
* read as one set rather than 200 competing brand colours. They are lazy: two
|
|
* hundred images above nothing is a page that loads slowly for a section most
|
|
* readers scroll past.
|
|
*
|
|
* Attribution is part of the section, not a footnote somewhere else. The marks
|
|
* belong to their owners and are shown to say what Hanzo connects to — a
|
|
* statement about this product, not a claim about theirs.
|
|
*
|
|
* NO TAILWIND AND NO STYLE OBJECTS: gui props over the design tokens. The grid is
|
|
* `@hanzo/ui/grid`'s `Grid`, whose `{min, max}` is one responsive track list
|
|
* rather than three breakpoint class sets — and `min` is a FIT floor
|
|
* (`min(Npx, 100%)`), so a 200-mark wall does not force a phone to scroll
|
|
* sideways.
|
|
*/
|
|
|
|
import { motion } from '@/components/motion'
|
|
import { Box, Text, View, XStack } from '@hanzo/ui'
|
|
import { Grid } from '@hanzo/ui/grid'
|
|
import { categories, CONNECTORS, type ConnectorGroup } from '@/lib/data/connectors'
|
|
import { fade, SectionHead } from '@/components/product/ProductLanding'
|
|
import type { SectionCopy } from '@/components/product/ProductLanding'
|
|
import { Line } from '@hanzo/ui/marketing'
|
|
|
|
export interface ConnectorsProps extends Partial<SectionCopy> {
|
|
/** Show one half of the catalogue. Omit for all of it. */
|
|
group?: ConnectorGroup
|
|
}
|
|
|
|
export function Connectors({ group, eyebrow, title, sub }: ConnectorsProps) {
|
|
const groups = categories(group)
|
|
const total = group ? CONNECTORS.filter((c) => c.group === group).length : CONNECTORS.length
|
|
|
|
return (
|
|
<Box render="section" borderTopWidth={1} borderColor="var(--border)" px={16} py={96}>
|
|
<Box mx="auto" maxW={1280}>
|
|
<SectionHead eyebrow={eyebrow} title={title} sub={sub} />
|
|
<Grid columns={1} gap={48}>
|
|
{groups.map((g, gi) => (
|
|
<motion.div key={g.category} {...fade} transition={{ duration: 0.5, delay: gi * 0.04 }}>
|
|
<Line render="div" display="block" mb={16} fontSize="$1" fontWeight="600" textTransform="uppercase" color="var(--muted-foreground)" letterSpacing="0.1em">
|
|
{g.category}
|
|
</Line>
|
|
<Grid columns={{ min: 72, max: 10 }} gap={12}>
|
|
{g.items.map((c) => (
|
|
/* One mark in its own cell. Square, because a wall of mixed ratios is a mess. */
|
|
<XStack
|
|
key={c.slug}
|
|
aspectRatio={1}
|
|
items="center"
|
|
justify="center"
|
|
rounded="var(--radius-xl, 16px)"
|
|
borderWidth={1}
|
|
borderColor="var(--border)"
|
|
bg="var(--surface-1)"
|
|
p={12}
|
|
>
|
|
<View
|
|
render={<img src={c.file} alt={c.name} title={c.name} width={512} height={512} loading="lazy" decoding="async" />}
|
|
display="block"
|
|
width={32}
|
|
height={32}
|
|
objectFit="contain"
|
|
opacity={0.7}
|
|
/>
|
|
</XStack>
|
|
))}
|
|
</Grid>
|
|
</motion.div>
|
|
))}
|
|
</Grid>
|
|
<Text render="p" display="block" mt={40} mx="auto" maxW={768} text="center" fontSize="$1" color="var(--text-tertiary)">
|
|
{total} tools. Each mark belongs to its owner and is shown to say what Hanzo connects
|
|
to — not to imply any partnership or endorsement.
|
|
</Text>
|
|
</Box>
|
|
</Box>
|
|
)
|
|
}
|