spb/tools-spboucher-ai
Public
1import type { Metadata } from "next";2import Link from "next/link";3import { categoryTree } from "@/lib/public/queries";4import { Breadcrumbs } from "@/components/breadcrumbs";5export const revalidate = 600;6export const metadata: Metadata = { title: "Categories", description: "Browse every tool category: AI, software development, infrastructure, Apple platforms, data, academic research, finance and productivity.", alternates: { canonical: "/categories" } };7export default async function Categories() {8 const tree = await categoryTree();9 return (10 <div className="mx-auto max-w-7xl px-4 py-8 sm:px-6">11 <Breadcrumbs items={[{ label: "Categories" }]} />12 <h1 className="display h1 mt-3">Categories</h1>13 <p className="mt-2 max-w-2xl text-fg-2">A two-level taxonomy. Tools may appear in several categories; the primary one defines the breadcrumb on its page. Counts include only published entries.</p>14 <div className="mt-8 space-y-10">15 {tree.map((c) => (16 <section key={c.slug} aria-labelledby={`c-${c.slug}`}>17 <div className="mb-3 flex items-baseline justify-between gap-3"><h2 id={`c-${c.slug}`} className="display h2"><Link href={`/categories/${c.slug}`} className="hover:text-accent">{c.name}</Link></h2><span className="text-sm text-fg-3">{c.count} tools</span></div>18 <p className="mb-4 max-w-3xl text-sm text-fg-2">{c.description}</p>19 <ul className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">20 {c.children.map((ch) => (21 <li key={ch.slug}><Link href={`/categories/${ch.slug}`} className="card flex items-start justify-between gap-3 p-3"><span><span className="block text-sm font-medium">{ch.name}</span><span className="mt-0.5 line-clamp-2 block text-xs text-fg-3">{ch.description}</span></span><span className="chip shrink-0">{ch.count}</span></Link></li>22 ))}23 </ul>24 </section>25 ))}26 </div>27 </div>28 );29}30