spb/satelliteindex
Public
TypeScript 66.5%
Python 30.9%
JavaScript 1.4%
CSS 0.7%
1import Link from 'next/link';2import type { ReactNode } from 'react';3import { cn } from '@/lib/cn';45/** Page section with eyebrow + title + optional action. Spatial composition — not everything in a card. */6export function Section({ eyebrow, title, action, children, className, id }: { eyebrow?: string; title?: ReactNode; action?: { href: string; label: string }; children: ReactNode; className?: string; id?: string }) {7 return (8 <section id={id} className={cn('py-8 md:py-12', className)}>9 {(eyebrow || title) && (10 <div className="mb-5 flex items-end justify-between gap-4">11 <div>12 {eyebrow && <p className="eyebrow">{eyebrow}</p>}13 {title && <h2 className="mt-1 text-xl font-semibold tracking-tight md:text-2xl">{title}</h2>}14 </div>15 {action && (16 <Link href={action.href} className="shrink-0 py-1 text-sm text-accent hover:underline">17 {action.label} →18 </Link>19 )}20 </div>21 )}22 {children}23 </section>24 );25}2627export function PageHeader({ eyebrow, title, lede, children, className }: { eyebrow?: ReactNode; title: ReactNode; lede?: ReactNode; children?: ReactNode; className?: string }) {28 return (29 <div className={cn('pb-6 pt-8 md:pb-8 md:pt-12', className)}>30 {eyebrow && <p className="eyebrow">{eyebrow}</p>}31 <h1 className="display mt-2 text-3xl md:text-5xl">{title}</h1>32 {lede && <p className="mt-4 max-w-2xl text-[15px] leading-relaxed text-ink-2 md:text-base">{lede}</p>}33 {children}34 </div>35 );36}3738/** Stat tile: big tabular number + label + optional hint. */39export function Stat({ label, value, hint, className, accent = false }: { label: string; value: ReactNode; hint?: ReactNode; className?: string; accent?: boolean }) {40 return (41 <div className={cn('min-w-0', className)}>42 <p className="eyebrow">{label}</p>43 <p className={cn('tnum mt-1 text-2xl font-semibold tracking-tight md:text-3xl', accent && 'text-accent')}>{value}</p>44 {hint && <p className="mt-0.5 text-xs text-ink-3">{hint}</p>}45 </div>46 );47}4849export function Container({ children, className, wide = false }: { children: ReactNode; className?: string; wide?: boolean }) {50 return <div className={cn('container-x mx-auto w-full', wide ? 'max-w-[1600px]' : 'max-w-[1280px]', className)}>{children}</div>;51}52