mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
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]>
91 lines
2.8 KiB
TypeScript
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>
|
|
)
|
|
}
|