126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { useConvexAuth } from 'convex/react';
|
|
import {
|
|
ArrowRight,
|
|
Bot,
|
|
CheckCircle2,
|
|
GitBranch,
|
|
GitPullRequest,
|
|
ShieldCheck,
|
|
} from 'lucide-react';
|
|
|
|
import { Badge, Button } from '@spoon/ui';
|
|
|
|
const previewRows = [
|
|
{
|
|
name: 'editor-spoon',
|
|
upstream: 'upstream/main',
|
|
status: 'Clean update',
|
|
icon: CheckCircle2,
|
|
tone: 'text-emerald-600',
|
|
},
|
|
{
|
|
name: 'billing-fork',
|
|
upstream: 'release/2026.06',
|
|
status: 'AI review queued',
|
|
icon: Bot,
|
|
tone: 'text-teal-600',
|
|
},
|
|
{
|
|
name: 'docs-platform',
|
|
upstream: 'main',
|
|
status: 'Needs review',
|
|
icon: GitPullRequest,
|
|
tone: 'text-amber-600',
|
|
},
|
|
];
|
|
|
|
export const Hero = () => {
|
|
const { isAuthenticated } = useConvexAuth();
|
|
return (
|
|
<section className='container mx-auto px-4 py-16 md:py-24'>
|
|
<div className='grid items-center gap-10 lg:grid-cols-[0.92fr_1.08fr]'>
|
|
<div className='max-w-3xl'>
|
|
<Badge variant='outline' className='mb-5 gap-2'>
|
|
<ShieldCheck className='size-3.5 text-emerald-600' />
|
|
Self-hostable fork maintenance
|
|
</Badge>
|
|
<h1 className='max-w-4xl text-4xl font-semibold tracking-normal text-balance sm:text-5xl md:text-6xl'>
|
|
Fork freely. Stay close to upstream.
|
|
</h1>
|
|
<p className='text-muted-foreground mt-6 max-w-2xl text-lg leading-8'>
|
|
Spoon helps you customize upstream projects without inheriting the
|
|
full maintenance burden. Track drift, review update risk, and keep
|
|
managed forks ready for merge requests.
|
|
</p>
|
|
<div className='mt-8 flex flex-col gap-3 sm:flex-row'>
|
|
<Button size='lg' asChild>
|
|
<Link href={isAuthenticated ? '/dashboard' : '/sign-in'}>
|
|
{isAuthenticated ? 'Open dashboard' : 'Start with Spoon'}
|
|
<ArrowRight className='size-4' />
|
|
</Link>
|
|
</Button>
|
|
<Button size='lg' variant='outline' asChild>
|
|
<Link href='#workflow'>See how it works</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className='border-border bg-card border shadow-sm'>
|
|
<div className='border-border flex items-center justify-between border-b px-5 py-4'>
|
|
<div>
|
|
<p className='text-sm font-medium'>Spoon dashboard</p>
|
|
<p className='text-muted-foreground text-xs'>
|
|
Upstream status across managed forks
|
|
</p>
|
|
</div>
|
|
<Badge className='bg-primary/10 text-primary hover:bg-primary/10'>
|
|
3 active Spoons
|
|
</Badge>
|
|
</div>
|
|
<div className='grid gap-4 p-5 md:grid-cols-3'>
|
|
{[
|
|
['Updates', '4', '2 clean'],
|
|
['Needs review', '1', 'conflict risk'],
|
|
['Agents', '2', 'queued'],
|
|
].map(([label, value, note]) => (
|
|
<div
|
|
key={label}
|
|
className='border-border bg-background border p-4'
|
|
>
|
|
<p className='text-muted-foreground text-xs'>{label}</p>
|
|
<p className='mt-2 text-2xl font-semibold'>{value}</p>
|
|
<p className='text-muted-foreground mt-1 text-xs'>{note}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className='space-y-3 px-5 pb-5'>
|
|
{previewRows.map(({ name, upstream, status, icon: Icon, tone }) => (
|
|
<div
|
|
key={name}
|
|
className='border-border bg-background flex items-center justify-between gap-4 border p-4'
|
|
>
|
|
<div className='flex items-center gap-3'>
|
|
<span className='bg-muted flex size-9 items-center justify-center rounded-md'>
|
|
<GitBranch className='size-4' />
|
|
</span>
|
|
<div>
|
|
<p className='text-sm font-medium'>{name}</p>
|
|
<p className='text-muted-foreground text-xs'>{upstream}</p>
|
|
</div>
|
|
</div>
|
|
<span className='flex items-center gap-2 text-sm'>
|
|
<Icon className={`size-4 ${tone}`} />
|
|
{status}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|