SPB Git
6.6 KB · 96 lines tsx
1import Link from "next/link";2import { homeData } from "@/lib/public/queries";3import { SearchBox } from "@/components/search-box";4import { ToolCard } from "@/components/tool-card";5import { fmtDate } from "@/lib/utils";6import { ArrowRight, Sparkles, ShieldCheck, Layers, BookMarked } from "lucide-react";78export const revalidate = 300;910const PATHS = [11  { href: "/tools?exec=local&category=ai", title: "Run AI locally", text: "Inference engines and model tooling that work on Apple Silicon and your own servers." },12  { href: "/tools?category=research", title: "Write and publish research", text: "Discovery, references, LaTeX, reproducible documents and dissemination." },13  { href: "/tools?category=market-data-apis&category=sec-filings&category=hf-finance-research", title: "Financial data for research", text: "Market data, fundamentals, filings and the engines that process them." },14  { href: "/tools?source=open-source&selfhost=1", title: "Self-host everything", text: "Open-source infrastructure you can run on your own hardware." },15];1617export default async function Home() {18  const { stats, featured, recent, tree, collections } = await homeData().catch(() => ({ stats: { tools: 0, deep: 0, categories: 0, vendors: 0, collections: 0, lastVerified: null }, featured: [], recent: [], tree: [], collections: [] }));19  return (20    <>21      <section className="relative overflow-hidden border-b border-line">22        <div className="grain pointer-events-none absolute inset-0 opacity-50 [mask-image:radial-gradient(60%_60%_at_50%_0%,black,transparent)]" aria-hidden />23        <div className="relative mx-auto max-w-7xl px-4 pb-16 pt-14 sm:px-6 sm:pt-20">24          <p className="eyebrow rise">Tool Atlas · curated, cited, verified</p>25          <h1 className="display h-display rise rise-1 mt-3 max-w-4xl">An encyclopedia of the software, AI systems and research tools that matter.</h1>26          <p className="rise rise-2 mt-5 max-w-2xl text-lg text-fg-2">Every entry is written from primary sources, states its license and pricing model without guesswork, lists real limitations, and shows when its links were last checked.</p>27          <div className="rise rise-3 mt-8"><SearchBox size="lg" /></div>28          <dl className="rise rise-3 mt-8 grid max-w-3xl grid-cols-2 gap-4 sm:grid-cols-4">29            {[["Tools", stats.tools], ["In-depth entries", stats.deep], ["Categories", stats.categories], ["Collections", stats.collections]].map(([k, v]) => (30              <div key={String(k)}><dt className="text-xs uppercase tracking-wider text-fg-3">{k}</dt><dd className="display text-3xl">{v as number}</dd></div>31            ))}32          </dl>33        </div>34      </section>3536      <section className="mx-auto max-w-7xl px-4 py-12 sm:px-6">37        <div className="mb-5 flex items-end justify-between gap-4">38          <div><p className="eyebrow">Browse</p><h2 className="display h2 mt-1">By discipline</h2></div>39          <Link href="/categories" className="inline-flex items-center gap-1 text-sm text-accent hover:underline">All categories <ArrowRight className="h-4 w-4" aria-hidden /></Link>40        </div>41        <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">42          {tree.map((c) => (43            <Link key={c.slug} href={`/categories/${c.slug}`} className="card group p-4">44              <div className="flex items-center justify-between"><h3 className="font-semibold tracking-tight">{c.name}</h3><span className="chip">{c.count}</span></div>45              <p className="mt-1.5 line-clamp-2 text-sm text-fg-2">{c.description}</p>46              <p className="mt-3 line-clamp-1 text-xs text-fg-3">{c.children.slice(0, 4).map((x) => x.name).join(" · ")}</p>47            </Link>48          ))}49        </div>50      </section>5152      {featured.length > 0 && (53        <section className="mx-auto max-w-7xl px-4 py-8 sm:px-6">54          <div className="mb-5 flex items-end justify-between gap-4">55            <div><p className="eyebrow inline-flex items-center gap-1"><Sparkles className="h-3.5 w-3.5" aria-hidden /> Featured</p><h2 className="display h2 mt-1">Editor&apos;s selection</h2></div>56            <Link href="/tools?depth=deep" className="inline-flex items-center gap-1 text-sm text-accent hover:underline">All in-depth entries <ArrowRight className="h-4 w-4" aria-hidden /></Link>57          </div>58          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">{featured.map((t) => <ToolCard key={t.id} t={t} />)}</div>59        </section>60      )}6162      <section className="mx-auto max-w-7xl px-4 py-8 sm:px-6">63        <div className="mb-5"><p className="eyebrow inline-flex items-center gap-1"><Layers className="h-3.5 w-3.5" aria-hidden /> Discovery paths</p><h2 className="display h2 mt-1">Start from a goal</h2></div>64        <div className="grid gap-3 md:grid-cols-2 lg:grid-cols-4">65          {PATHS.map((p) => <Link key={p.href} href={p.href} className="card p-4"><h3 className="font-semibold">{p.title}</h3><p className="mt-1 text-sm text-fg-2">{p.text}</p></Link>)}66        </div>67      </section>6869      {collections.length > 0 && (70        <section className="mx-auto max-w-7xl px-4 py-8 sm:px-6">71          <div className="mb-5 flex items-end justify-between gap-4">72            <div><p className="eyebrow inline-flex items-center gap-1"><BookMarked className="h-3.5 w-3.5" aria-hidden /> Collections</p><h2 className="display h2 mt-1">Curated stacks</h2></div>73            <Link href="/collections" className="inline-flex items-center gap-1 text-sm text-accent hover:underline">All collections <ArrowRight className="h-4 w-4" aria-hidden /></Link>74          </div>75          <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">76            {collections.slice(0, 6).map((c) => (77              <Link key={c.slug} href={`/collections/${c.slug}`} className="card p-5">78                <h3 className="display text-xl">{c.title}</h3>79                <p className="mt-2 line-clamp-2 text-sm text-fg-2">{c.description}</p>80                <p className="mt-3 text-xs text-fg-3">{c.count} tools · {c.preview.map((p) => p.name).join(", ")}</p>81              </Link>82            ))}83          </div>84        </section>85      )}8687      {recent.length > 0 && (88        <section className="mx-auto max-w-7xl px-4 py-8 pb-4 sm:px-6">89          <div className="mb-5"><p className="eyebrow inline-flex items-center gap-1"><ShieldCheck className="h-3.5 w-3.5" aria-hidden /> Recently verified</p><h2 className="display h2 mt-1">Links checked {stats.lastVerified ? fmtDate(stats.lastVerified) : "soon"}</h2></div>90          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">{recent.map((t) => <ToolCard key={t.id} t={t} />)}</div>91        </section>92      )}93    </>94  );95}96
Files · main
Menu

Theme