Skip to content

overhaul: event landing pattern (/openhouse, /programs/frc/kickoff) - #24

Open
CS-5 wants to merge 1 commit into
claude/phase-7-implementation-7jspr3from
overhaul/08-events
Open

overhaul: event landing pattern (/openhouse, /programs/frc/kickoff)#24
CS-5 wants to merge 1 commit into
claude/phase-7-implementation-7jspr3from
overhaul/08-events

Conversation

@CS-5

@CS-5 CS-5 commented Aug 31, 2026

Copy link
Copy Markdown
Member

Phase 08 of the overhaul stack (plan/08-events.md), stacked on the Phase 07 layer.

What this does

/openhouse was a fork of the homepage and /programs/frc/kickoff a fork of the FRC page — 777 lines of JSX between them, with the dates, the FAQ array and KICKOFF_CONFIG inlined. Both are now thin routes rendering entries from the events collection through one EventLayout (D17). Next season is an edit to one markdown file; retiring a season is hidden: true.

Changes

  • src/layouts/EventLayout.astro — hero (the entry's photo, or a fallback keyed to its program), the date/location band, the body markdown, the season media links, the referenced FAQ, and the closing banner. Themed by the entry's program (sc2 keeps the default look, kickoff renders Hazard Green). Emits Event and FAQPage JSON-LD, plus breadcrumbs on nested routes.
  • src/components/ui/Countdown.astro — the absolute date is always in the HTML, so an agent or a reader without JavaScript gets the real answer; ~25 lines of script upgrade it to a live countdown and correct the state the static build froze. All three states are markup, one shown. An event with no end never reads as passed — nothing in such an entry says when it is over.
  • src/components/ui/FaqList.astrofaq entries as native <details> disclosures.
  • src/lib/jsonld.tsevent() and faqPage() builders.
  • src/lib/events.tsgetVisibleEvents() / getVisibleEvent(), the one place hidden is read: the routes redirect through it, and plan/10's sitemap filter will use the same list.
  • src/pages/openhouse.astro, src/pages/programs/frc/kickoff.astro — ~15 lines each, no copy.
  • knip.jsonc — the src/lib/event-date.ts entry is gone; Countdown is its real consumer, which is the seam this phase was required to close.
  • docs/content.md — updating an event for a new season, hiding one, and creating a new one (with the route file it still needs).

Decisions worth a look

  • heroImageAlt added to the events schema (docs/adr/0004). The layout had no honest alt for a hero photo. Optional, but supplying heroImage without it fails the build — the mechanism Seo.astro already uses for ogImage/ogImageAlt.
  • Hidden events redirect via Astro.redirect, which in a static build emits a meta-refresh page carrying noindex and a canonical to the parent. Chosen over a _redirects line so the rule lives beside the entry it reads, rather than in a second file to remember when the flag flips. The sitemap still lists a hidden event's URL; that filter is plan/10's, and getVisibleEvents() is in place for it.
  • Two dates written in prose are gone, per the rule docs/content.md already states: the open house's hero sentence (the countdown renders it from start/end) and kickoff's **Kickoff - January 10.** timeline entry. Kickoff also gained the end its own meeting schedule states.
  • @typescript-eslint/no-misused-promises is off for .astro. A return in frontmatter has no enclosing function node in astro-eslint-parser's AST and the rule asserts one exists, so it crashes rather than reporting — the same class of parser gap as the no-unsafe-return entry beside it.

Copy that did not come across

From legacy /openhouse: the two program cards (the homepage fork D17 exists to kill — /programs and the homepage carry them) and the embedded Google My Maps iframe with its parking prose, which the DIRECTIONS row links to instead. From legacy kickoff: the modal holding the meeting schedule (body copy now) and the two map-backed panels, whose content is the info card and the closing banner. The teaser and hint links are present.

Verification

pnpm check && pnpm build green. Both routes driven in Chromium at 390px and 1440px against the production preview: zero axe-core violations over WCAG 2.2 AA plus best-practice, no console or page errors, no horizontal overflow, every image with alt and explicit dimensions, clean heading outline. The countdown's three states were each exercised — from a build for the static path, and against a faked clock for the script's transitions on a page whose HTML was built in the passed state. Flipping hidden on and off was verified by building both ways.

The Google Rich Results test needs a public URL, so it runs on the preview deploy; the emitted Event and FAQPage objects were checked against their schema.org shapes offline.


Generated by Claude Code

…koff

Both pages were forks — /openhouse of the homepage, /programs/frc/kickoff of
the FRC page, 777 lines of JSX between them with the dates, the FAQ, and the
kickoff config inlined. They are now two ~15-line routes rendering `events`
entries through one EventLayout, so next season is an edit to one markdown
file and retiring a season is `hidden: true`.

- `EventLayout` renders the hero (entry photo or a program fallback), the
  date and location band, the body markdown, the season media links, the
  referenced FAQ, and the closing banner, themed by the entry's `program`.
- `ui/Countdown` always ships the absolute date; ~25 lines of script upgrade
  it to a live countdown and correct the state a static build froze. An event
  with no `end` never reads as passed.
- `ui/FaqList` renders `faq` entries as native disclosures.
- `lib/jsonld` gains `event()` and `faqPage()`; `lib/events` gains the
  `getVisibleEvents()`/`getVisibleEvent()` pair that the routes and plan/10's
  sitemap filter both read `hidden` through.
- `events` gains `heroImageAlt` (docs/adr/0004), and kickoff gains the `end`
  its own meeting schedule states.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GSWG5JxxUEXX3NYKeLwWzf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants