Files
hanzo.ai/components/family/Read.tsx
zeekayandHanzo Dev d9dc417ee5 Let the family reading grid typecheck.
gui's align union has flex-start, and items="start" failed tsc, which is the check in front of the publish.

Co-authored-by: Hanzo Dev <[email protected]>
2026-10-07 14:44:03 -07:00

91 lines
2.8 KiB
TypeScript

'use client'
/**
* The map at the foot of a family page: its models, its benchmarks, its
* writing. The page passes the links. This file owns none of them, and it
* does not point at another family — that comparison is /models.
*
* A row is the link. The arrow is drawn here, so a label does not carry one.
*/
import { ArrowRight, ArrowUpRight } from 'lucide-react'
import { Band, Card, Head } from '@/components/marketing/band'
import { Text, XStack, YStack } from '@hanzo/ui'
import { Grid } from '@hanzo/ui/grid'
export type ReadLink = { href: string; label: string; note?: string }
export type ReadGroup = { label: string; links: readonly ReadLink[] }
function labelOf(label: string) {
return label.endsWith(' →') ? label.slice(0, -2) : label
}
function Row({ link }: { link: ReadLink }) {
const external = link.href.startsWith('http')
return (
<XStack
render={
<a
href={link.href}
{...(external ? { target: '_blank', rel: 'noreferrer noopener' } : {})}
/>
}
group
width="100%"
items="center"
gap="$3"
px="$5"
py="$3"
borderTopWidth={1}
borderColor="var(--border)"
hoverStyle={{ bg: '$hover' }}
focusVisibleStyle={{ outlineWidth: 2, outlineStyle: 'solid', outlineColor: 'var(--ring)', outlineOffset: -2 }}
$touchable={{ minH: 44 }}
$platform-web={{ textDecoration: 'none', transition: 'background-color var(--duration-fast) var(--ease-in-out)' }}
>
<YStack flex={1} minW={0} gap="$1">
<Text fontSize="$3" lineHeight="$3" fontWeight="500" color="$ink">
{labelOf(link.label)}
</Text>
{link.note ? (
<Text fontSize="$2" lineHeight="$2" color="var(--text-secondary)">
{link.note}
</Text>
) : null}
</YStack>
<Text display="inline-flex" color="var(--muted-foreground)" $group-hover={{ color: '$ink' }} $group-focusVisible={{ color: '$ink' }}>
{external ? <ArrowUpRight size={16} /> : <ArrowRight size={16} />}
</Text>
</XStack>
)
}
export function Read({
eyebrow,
title,
lede,
groups,
}: {
eyebrow: string
title: string
lede: string
groups: readonly ReadGroup[]
}) {
return (
<Band measure={1024}>
<Head eyebrow={eyebrow} title={title} lede={lede} />
<Grid columns={{ min: 280, max: 3 }} gap={16} items="flex-start">
{groups.map((group) => (
<Card key={group.label} p={0} overflow="hidden">
<Text render="h3" px="$5" pt="$5" pb="$4" fontSize="$4" lineHeight="$4" fontWeight="600" color="$ink">
{group.label}
</Text>
{group.links.map((link) => (
<Row key={link.href + link.label} link={link} />
))}
</Card>
))}
</Grid>
</Band>
)
}