Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
TypeScript 35%
Astro 28%
Python 20%
JavaScript 7%
CSS 5%
Shell 3%
MDX 2%
HTML <1%
<1%

README.md

atproto.<cc> — community websites #

One codebase, several country websites for the AT Protocol community in Europe. Each country is its own standalone site built from this same repo, selected at build time with SITE_SCOPE:

SITE_SCOPE Site Accent Languages
nl (default) atproto.nl orange English, Dutch
be atproto.be yellow English, Dutch, French
no atproto.no purple English (Norwegian pending)
eu atproto.eu blue English (the aggregate/directory)

There are no redirects between the sites and each is complete on its own. .eu is the aggregate: all-Europe stats plus a directory of country and city communities.

Run your country's site locally #

Prereqs: Node ≥ 22.12 and npm.

git clone tangled.org:did:plc:aqrkn66k2alnwxfrhstp3unq/website atproto-website
cd atproto-website
npm install

SITE_SCOPE=be npm run dev      # runs the Belgian site at http://localhost:4321
# SITE_SCOPE=no npm run dev     # the Norwegian site
# npm run dev                   # no SITE_SCOPE = the Dutch site (the default)

Build a single country's static site into dist/:

SITE_SCOPE=no npm run build

How a country is configured #

Everything specific to a country lives in src/config/scopes.ts — one entry per site:

be: {
  site: 'https://atproto.be',
  countries: ['be'],          // whose members/events/tools/builders this site shows
  locales: ['en', 'nl', 'fr'],// first is the default; only add a locale once its strings exist
  cc: 'be',                   // wordmark //atproto.be, favicon, map highlight
  accent: 'yellow',           // one of the Gruvbox packs in src/styles/country-packs.css
  cities: { Brussel: [4.35, 50.85], /* ... */ }, // dots on the map (lon, lat)
  maintainer: null,           // a handle, or null -> the "caretaker, get in touch" note
  endonyms: { en: 'English', fr: 'Français', nl: 'Nederlands' }, // header language switcher
  relatedLangs: ['nl', 'fr'], // /builders affinity section
},

To stand up or customize a country you typically touch:

  1. src/config/scopes.ts — the entry above.
  2. Copy — src/i18n/ui.ts. Shared strings use {siteName} / {inCountry} tokens and work everywhere. Genuinely per-country strings (the hero welcome, the about intro) go in the uiByScope override map. A language must have complete strings before it goes in locales — shipping a locale with missing strings puts English text on that language's URLs.
  3. Assets — public/brand/favicon-<cc>.svg and avatar-<cc>.svg, plus an accent pack in src/styles/country-packs.css (Gruvbox hues only, one per country).

Rules that matter #

  • Language is not nationality. The "(Belgian or otherwise)" welcome means nationals and the many foreigners who build here — never a language. Don't write "Flemish"/"Walloon"; the languages are Dutch and French.
  • One accent per view. A pack re-points the accent role and nothing else.
  • Every page carries the disclaimer: "atproto.<cc> is an independent community project. It is not affiliated with, sponsored or endorsed by Bluesky Social PBC."
  • Spelling: "the AT Protocol", "atproto". Never "AtProto"/"at-proto". No Bluesky/AT Protocol logos.

Tests #

npm test            # unit tests (vitest)
npm run test:a11y   # build + Playwright accessibility checks

Contributing & home base #

Home base is Tangled at tangled.org/atcommons.eu/website — open to pull requests. Push there (a Codeberg mirror handles delivery; maintainers rarely deploy themselves). See AGENTS.md for the coding conventions.