import {
IconCloud as Cloud,
IconContainer as Container,
IconDatabase as Database,
IconWorld as Globe,
IconDeviceSdCard as HardDrive,
IconKey as Key,
IconStack2 as Layers,
IconRadio as Radio,
IconServer as Server,
IconBolt as Zap,
} from '@tabler/icons-react';
import { motion } from 'framer-motion';
import { FresnelEdge } from '../effects/FresnelEdge';
import { GlowTracker } from '../effects/GlowTracker';
/* ------------------------------------------------------------------ */
/* Layer data */
/* ------------------------------------------------------------------ */
interface TechItem {
icon: React.ComponentType<{ className?: string; stroke?: number }>;
label: string;
accent: 'teal' | 'magenta';
}
interface LayerConfig {
id: string;
title: string;
/** Tailwind max-width class — drives the pyramid shape */
maxWidth: string;
borderColor: string;
glowShadow: string;
/** Framer Motion entrance delay (bottom-up stagger) */
delay: number;
/** Framer Motion entrance y offset */
yOffset: number;
accent: 'teal' | 'magenta';
items: TechItem[];
/** Optional second row of items (Supabase uses a 2×2 + banner layout) */
itemsRow2?: TechItem[];
/** Full-width banner item (PostgreSQL) */
banner?: TechItem;
/** Show divider between items (Backend layer) */
divider?: boolean;
/** Show dot-grid background (Infrastructure layer) */
dotGrid?: boolean;
}
const LAYERS: LayerConfig[] = [
{
id: 'frontend',
title: 'FRONTEND',
maxWidth: 'max-w-md',
borderColor: 'border-primary/20',
glowShadow: '0 8px 32px oklch(0.82 0.14 192 / 0.15)',
delay: 0.55,
yOffset: 10,
accent: 'teal',
items: [
{ icon: Zap, label: 'React 19', accent: 'teal' },
{ icon: Globe, label: 'Vite', accent: 'teal' },
{ icon: Layers, label: 'Shadcn UI', accent: 'teal' },
],
},
{
id: 'backend',
title: 'BACKEND',
maxWidth: 'max-w-lg',
borderColor: 'border-primary/20',
glowShadow: '0 8px 24px oklch(0.82 0.14 192 / 0.10)',
delay: 0.4,
yOffset: 20,
accent: 'teal',
divider: true,
items: [
{ icon: Globe, label: 'Traefik', accent: 'teal' },
{ icon: Server, label: 'Hono API', accent: 'teal' },
],
},
{
id: 'supabase',
title: 'SUPABASE',
maxWidth: 'max-w-xl',
borderColor: 'border-primary/20',
glowShadow: '0 8px 28px oklch(0.75 0.20 270 / 0.12)',
delay: 0.25,
yOffset: 30,
accent: 'teal',
items: [
{ icon: Key, label: 'Auth', accent: 'teal' },
{ icon: Globe, label: 'REST API', accent: 'teal' },
],
itemsRow2: [
{ icon: Radio, label: 'Realtime', accent: 'teal' },
{ icon: HardDrive, label: 'Storage', accent: 'teal' },
],
banner: { icon: Database, label: 'PostgreSQL + RLS', accent: 'teal' },
},
{
id: 'infrastructure',
title: 'INFRASTRUCTURE',
maxWidth: 'max-w-2xl',
borderColor: 'border-secondary-accent/20',
glowShadow: '0 8px 32px oklch(0.65 0.26 350 / 0.12)',
delay: 0.1,
yOffset: 40,
accent: 'magenta',
dotGrid: true,
items: [
{ icon: Container, label: 'Docker', accent: 'teal' },
{ icon: Layers, label: 'Kubernetes', accent: 'teal' },
{ icon: HardDrive, label: 'S3 Storage', accent: 'magenta' },
{ icon: Cloud, label: 'Hetzner', accent: 'magenta' },
],
},
];
/* ------------------------------------------------------------------ */
/* TechChip */
/* ------------------------------------------------------------------ */
function TechChip({ icon: Icon, label, accent }: TechItem) {
const styles = {
teal: {
bg: 'bg-primary/10',
icon: 'text-primary',
border: 'border-primary/20',
hoverGlow: '0 0 12px oklch(0.82 0.14 192 / 0.35)',
},
magenta: {
bg: 'bg-secondary-accent/10',
icon: 'text-secondary-accent',
border: 'border-secondary-accent/20',
hoverGlow: '0 0 12px oklch(0.65 0.26 350 / 0.35)',
},
}[accent];
return (