Developer Page Specifications
Listing Pages
Landing + 8 scoped listings. CalendarLandingPage rails + EventListingPage with filter rail.
Complete
Routes: /:lang/calendar (landing — rails-driven, not query-driven), /:lang/calendar/events (full listing, all filters), /:lang/calendar/events/countries/{countrySlug}, /:lang/calendar/events/categories/{categorySlug}, /:lang/calendar/events/audiences/{audienceSlug}, /:lang/calendar/events/stages/{stageSlug}, /:lang/calendar/this-week, /:lang/calendar/closing-soon. 8 routes total, 2 components: CalendarLandingPage (rails) + EventListingPage (filter+grid, reused via route.data.scope).
Landing page sections (/:lang/calendar)
- A · Hero (eyebrow + H1 + 1-line lede + 2 CTAs: "Submit an event" + "View all events")
- B · This-week rail (horizontal scroll, events within ±7 days of NOW)
- C · Closing-soon rail (deadlines within 7 days, warning-tinted deadline chips)
- D · By-country grid (16 flag tiles, each linking to /calendar/events/countries/{slug} with live event count)
- E · By-category grid (17 category tiles)
- F · Spotlight (at most 1 editorialPriority=spotlight event, full-width banner)
- G · Submit-an-event CTA block (one-line pitch → routerLink to /:lang/calendar/submit)
- H · Footer
Listing page sections (/:lang/calendar/events*)
- A · Hero (scoped title — "All events" / "Events in Egypt" / "Demo days" — + result count + active filter chips)
- B · Filter rail (left desktop sticky, bottom-drawer mobile): country / category / audience / stage / status / mode (physical/online/hybrid)
- C · Grid (3-col desktop, 2-col tablet, 1-col mobile)
- D · Counter at bottom ("Showing X of Y events")
- E · No pagination — infinite scroll, 24 cards/batch
Event card fields (canonical <app-event-card>)
- date chip
- NEVER-collapse element. Dominant in card hierarchy. Format: D-{N} for upcoming, "LIVE NOW" for status=live, "+{N}d" for completed, formatted full date for ≥30 days out.
- flag + country chip
- Source: Event.CountryCode + Country.NameLang. Display: flag emoji + abbreviated country name when card narrow.
- category icon + label
- Source: Event.Category. Lookup icon from CATEGORY_ICONS (e.g. demo-day → presentation icon, hackathon → terminal icon).
- status badge
- Computed from times. Tints: upcoming=neutral / open=primary / closing-soon=warning / live=accent pulse / completed=muted / postponed=amber / cancelled=destructive.
- title + organizer
- Source: EventLang.Title + Event.OrganizerName. Title H3, organizer t-meta below.
- mode chip
- Source: Event.Mode (physical | online | hybrid). Small chip in card foot.
- CTAs
- Primary: routerLink to /:lang/calendar/events/{slug}. Secondary (when registrationUrl OR applyUrl): outbound to that URL with target=_blank.
