Add theme toggle, hero snippet, and reorganize homepage components

- Set up next-themes with a light/dark toggle in the header and move all
  sections onto theme tokens; dark mode stays pure black
- Replace the hero terminal line with the AI Elements Snippet component
- Restructure components into layout/, sections/, and shared/ with
  site-wide config in lib/site.ts

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Rami Bitar
2026-09-18 09:29:12 -04:00
co-authored by Claude Fable 5.1
parent a40edbffa9
commit 07a99b441c
28 changed files with 812 additions and 437 deletions
+41
View File
@@ -0,0 +1,41 @@
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
type Action = { label: string; href: string };
export function ActionButtons({
primary,
secondary,
className,
}: {
primary: Action;
secondary?: Action;
className?: string;
}) {
return (
<div
className={cn(
'flex flex-col items-center justify-center gap-3 sm:flex-row',
className,
)}
>
<Button
asChild
size="lg"
className="h-11 rounded-full bg-foreground px-6 text-[15px] text-background hover:bg-foreground/90"
>
<a href={primary.href}>{primary.label}</a>
</Button>
{secondary && (
<Button
asChild
size="lg"
variant="outline"
className="h-11 rounded-full border-foreground/20 bg-transparent px-6 text-[15px] text-foreground hover:bg-foreground/5 hover:text-foreground"
>
<a href={secondary.href}>{secondary.label}</a>
</Button>
)}
</div>
);
}
+20
View File
@@ -0,0 +1,20 @@
import { cn } from '@/lib/utils';
import { siteConfig } from '@/lib/site';
export function Brand({ className }: { className?: string }) {
return (
<span className={cn('flex items-center gap-2 font-medium', className)}>
<svg
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
className="shrink-0"
>
<path d="M12 2L23 21H1L12 2Z" fill="currentColor" />
</svg>
<span className="text-[17px] tracking-tight">{siteConfig.name}</span>
</span>
);
}
+9
View File
@@ -0,0 +1,9 @@
import { type ComponentProps } from 'react';
import { cn } from '@/lib/utils';
export function Container({ className, ...props }: ComponentProps<'div'>) {
return (
<div className={cn('mx-auto w-full max-w-6xl px-6', className)} {...props} />
);
}
+21
View File
@@ -0,0 +1,21 @@
import { cn } from '@/lib/utils';
/**
* Soft conic-gradient bloom used behind hero and CTA copy.
* Position and size it with `className`; it never captures pointer events.
*/
export function GradientGlow({ className }: { className?: string }) {
return (
<div
aria-hidden="true"
className={cn(
'pointer-events-none absolute rounded-full blur-3xl',
className,
)}
style={{
background:
'conic-gradient(from 180deg at 50% 50%, #7c3aed, #2563eb, #06b6d4, #ec4899, #7c3aed)',
}}
/>
);
}
+44
View File
@@ -0,0 +1,44 @@
import { cn } from '@/lib/utils';
export function SectionHeading({
eyebrow,
title,
description,
align = 'left',
className,
}: {
eyebrow?: string;
title: string;
description?: string;
align?: 'left' | 'center';
className?: string;
}) {
return (
<div
className={cn(
'max-w-2xl',
align === 'center' && 'mx-auto text-center',
className,
)}
>
{eyebrow && (
<p className="font-mono text-xs uppercase tracking-[0.2em] text-foreground/40">
{eyebrow}
</p>
)}
<h2
className={cn(
'text-3xl font-semibold tracking-tight sm:text-4xl',
eyebrow && 'mt-4',
)}
>
{title}
</h2>
{description && (
<p className="mt-5 text-lg leading-8 text-foreground/55">
{description}
</p>
)}
</div>
);
}