features.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. import {
  2. Boxes,
  3. Network,
  4. Send,
  5. ShieldCheck,
  6. TerminalSquare,
  7. Users,
  8. type LucideIcon,
  9. } from 'lucide-react';
  10. // Icons map by position to the localized feature items in lib/site-i18n.ts
  11. // (Every major protocol, REALITY, Clients, Multi-node, Telegram, Self-hosted).
  12. const ICONS: LucideIcon[] = [Boxes, ShieldCheck, Users, Network, Send, TerminalSquare];
  13. export function Features({
  14. heading,
  15. subtitle,
  16. items,
  17. }: {
  18. heading: string;
  19. subtitle: string;
  20. items: { title: string; description: string }[];
  21. }) {
  22. return (
  23. <section className="mx-auto w-full max-w-6xl px-4 py-16 sm:py-24">
  24. <div className="mx-auto max-w-2xl text-center">
  25. <h2 className="text-2xl font-bold tracking-tight sm:text-3xl">{heading}</h2>
  26. <p className="mt-3 text-fd-muted-foreground">{subtitle}</p>
  27. </div>
  28. <div className="mt-12 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
  29. {items.map(({ title, description }, i) => {
  30. const Icon = ICONS[i] ?? Boxes;
  31. return (
  32. <div
  33. key={title}
  34. className="rounded-2xl border bg-fd-card p-6 transition-colors hover:border-fd-primary/40"
  35. >
  36. <div className="inline-flex size-11 items-center justify-center rounded-xl bg-brand/10 text-brand">
  37. <Icon className="size-6" aria-hidden />
  38. </div>
  39. <h3 className="mt-4 font-semibold">{title}</h3>
  40. <p className="mt-2 text-sm text-fd-muted-foreground">{description}</p>
  41. </div>
  42. );
  43. })}
  44. </div>
  45. </section>
  46. );
  47. }