SPB Git forge
3commits 1branches 0releases
417.0 KBsize
maindefault branch
10 days agolast push
TypeScript 66.5% Python 30.9% JavaScript 1.4% CSS 0.7%
2.3 KB · 52 lines tsx
Raw Blame History
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