TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import Link from 'next/link';2import type { ReactNode } from 'react';3import { cn } from '@/lib/format';4import { StatStrip } from './primitives';56export interface Crumb {7 label: string;8 href?: string;9}1011export function Breadcrumbs({ items, className }: { items: Crumb[]; className?: string }) {12 if (!items.length) return null;13 return (14 <nav aria-label="Breadcrumb" className={cn('mb-2 overflow-x-auto scrollbar-none text-[11px] text-subtle', className)}>15 <ol className="flex min-w-max items-center gap-1">16 {items.map((c, i) => (17 <li key={`${c.label}-${i}`} className="flex items-center gap-1">18 {i > 0 ? (19 <span aria-hidden className="text-border-strong">20 /21 </span>22 ) : null}23 {c.href && i < items.length - 1 ? (24 <Link href={c.href} className="hover:text-fg">25 {c.label}26 </Link>27 ) : (28 <span className={i === items.length - 1 ? 'text-muted' : undefined}>{c.label}</span>29 )}30 </li>31 ))}32 </ol>33 </nav>34 );35}3637/**38 * Consistent page header: breadcrumb → kicker → title → one-line context → meta row → optional KPI strip.39 */40export function PageHeader({ title, description, crumbs, actions, meta, className, compact, kicker, stats }: { title: ReactNode; description?: ReactNode; crumbs?: Crumb[]; actions?: ReactNode; meta?: ReactNode; className?: string; compact?: boolean; kicker?: ReactNode; stats?: Array<{ label: ReactNode; value: ReactNode; sub?: ReactNode; href?: string }> }) {41 return (42 <div className={cn(compact ? 'mb-4' : 'mb-6', className)}>43 {crumbs ? <Breadcrumbs items={crumbs} /> : null}44 <div className="flex flex-wrap items-end justify-between gap-x-6 gap-y-3">45 <div className="min-w-0 flex-1">46 {kicker ? <p className="t-label mb-1.5">{kicker}</p> : null}47 <h1 className={cn('text-fg', compact ? 't-title sm:text-xl' : 't-headline')}>{title}</h1>48 {description ? <p className={cn('mt-1.5 max-w-3xl text-muted', compact ? 'text-[13px] leading-relaxed' : 'text-sm leading-relaxed')}>{description}</p> : null}49 {meta ? <div className="mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted">{meta}</div> : null}50 </div>51 {actions ? <div className="flex shrink-0 flex-wrap items-center gap-2">{actions}</div> : null}52 </div>53 {stats?.length ? <StatStrip items={stats} className="mt-4" /> : null}54 </div>55 );56}57