mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 04:20:06 +00:00
80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
'use client'
|
|
|
|
import React from "react";
|
|
import { motion } from "@/components/motion";
|
|
import { Check } from "lucide-react";
|
|
import type { OperatorModel } from "./operatorModelData";
|
|
import { Box, View, YStack, XStack } from '@hanzo/ui'
|
|
import { Line } from '@/components/type'
|
|
import { Words } from '@/components/marketing/band'
|
|
|
|
interface ModelCardProps {
|
|
model: OperatorModel;
|
|
index: number;
|
|
}
|
|
|
|
/**
|
|
* The tile a provider sits in. Its edge is the one thing that varies — the
|
|
* recommended row is drawn at half white, the rest at the hairline — so the
|
|
* edge is the only value computed per card and everything else is stated once.
|
|
*
|
|
* It has no hover: hovered and at rest the tile is the same
|
|
* oklab(0.204625 … / 0.3).
|
|
*/
|
|
const CARD = {
|
|
position: 'relative',
|
|
p: 24,
|
|
rounded: 'var(--radius-xl)',
|
|
background: 'color-mix(in oklab, var(--neutral-900) 30%, transparent)',
|
|
} as const
|
|
|
|
/** The flag over the recommended tile, hung off its top edge. */
|
|
const FLAG = {
|
|
position: 'absolute',
|
|
t: 0,
|
|
r: 24,
|
|
y: '-50%',
|
|
px: 12,
|
|
py: 4,
|
|
rounded: 'var(--radius-full)',
|
|
bg: 'var(--primary)',
|
|
color: 'var(--primary-foreground)',
|
|
fontSize: '$1',
|
|
lineHeight: 'calc(1 / 0.75)',
|
|
weight: '600',
|
|
} as const
|
|
|
|
const ModelCard = ({ model, index }: ModelCardProps) => {
|
|
return (
|
|
<View
|
|
key={index}
|
|
render={<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5, delay: index * 0.1 }} />}
|
|
display="block"
|
|
{...CARD}
|
|
border={`1px solid ${model.recommended ? 'color-mix(in oklab, var(--pure-white) 50%, transparent)' : 'var(--neutral-800)'}`}
|
|
>
|
|
{model.recommended && <Words {...FLAG}>Recommended</Words>}
|
|
|
|
<Line render="h3" size="xl" weight="600" color="var(--white)" marginBottom={4}>{model.name}</Line>
|
|
<Line render="p" size="sm" tone="muted" marginBottom={16}>by {model.provider}</Line>
|
|
|
|
<YStack render="ul" gap={8} mb={24}>
|
|
{model.features.map((feature, i) => (
|
|
<XStack render="li" key={i} items="flex-start">
|
|
<View mr={8} mt={2}>
|
|
<Check width={20} height={20} color="var(--foreground)" />
|
|
</View>
|
|
<Line size="sm" tone="soft">{feature}</Line>
|
|
</XStack>
|
|
))}
|
|
</YStack>
|
|
|
|
<Box pt={8} mt="auto">
|
|
<Line render="p" size="sm" tone="muted" fontFamily="$mono">{model.command}</Line>
|
|
</Box>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default ModelCard;
|