Site Components
Components are organized by feature in subdirectories under src/components/. This page covers non-MDX components used by pages and layouts.
Layout Components
Directory: src/components/layout/
Header
Sticky navigation bar with mobile menu and full-site search.
No external props — navigation links are hardcoded in the component.
Alpine.js features:
- Search — Pagefind integration with 150ms debounce, keyboard navigation (arrows, Enter, Escape), and
Cmd/Ctrl+Kglobal hotkey - Mobile menu — Slide-out overlay with staggered link animations
- Scroll behavior — Hides on scroll down, shows on scroll up
Footer
Site-wide footer with navigation columns, social links, and legal info.
No external props — loads content from multiple page-text entries:
social— Social media icons with custom hover colorscontact-details— Email + multilineaddressfield, shared with the Contact page so both surfaces stay in syncnav-columns— Navigation columnsnav-links/footer-bottom— Copyright and legal links
BackToTopButton
Floating button that appears after scrolling 300px. Uses Alpine.js for scroll detection and smooth scroll back to top.
Post Catalog Components
Directory: src/components/posts-catalog/
These components work together with the Alpine.js grid filtering pattern in events.astro and projects.astro.
PostShowcase
| Prop | Type | Default | Description |
|---|---|---|---|
coverImage | ImageMetadata | — | Card background image |
imageAlt | string | — | Alt text |
date | string | — | Formatted date string |
title | string | — | Card title |
description | string | — | Card description |
href | string? | — | Link URL (renders <a> if set) |
isCompleted | boolean? | — | Show “Completed” badge |
isUpcoming | boolean? | — | Show “Upcoming” badge |
category | string? | — | Category label badge |
Fixed height card (320px) with image zoom on hover, glass-morphism badges, and accent glow border effect on desktop hover.
FilterMenu
| Prop | Type | Description |
|---|---|---|
filterGroups | FilterGroup[] | Array of { label, stateVariable, categories, categoryLabels } |
Dropdown panel with filter groups. Shows active filter count badge. Provides clearFilters() method.
SortMenu
| Prop | Type | Default | Description |
|---|---|---|---|
stateVariable | string? | 'sortOrder' | Alpine state variable to bind to |
Dropdown toggle between “Newest first” and “Oldest first” with animated direction icon.
CategoryFilter
| Prop | Type | Default | Description |
|---|---|---|---|
categories | string[] | — | Category values |
categoryLabels | Record<string, string> | — | Display labels |
stateVariable | string? | 'activeCategory' | Alpine state array to toggle |
Row of filter chip buttons that call toggleFilter() on the Alpine state.
Reusable Components
Directory: src/components/reusable/
PageHeroImage
| Prop | Type | Default | Description |
|---|---|---|---|
image | ImageMetadata | — | Background image |
alt | string | — | Alt text |
title | string | — | Title (bottom-left) |
subtitle | string? | — | Subtitle |
variant | 'dark' | 'light' | 'dark' | Gradient color |
loading | 'eager' | 'lazy' | 'eager' | Loading strategy |
Full viewport hero section (h-[50vh] lg:h-[60vh]) with gradient overlays for text readability. Title takes half width on desktop.
ImageGrid
| Prop | Type | Default | Description |
|---|---|---|---|
images | ImageWithAlt[] | — | Images with alt text + optional description (rendered as a gradient overlay) |
cols | 2-6 | 4 | Grid columns |
gap | 'sm' | 'md' | 'lg' | 'md' | Item spacing |
enableClickToEnlarge | boolean | true | Click-to-enlarge modal |
aspectRatio | 'square' | 'native' | 'square' | Layout mode |
Two modes: square uses CSS Grid with 1:1 aspect ratio, native uses CSS Columns for masonry layout. Mobile always shows 2 columns. First cols * 2 images use eager loading.
CollapsibleImageGrid
| Prop | Type | Default | Description |
|---|---|---|---|
images | ImageWithAlt[] | — | Images with alt text + optional description (rendered as a gradient overlay) |
cols | 2-6 | 4 | Grid columns |
gap | 'sm' | 'md' | 'lg' | 'md' | Item spacing |
previewRows | number | 1 | Visible rows when collapsed |
Wraps ImageGrid with a gradient overlay and expand/collapse button. Uses Alpine.js for height animation with scrollHeight measurement.
MediaAccordion
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Section title |
images | ImageMetadata[] | — | Images to display |
cols | 2-6 | 4 | Grid columns |
gap | 'sm' | 'md' | 'lg' | 'md' | Item spacing |
Smart wrapper: if all images fit in one row, renders a static header. Otherwise renders a clickable header with CollapsibleImageGrid.
CarouselArrow
| Prop | Type | Default | Description |
|---|---|---|---|
direction | 'prev' | 'next' | 'down' | — | Arrow direction |
onClick | string | — | Alpine click handler |
variant | 'flex' | 'absolute' | 'flex' | Positioning mode |
position | 'left' | 'right' | 'left' | Position for absolute variant |
inverted | boolean | false | White border for dark backgrounds |
Responsive SVG arrow button (w-10 h-10 sm:w-12 sm:h-12). Standard variant uses red accent; inverted uses white border with mix-blend-difference.
GradientDivider
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'dark' | 'light' | 'dark' | Color scheme |
Thin gradient line used as a visual separator.
CrosslinkBanner
| Prop | Type | Description |
|---|---|---|
text | string | Prompt text |
linkText | string | Link label |
href | string | Destination URL |
Subtle banner with text and arrow link, used below pagination to cross-link between events and projects pages.
Landing Components
Directory: src/components/landing/
SponsorTier
| Prop | Type | Description |
|---|---|---|
sponsors | SponsorData[] | Array of sponsor objects |
tier | SponsorTier | Tier key for size styling |
Each sponsor object: { name, logo (ImageMetadata), url?, tier, slug, bgColor? }.
Renders sponsor logos in a flex-wrap row with tier-proportional sizing. Each logo sits inside a white card container with soft shadow, rounded corners, and padding that scales with the tier (larger cards for higher tiers). The card background color defaults to #ffffff but can be overridden per sponsor via the bgColor frontmatter field to meet corporate identity requirements.
Used by both BecomeSponsor (landing page) and SponsorShowcase (dedicated sponsors page).
SponsorShowcase
| Prop | Type | Default | Description |
|---|---|---|---|
title | string? | — | Section heading |
subtitle | string? | — | Accent label above heading |
description | string? | — | Intro paragraph |
tiers | TierGroup[] | — | Tier groups with sponsors |
Light-background section with accordion-style tier groups (all open by default). Each tier header is a clickable button with height animation. Uses SponsorTier internally for logo display.
LandingHero
| Prop | Type | Default | Description |
|---|---|---|---|
autoScroll | boolean? | — | Auto-advance slides |
autoScrollInterval | number? | 8000 | Interval (ms) |
showArrows | boolean? | true | Show navigation arrows |
showDots | boolean? | false | Show dot indicators |
ctas | HeroCTAItem[]? | — | 1–3 CTA buttons |
tagline | string? | — | Text below BEARS logo |
Full viewport hero with video/image carousel background. Loads media from src/assets/hero/landingpage/. Videos autoplay muted. Touch swipe support for mobile.
The CTA grid (HeroCTA.astro) uses CSS-only hover effects — no client-side JS required.
Docs Components
Directory: src/components/docs/
DocsSidebar
Navigation sidebar for documentation pages. No external props — fetches docs via getDocsBySection().
- Collapsible sections (Guides, Dev Docs) and groups within sections
- localStorage persistence for expansion state
- Active page highlighting
- Desktop: sticky sidebar; Mobile: slide-out overlay
DocsToc
| Prop | Type | Description |
|---|---|---|
headings | Array<{depth, slug, text}> | Page heading hierarchy |
Table of contents sidebar (right column, XL+ screens only). Filters to depth 2–3 headings. Only renders if 2+ headings exist.