Files
new-api/web/default/src/features/home/components/sections/features.tsx
T

223 lines
7.6 KiB
TypeScript
Vendored

import {
Zap,
Shield,
Globe,
Code,
Gauge,
DollarSign,
Users,
HeartHandshake,
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { AnimateInView } from '@/components/animate-in-view'
interface FeaturesProps {
className?: string
}
export function Features(_props: FeaturesProps) {
const { t } = useTranslation()
const features = [
{
id: 'fast',
num: '01',
title: t('Lightning Fast'),
desc: t(
'Optimized network architecture ensures millisecond response times'
),
span: 'md:col-span-2',
icon: <Zap className='size-4 text-blue-400' />,
visual: (
<div className='mt-4 grid grid-cols-3 gap-2'>
{['OpenAI', 'Claude', 'Gemini', 'DeepSeek', 'Qwen', 'Llama'].map(
(name) => (
<div
key={name}
className='border-border/30 bg-muted/20 text-muted-foreground flex items-center justify-center rounded-lg border px-3 py-2 text-xs transition-colors duration-300 hover:border-blue-500/30 hover:bg-blue-500/5'
>
{name}
</div>
)
)}
</div>
),
},
{
id: 'secure',
num: '02',
title: t('Secure & Reliable'),
desc: t(
'Enterprise-grade security with comprehensive permission management'
),
span: 'md:col-span-1',
icon: <Shield className='size-4 text-emerald-400' />,
visual: (
<div className='mt-4 flex items-center justify-center'>
<div className='relative'>
<div className='flex size-16 items-center justify-center rounded-2xl border border-emerald-500/20 bg-emerald-500/5'>
<Shield
className='size-7 text-emerald-500/70'
strokeWidth={1.5}
/>
</div>
<div className='absolute -top-1 -right-1 flex size-4 items-center justify-center rounded-full bg-emerald-500'>
<svg
className='size-2.5 text-white'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
strokeWidth={3}
>
<path
strokeLinecap='round'
strokeLinejoin='round'
d='m4.5 12.75 6 6 9-13.5'
/>
</svg>
</div>
</div>
</div>
),
},
{
id: 'global',
num: '03',
title: t('Global Coverage'),
desc: t('Multi-region deployment for stable global access'),
span: 'md:col-span-1',
icon: <Globe className='size-4 text-violet-400' />,
visual: (
<div className='mt-4 space-y-2'>
{[t('Load Balancing'), t('Rate Limiting'), t('Cost Tracking')].map(
(step, i) => (
<div key={step} className='flex items-center gap-2'>
<div
className={`flex size-6 items-center justify-center rounded-full text-[10px] font-bold ${
i === 1
? 'border border-blue-500/30 bg-blue-500/20 text-blue-500'
: 'border-border/40 bg-muted text-muted-foreground border'
}`}
>
{i + 1}
</div>
<div className='bg-border/40 h-px flex-1' />
<span className='text-muted-foreground text-xs'>{step}</span>
</div>
)
)}
</div>
),
},
{
id: 'developer',
num: '04',
title: t('Developer Friendly'),
desc: t('Compatible API routes for common AI application workflows'),
span: 'md:col-span-2',
icon: <Code className='size-4 text-amber-400' />,
visual: (
<div className='mt-4 flex items-center gap-3'>
<div className='flex -space-x-2'>
{['API', 'SDK', 'CLI', 'Docs'].map((n) => (
<div
key={n}
className='border-background from-muted to-muted/60 text-muted-foreground flex size-8 items-center justify-center rounded-full border-2 bg-gradient-to-br text-[9px] font-bold'
>
{n}
</div>
))}
</div>
<div className='text-muted-foreground flex items-center gap-1.5 text-xs'>
<Code className='size-3.5 text-blue-500' />
{t('Multi-protocol Compatible')}
</div>
</div>
),
},
]
const additionalFeatures = [
{
icon: <Gauge className='size-5' strokeWidth={1.5} />,
title: t('High Performance'),
desc: t('Support for high concurrency with automatic load balancing'),
},
{
icon: <DollarSign className='size-5' strokeWidth={1.5} />,
title: t('Transparent Billing'),
desc: t('Pay-as-you-go with real-time usage monitoring'),
},
{
icon: <Users className='size-5' strokeWidth={1.5} />,
title: t('Team Collaboration'),
desc: t('Multi-user management with flexible permission allocation'),
},
{
icon: <HeartHandshake className='size-5' strokeWidth={1.5} />,
title: t('Open Source'),
desc: t('Community driven, self-hosted, and extensible'),
},
]
return (
<section className='relative z-10 px-6 py-24 md:py-32'>
<div className='mx-auto max-w-6xl'>
<AnimateInView className='mb-16 max-w-lg'>
<p className='text-muted-foreground mb-3 text-xs font-medium tracking-widest uppercase'>
{t('Core Features')}
</p>
<h2 className='text-2xl leading-tight font-bold tracking-tight md:text-3xl'>
{t('Built for developers,')}
<br />
{t('designed for scale')}
</h2>
</AnimateInView>
{/* Bento grid */}
<div className='border-border/40 bg-border/40 grid gap-px overflow-hidden rounded-xl border md:grid-cols-3'>
{features.map((f, i) => (
<AnimateInView
key={f.id}
delay={i * 100}
animation='scale-in'
className={`bg-background group hover:bg-muted/20 p-7 transition-colors duration-300 md:p-8 ${f.span}`}
>
<div className='mb-3 flex items-center gap-3'>
<span className='border-border/40 bg-muted text-muted-foreground flex size-7 items-center justify-center rounded-md border text-[10px] font-semibold tabular-nums'>
{f.num}
</span>
<h3 className='text-sm font-semibold'>{f.title}</h3>
</div>
<p className='text-muted-foreground text-sm leading-relaxed'>
{f.desc}
</p>
{f.visual}
</AnimateInView>
))}
</div>
{/* Additional features row */}
<div className='mt-12 grid grid-cols-2 gap-8 md:grid-cols-4 md:gap-12'>
{additionalFeatures.map((f, i) => (
<AnimateInView
key={f.title}
delay={i * 100}
animation='fade-up'
className='flex flex-col items-center text-center'
>
<div className='text-muted-foreground border-border/50 bg-muted/30 group-hover:text-foreground mb-3 flex size-12 items-center justify-center rounded-xl border transition-colors'>
{f.icon}
</div>
<h3 className='mb-1.5 text-sm font-semibold'>{f.title}</h3>
<p className='text-muted-foreground max-w-[200px] text-xs leading-relaxed'>
{f.desc}
</p>
</AnimateInView>
))}
</div>
</div>
</section>
)
}