spb/satelliteindex
Public
TypeScript 66.5%
Python 30.9%
JavaScript 1.4%
CSS 0.7%
1import { ArrowRight } from 'lucide-react';2import Link from 'next/link';3import { LazyGlobe } from '@/components/globe/lazy-globe';4import { Container } from '@/components/ui/section';5import { fmtInt } from '@/lib/format';6import { routes } from '@/lib/site';7import type { HomePayload } from '@/lib/types';8import { SearchButton } from './search-button';910function Count({ label, value, href }: { label: string; value: string; href: string }) {11 return (12 <Link href={href} className="group min-w-0 py-3 pr-4 md:py-0">13 <p className="tnum display text-2xl text-ink md:text-[2rem]">{value}</p>14 <p className="mt-1 text-2xs uppercase tracking-[0.12em] text-ink-3 group-hover:text-ink-2">{label}</p>15 </Link>16 );17}1819/** Hero: statement + live counts (from /stats/home, never hardcoded) + CTAs, with the compact globe island beside/below. */20export function HomeHero({ home }: { home: HomePayload | null }) {21 const s = home?.stats;22 const counts: [string, string, string][] = [23 ['Active satellites', fmtInt(s?.active_satellites), routes.satellites('status=ACTIVE')],24 ['Objects on orbit', fmtInt(s?.objects_on_orbit), routes.satellites('on_orbit=true')],25 ['Launches catalogued', fmtInt(home?.launches.total), routes.launches()],26 ['Active operators', fmtInt(s?.active_operators), routes.operators()],27 ['Countries', fmtInt(s?.active_countries), routes.countries()],28 ];29 return (30 <section className="relative overflow-hidden border-b border-rule">31 <div className="grid-bg pointer-events-none absolute inset-0" aria-hidden />32 <Container wide className="relative">33 <div className="grid items-center gap-4 lg:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)] lg:gap-8">34 <div className="pb-4 pt-10 md:pt-14 lg:py-20">35 <p className="eyebrow flex items-center gap-2">36 <span className="dot pulse text-active" aria-hidden /> Satellite Index · live catalogue37 </p>38 <h1 className="display mt-4 max-w-[14ch] text-[2.5rem] text-ink sm:text-5xl md:text-6xl lg:text-[4.25rem]">39 The world’s orbital infrastructure, mapped and indexed.40 </h1>41 <p className="mt-5 max-w-xl text-[15px] leading-relaxed text-ink-2 md:text-lg">42 Every satellite, constellation, operator, launch, debris object and reentry in Earth orbit — one canonical, source-attributed43 database with live SGP4 positions, orbital history and a transparent methodology.44 </p>45 <div className="mt-7 flex flex-wrap items-center gap-3">46 <Link href={routes.explore()} className="inline-flex h-12 items-center justify-center gap-2 rounded-md bg-accent px-5 text-sm font-semibold text-accent-ink hover:brightness-110">47 Explore orbit <ArrowRight className="size-4" aria-hidden />48 </Link>49 <SearchButton />50 </div>51 <dl className="mt-9 grid grid-cols-2 gap-x-4 gap-y-2 border-y border-rule py-2 sm:grid-cols-3 md:mt-12 md:grid-cols-5 md:gap-6 md:border-0 md:py-0">52 {counts.map(([label, value, href]) => (53 <div key={label} className="[&:nth-child(5)]:col-span-2 sm:[&:nth-child(5)]:col-span-1 md:border-l md:border-rule md:pl-4 md:first:border-0 md:first:pl-0">54 <Count label={label} value={value} href={href} />55 </div>56 ))}57 </dl>58 {!home && <p className="mt-2 text-xs text-warn">Live statistics unavailable — the catalogue API did not respond.</p>}59 </div>60 <div className="relative -mx-4 h-[46vh] min-h-[300px] md:mx-0 md:h-[520px] lg:h-[680px]">61 <LazyGlobe variant="hero" />62 </div>63 </div>64 </Container>65 </section>66 );67}68