Something went wrong. Try again.
Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293// @ts-checkimport { writeFile, copyFile } from 'node:fs/promises';import { defineConfig } from 'astro/config';import tailwindcss from '@tailwindcss/vite';import sitemap from '@astrojs/sitemap';import { getScope, resolveScopeId } from './src/config/scopes.ts';
// One codebase, three real domains. SITE_SCOPE=nl|be|eu picks which one this build is; see// src/config/scopes.ts. Astro resolves `site` and `i18n.locales` at build time rather than per// request, which is exactly why three builds beat one deploy serving three hosts.const scopeId = resolveScopeId(process.env.SITE_SCOPE);const scope = getScope(scopeId);console.log(`[scope] building ${scopeId} -> ${scope.site} [${scope.locales.join(', ')}]`);
// https://astro.build/configexport default defineConfig({ site: scope.site,
// Base path. Default '/' (production apex atproto.nl + local dev). The Codeberg // preview serves at codeberg.page/<repo>/, so the deploy script builds with // SITE_BASE=/atprotonl-website/ for that subpath. At DNS cutover, deploy with SITE_BASE=/. base: process.env.SITE_BASE || '/',
// Keep author whitespace. Astro's default HTML compression (compressHTML: true) strips the // significant space between an inline element and text on the next source line, so a paragraph // link like `<a>Eurosky</a>\n runs …` rendered as "Euroskyruns". Disabling compression preserves // the newline, which the browser collapses to a single space -- the correct rendering. compressHTML: false,
// Fully static output: portable `dist/` that any static host or CDN can serve. // atproto OAuth + writes to a user's own PDS run client-side, so no server is needed. // If a genuine server route appears later, add the host's Astro adapter then. output: 'static',
// Locales come from the scope: .nl = en/nl, .be = en/nl/fr, .eu = en. The first is the // default and is served at /, the rest under /<locale>/. i18n: { locales: [...scope.locales], defaultLocale: scope.locales[0], routing: { prefixDefaultLocale: false }, },
// Redirects: .eu renamed /countries to /stats; national scopes keep /stats → /community-size. // Each scope builds separately, so the conditional keeps the right redirect per build. redirects: Object.fromEntries( scope.aggregate ? [ ['/countries', '/stats'], ...scope.locales.slice(1).map((l) => [`/${l}/countries`, `/${l}/stats`]), ] : [ ['/stats', '/community-size'], ...scope.locales.slice(1).map((l) => [`/${l}/stats`, `/${l}/community-size`]), ], ),
integrations: [ sitemap(), // Codeberg Pages maps a custom domain to the repo via a `.domains` file at the site root. // It is per-domain, so it MUST follow the scope -- a hardcoded public/.domains would make the // .be and .eu builds both claim atproto.nl. Emit it from scope.site here so every build path // (plain `npm run build` and the deploy script) gets the right host automatically. { name: 'emit-scope-build-files', hooks: { 'astro:build:done': async ({ dir }) => { const host = new URL(scope.site).host; // atproto.nl | atproto.be | atproto.eu await writeFile(new URL('.domains', dir), `${host}\n`); // Serve this scope's own icon on the bare /favicon.ico convention path. The <link> tags // point at /brand/favicon-<cc>.ico, but Google's favicon scraper and some feed readers // request /favicon.ico directly, ignoring the HTML -- so place the per-scope icon there. await copyFile( new URL(`./public/brand/favicon-${scope.cc}.ico`, import.meta.url), new URL('favicon.ico', dir), ); // The organizer guides used to live at /events/*.md here and were patched per scope to // swap in this build's community account. They now live in the EU-wide handbook at // docs.atproto.eu (one source for every country), so there is nothing to patch here. }, }, }, ],
vite: { plugins: [tailwindcss()], // Inline the scope for client-side code. Vite only exposes PUBLIC_-prefixed vars to the // browser, and plain process.env is not available there at all -- without this a .be build // would silently fall back to the default scope in the browser and write the wrong country // into members' records. define: { 'import.meta.env.PUBLIC_SITE_SCOPE': JSON.stringify(scopeId) }, },});