← Back to site

Architecture

The BEARS website is built with Astro.js 5.x, Tailwind CSS v4, and Alpine.js.

Technology Stack

  • Astro.js 5.x — static site generation with file-based routing
  • Tailwind CSS v4 — utility-first styling via Vite plugin
  • Alpine.js — lightweight client-side interactivity
  • TypeScript — strict mode enabled
  • MDX — Markdown with component support for rich content pages

Project Structure

src/
├── pages/           # File-based routing (English, default locale)
│   └── de/          # German locale wrappers
├── layouts/         # Page layouts (BaseLayout, PostLayout, DocsLayout)
├── components/      # UI components organized by feature
├── content/         # Content collections (events, projects, docs, etc.)
│                    # Localized collections use en/ and de/ subfolders
├── utils/           # Shared utilities (contentQueries, i18n, imageLoader, etc.)
├── styles/          # Global CSS and Tailwind theme
├── assets/          # Images and static assets (processed by Astro)
└── types/           # Shared TypeScript types

Content Collections

Content is managed through Astro’s content collections, defined in src/content/config.ts. Each collection has a Zod schema that validates frontmatter fields.

Localized collections (events, projects, page-text) use en/ and de/ subfolders. Language-neutral collections (sponsors, instagram, hero-slides, docs, people, testimonials, social-platforms) stay flat — people carries both role translations inline (roleEn/roleDe), and testimonials carries both quote translations inline (quoteEn/quoteDe).

A second class of collections — landing-section-visibility, about-section-visibility, sponsors-section-visibility, contact-section-visibility, media-section-visibility — store per-page section-toggle YAML (settings.yaml) rather than rendered content. Pages read them to skip entire sections at render time, and editors flip the toggles through the <page> — segments singletons in Keystatic.

Internationalization (i18n)

The site supports English (default, no URL prefix) and German (/de/ prefix). Configured via Astro’s built-in i18n in astro.config.mjs.

Key utilities in src/utils/i18n.ts:

  • getLocale(url) — derives locale from URL pathname
  • localizeUrl(path, locale) — adds/removes /de/ prefix
  • getCategoryLabel(key, locale) — locale-aware category translations
  • getHreflangUrls(pathname, origin) — generates SEO hreflang URLs
  • catalogUiStrings — locale-aware UI labels for events/projects pages (filter, sort, status labels)
  • mediaUiStrings — locale-aware UI labels for the media page

German pages in src/pages/de/ are thin wrappers that import and re-render the root page component. The root page detects its locale via getLocale(Astro.url) and passes it to all components and content queries.

Routing

Astro uses file-based routing. Files in src/pages/ map directly to URLs:

  • src/pages/index.astro/
  • src/pages/events.astro/events
  • src/pages/events/[slug].astro/events/:slug
  • src/pages/de/events.astro/de/events (German wrapper)
  • src/pages/de/events/[slug].astro/de/events/:slug