● Zion Boggan
repos/Docket/app/categories/page.tsx
zionboggan.com ↗
85 lines · tsx
History for this file →
1
import type { Metadata } from "next";
2
import Link from "next/link";
3
import { Card, PageHeader } from "@/components/ui";
4
import { getCategories } from "@/lib/feed";
5
 
6
export const revalidate = 300;
7
 
8
export const metadata: Metadata = {
9
  title: "Topics",
10
  description:
11
    "Browse the record by topic -bills and awards grouped by policy area. Counts only, no editorial weighting.",
12
};
13
 
14
export default function CategoriesPage() {
15
  const cats = getCategories().sort(
16
    (a, b) => b.total - a.total || a.label.localeCompare(b.label)
17
  );
18
 
19
  const withItems = cats.filter((c) => c.total > 0);
20
  const empty = cats.filter((c) => c.total === 0);
21
 
22
  return (
23
    <div className="mx-auto w-full max-w-register px-4 py-10 sm:px-6">
24
      <Link
25
        href="/register"
26
        className="focus-ring tap label mb-6 gap-1 text-ash hover:text-paper"
27
      >
28
        ← Register
29
      </Link>
30
 
31
      <PageHeader
32
        eyebrow="Topics · browse the record"
33
        title="By policy area"
34
        lead="Every bill is tagged with one policy area; federal awards carry the same tags. Pick a topic to read the bills filed under it. Counts reflect the record only -no ranking by importance."
35
      />
36
 
37
      <div className="mt-8">
38
        <p className="label mb-3">{withItems.length} topics on record</p>
39
        <ul className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
40
          {withItems.map((c) => (
41
            <li key={c.slug}>
42
              <Link
43
                href={`/bills?policyArea=${encodeURIComponent(c.label)}`}
44
                className="focus-ring block rounded-[3px] border border-line bg-surface p-4 transition-colors hover:bg-graphite"
45
              >
46
                <div className="flex items-start justify-between gap-3">
47
                  <span className="font-mono text-[13px] text-paper">
48
                    {c.label}
49
                  </span>
50
                  <span className="label shrink-0 text-ash-2">{c.total}</span>
51
                </div>
52
                <p className="label mt-2 text-ash-2">
53
                  {c.billCount} bill{c.billCount === 1 ? "" : "s"}
54
                  {c.awardCount > 0 ? ` · ${c.awardCount} award${c.awardCount === 1 ? "" : "s"}` : ""}
55
                </p>
56
              </Link>
57
            </li>
58
          ))}
59
        </ul>
60
      </div>
61
 
62
      {empty.length > 0 ? (
63
        <div className="mt-10">
64
          <p className="label mb-3">No record yet</p>
65
          <Card className="p-5">
66
            <p className="font-mono text-[12px] leading-relaxed text-ash-2">
67
              {empty.map((c) => c.label).join(" · ")}
68
            </p>
69
            <p className="label mt-3 text-ash-2">
70
              These topics have no bills or awards on record. They appear here so
71
              the list stays complete rather than hiding the gap.
72
            </p>
73
          </Card>
74
        </div>
75
      ) : null}
76
 
77
      <div className="mt-12 border-t border-line pt-6">
78
        <p className="label text-ash-2">
79
          Policy areas come from congress.gov bill metadata. Awards are tagged
80
          from USAspending.gov. No topic is weighted over another by coverage.
81
        </p>
82
      </div>
83
    </div>
84
  );
85
}