spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1import type { Metadata } from 'next';2import Link from 'next/link';3import { CompanyTable } from '@/components/company/company-table';4import { Pagination, withParams } from '@/components/ui/pagination';5import { Container, PageHeader, Unavailable } from '@/components/ui/section';6import { api, safe } from '@/lib/api';7import { cn } from '@/lib/cn';8import { fmtInt } from '@/lib/format';9import { flat, int, str, type SP } from '@/lib/params';1011export const metadata: Metadata = { title: 'Companies', description: 'Directory of monitored companies with activity, hiring momentum, AI adoption, sensors and event counts.' };12export const revalidate = 120;1314const SORTS = [15 ['activity', 'Activity'],16 ['events', 'Events'],17 ['hiring', 'Hiring'],18 ['recent', 'Most recent event'],19 ['importance', 'Importance'],20 ['name', 'Name'],21] as const;2223export default async function CompaniesPage({ searchParams }: { searchParams: Promise<SP> }) {24 const sp = await searchParams;25 const cur = flat(sp);26 const page = int(sp.page, 1);27 const query = { q: str(sp.q), country: str(sp.country), industry: str(sp.industry), tier: str(sp.tier), public: str(sp.public), has_events: str(sp.has_events), sort: str(sp.sort) ?? 'activity', page, per_page: 50, sparkline: 1 };28 const [data, countries, industries] = await Promise.all([safe(api.companies(query)), safe(api.countries()), safe(api.industries())]);29 const href = (patch: Record<string, string | number | undefined | null>) => withParams('/companies', cur, patch);30 return (31 <Container wide>32 <PageHeader eyebrow="Directory" title="Companies" lede={data ? `${fmtInt(data.total)} monitored companies. Each row links to the profile with its sensors, timeline and historical page versions.` : 'Monitored companies.'} />33 <form method="get" action="/companies" className="mb-4 grid gap-2 sm:grid-cols-[minmax(0,2fr)_repeat(3,minmax(0,1fr))_auto]">34 <input type="search" name="q" defaultValue={str(sp.q)} placeholder="Search name, domain, alias…" className="field" aria-label="Search companies" />35 <select name="country" defaultValue={str(sp.country) ?? ''} className="field" aria-label="Country">36 <option value="">All countries</option>37 {(countries?.items ?? []).map((c) => (38 <option key={c.code} value={c.code}>39 {c.name} ({c.companies})40 </option>41 ))}42 </select>43 <select name="industry" defaultValue={str(sp.industry) ?? ''} className="field" aria-label="Industry">44 <option value="">All industries</option>45 {(industries?.items ?? []).map((i) => (46 <option key={i.slug} value={i.slug}>47 {i.name} ({i.companies})48 </option>49 ))}50 </select>51 <select name="tier" defaultValue={str(sp.tier) ?? ''} className="field" aria-label="Tier">52 <option value="">All tiers</option>53 {[1, 2, 3, 4].map((t) => (54 <option key={t} value={t}>55 Tier {t}56 </option>57 ))}58 </select>59 <input type="hidden" name="sort" value={query.sort} />60 <button type="submit" className="btn btn-primary">61 Filter62 </button>63 </form>64 <div className="mb-3 flex flex-wrap items-center gap-2 text-xs">65 <span className="text-ink-3">Sort</span>66 {SORTS.map(([id, label]) => (67 <Link key={id} href={href({ sort: id === 'activity' ? undefined : id })} className="chip-btn" data-on={query.sort === id}>68 {label}69 </Link>70 ))}71 <Link href={href({ public: str(sp.public) === '1' ? undefined : '1' })} className={cn('chip-btn ml-2')} data-on={str(sp.public) === '1'}>72 Public companies73 </Link>74 <Link href={href({ has_events: str(sp.has_events) === '1' ? undefined : '1' })} className="chip-btn" data-on={str(sp.has_events) === '1'}>75 With events76 </Link>77 {(str(sp.q) || str(sp.country) || str(sp.industry) || str(sp.tier) || str(sp.public) || str(sp.has_events)) && (78 <Link href="/companies" className="text-ink-3 underline-offset-2 hover:underline">79 Clear80 </Link>81 )}82 </div>83 {!data ? (84 <Unavailable what="The directory" />85 ) : (86 <>87 <CompanyTable items={data.items} />88 <Pagination total={data.total} page={data.page} pages={data.pages} perPage={data.per_page} makeHref={(p) => href({ page: p > 1 ? p : undefined })} className="mt-4" />89 </>90 )}91 </Container>92 );93}94