Add a reusable event calendar and put it on the front page
EventCalendar shows events on a month grid or as a list of the month. Multi-day events are lane-packed bars that break at week edges, series events appear on every meeting with their time, and clicking a day lists everything on it. Phones get the list. Visitors can narrow by scope, type, online only and search, all starting at "all"; a page can pin section, host or type through props, which hides that control. Migration 019 rebuilds front_page_sections to allow a 'calendar' band and slots it in after the retreats carousel, so it can be reordered, retitled or hidden from the Front page editor. useEvents drops its empty fallback so a failed request surfaces as an error rather than an empty list, and returns the scope list alongside the events for the calendar's scope filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
641ab167b0
commit
2e125b4629
10 changed files with 947 additions and 8 deletions
|
|
@ -171,6 +171,39 @@ export function upcomingOccurrences(
|
|||
return out
|
||||
}
|
||||
|
||||
/** Every meeting between two dates, inclusive, in order. For a
|
||||
* calendar page: `from` and `to` are the visible range. */
|
||||
export function occurrencesBetween(
|
||||
series: EventSeries | null | undefined,
|
||||
startsOn: string | null | undefined,
|
||||
endsOn: string | null | undefined,
|
||||
from: string,
|
||||
to: string,
|
||||
): string[] {
|
||||
if (!series) return []
|
||||
const out: string[] = []
|
||||
for (const date of occurrences(series, startsOn, endsOn)) {
|
||||
if (date > to) break
|
||||
if (date >= from) out.push(date)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/** The first meeting on or after `from`, or null if the series has
|
||||
* ended by then. */
|
||||
export function firstOccurrenceFrom(
|
||||
series: EventSeries | null | undefined,
|
||||
startsOn: string | null | undefined,
|
||||
endsOn: string | null | undefined,
|
||||
from: string,
|
||||
): string | null {
|
||||
if (!series) return null
|
||||
for (const date of occurrences(series, startsOn, endsOn)) {
|
||||
if (date >= from) return date
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/* ── Words ───────────────────────────────────────────────────── */
|
||||
|
||||
const ORDINALS = ['', '1st', '2nd', '3rd', '4th', 'last']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue