A static directory of mutual aid networks and grassroots groups, organized by city, state, and topic. Live at https://organize.directory.
The site is a static HTML build deployed to Cloudflare Pages. Content lives in JSON; pages are generated by scripts/build.js and committed to the repo.
data/
├── locations/ # one JSON file per city → cities/<slug>.html
├── states/ # one JSON file per state → states/<slug>.html
└── topics/ # one JSON file per topic → topics/<slug>.html
scripts/
├── build.js # JSON → HTML, sitemap, robots, _redirects, stats;
│ # content-hashes CSS/JS (?v=…) and normalizes the
│ # <head> of the hand-maintained static pages
└── ...
assets/
├── styles/system.css # Single source of truth for all styling (+ @font-face)
├── scripts/ # theme-toggle.js, city-page.js
└── fonts/ # Self-hosted Archivo + Archivo Black + JetBrains Mono (woff2)
js/ # title-search.js, analytics.js, newsletter-form.js
_headers # Cloudflare Pages CSP, caching, security headers
_redirects # Generated by build: bare-slug → /cities/<slug>.html
Fonts are self-hosted (latin subset) and declared via @font-face in
system.css — there is no Google Fonts request. CSS/JS are served immutable
for a year and cache-busted by a ?v=<contenthash> the build injects, so an
edited asset is re-fetched while unchanged ones stay cached.
Hand-maintained pages: index.html, location.html, topics.html, guides.html, contact.html, subscribe.html, thank-you.html, 404.html.
npm install
npm run build # regenerate cities/, states/, topics/, sitemap, _redirects, stats
npm run dev # wrangler pages dev — serves locally with Pages semantics
npm run generate-title-index # rebuild the search index (after adding/removing pages)There is no separate dev server — wrangler pages dev serves the static files plus _headers and _redirects.
- Open the relevant
data/locations/<city>.json(or create a new one — see existing files for the schema). - Add an entry under the matching section's
initiativesarray:{ "name": ..., "url": ..., "description": ... }. - Run
npm run build, thennpm run generate-title-indexif you added a new page. - Commit JSON + regenerated HTML.
Submissions are POSTed directly to Web3Forms from the browser using the access key embedded in contact.html. There's no server-side handler. A botcheck honeypot field filters bots.
Pushed to main → Cloudflare Pages auto-builds and deploys. The build command is npm run build; the output directory is the repo root.
ISC. See package.json.