# PortalJS Catalog Template (dynamic routes)
A template variant for portals with **many datasets**. Instead of one page file per
dataset, the catalog is driven by a single manifest (`datasets.json`) and rendered by a
dynamic route (`pages/[owner]/[slug].tsx` + `getStaticPaths`). Adding a dataset is one
JSON entry plus a data file — no new page.
## The three surfaces
| Surface | Route | File | What it is |
|---|---|---|---|
| Home | `/` | `pages/index.tsx` | Landing page: hero + search CTA + suggested-query chips |
| Catalog / search | `/search` | `pages/search.tsx` | The dataset list with client-side full-text filtering |
| Dataset showcase | `/@ / ` | `pages/[owner]/[slug].tsx` | One dataset: metadata, data preview, download/API, views |
The home page's search box and chips navigate to `/search?q=…`; each search result links
to its showcase at `/@ / `.
## When to use this vs `portaljs-template`
| | `portaljs-template` | `portaljs-catalog` (this) |
|---|---|---|
| Dataset pages | one `.tsx` file per dataset | one dynamic `[owner]/[slug].tsx` for all |
| Registration | hardcoded array in `index.tsx` | `datasets.json` manifest |
| Best for | a handful of datasets | dozens to hundreds |
Both ship the same lightweight `components/Table.tsx`, Tailwind setup, and Next 14 config.
## Running
```bash
cd examples/portaljs-catalog
npm install
npm run dev
```
## Adding a dataset
1. Drop the file in `public/data/` (e.g. `public/data/my-data.csv`).
2. Append an entry to `datasets.json`:
```json
{
"slug": "my-data",
"namespace": "reference",
"name": "My Data",
"description": "One-line description.",
"file": "my-data.csv",
"format": "csv"
}
```
That's it. `getStaticPaths` picks up the new `(namespace, slug)` pair at build time and
`/@reference/my-data` renders automatically. CSV and TSV files are previewed in an
interactive ` `; other formats (`json`, `geojson`) show a download link.
The bundled sample files under `public/data/` are the small reference data that ships …