335 lines
12 KiB
Text
335 lines
12 KiB
Text
---
|
|
import type { Event, EventPageEntry } from "../data/events";
|
|
import {
|
|
getEventBasePath,
|
|
getEventOverviewSectionIndex,
|
|
getEventPageEntries,
|
|
} from "../data/events";
|
|
import EventSchedule from "./EventSchedule.astro";
|
|
import { getEventNavItems } from "../data/eventNav";
|
|
import SiteLayout from "../layouts/SiteLayout.astro";
|
|
|
|
type Props = {
|
|
event: Event;
|
|
pageEntry?: EventPageEntry;
|
|
};
|
|
|
|
const { event } = Astro.props;
|
|
const eventPages = getEventPageEntries(event);
|
|
const pageEntry = Astro.props.pageEntry ?? eventPages[0];
|
|
const theme = event.theme ?? "default";
|
|
const basePath = getEventBasePath(event);
|
|
const overviewSectionIndex = getEventOverviewSectionIndex(event);
|
|
const overviewSection =
|
|
typeof overviewSectionIndex === "number" ? event.sections?.[overviewSectionIndex] : undefined;
|
|
const overviewSections = overviewSection ? [overviewSection] : [];
|
|
const currentSection =
|
|
pageEntry.type === "section" && typeof pageEntry.sectionIndex === "number"
|
|
? event.sections?.[pageEntry.sectionIndex]
|
|
: undefined;
|
|
const schedulePage = eventPages.find((page) => page.type === "schedule");
|
|
const eventTitle = event.shortTitle ?? event.title;
|
|
const isOverview = pageEntry.type === "overview";
|
|
const pageTitle = isOverview ? eventTitle : `${pageEntry.label} - ${eventTitle}`;
|
|
const pageContext = `${event.kind} / ${event.year}`;
|
|
const navItems = getEventNavItems(event);
|
|
const showOverviewContent = event.showOverviewContent !== false;
|
|
const showScheduleBlock = Boolean(
|
|
event.schedule && (pageEntry.type === "schedule" || (isOverview && event.showScheduleOnOverview)),
|
|
);
|
|
const shouldRenderBody = !isOverview || showOverviewContent || showScheduleBlock;
|
|
const shouldUseWideBody = Boolean(isOverview && event.showScheduleOnOverview);
|
|
const scheduleAsTabs =
|
|
showScheduleBlock && event.scheduleDisplay === "tabs" && (event.schedule?.length ?? 0) > 1;
|
|
const showHeroScheduleLink = Boolean(
|
|
schedulePage && !event.showScheduleOnOverview && event.showScheduleLinkInHero !== false,
|
|
);
|
|
const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
|
|
|
---
|
|
|
|
<SiteLayout
|
|
title={pageTitle}
|
|
description={event.summary}
|
|
theme={theme}
|
|
brandHref={basePath}
|
|
brandTitle={eventTitle}
|
|
brandSubtitle="Event home"
|
|
navItems={navItems}
|
|
accessPassword={event.accessPassword}
|
|
>
|
|
{isOverview ? (
|
|
<section class:list={["event-hero", `event-hero--${theme}`, event.slug === "ncert" && "event-hero--narrow"]}>
|
|
<div class="event-hero__content">
|
|
<p class="eyebrow">{event.kind} / {event.year}</p>
|
|
<h1>{event.title}</h1>
|
|
{event.subtitle && <p class="lede">{event.subtitle}</p>}
|
|
<p>{event.summary}</p>
|
|
{hasHeroActions && (
|
|
<div class="hero-actions">
|
|
{event.sourceUrl && <a class="button button--secondary" href={event.sourceUrl}>Event website</a>}
|
|
{showHeroScheduleLink && schedulePage && <a class="button" href={schedulePage.href}>Schedule</a>}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<aside class="event-hero__panel" aria-label="Event facts">
|
|
{event.image ? (
|
|
<img src={event.image.src} alt={event.image.alt} loading="eager" />
|
|
) : (
|
|
<div class="event-visual" aria-hidden="true">
|
|
<span></span><span></span><span></span><span></span>
|
|
</div>
|
|
)}
|
|
<dl>
|
|
<div>
|
|
<dt>Date</dt>
|
|
<dd>{event.date}</dd>
|
|
</div>
|
|
{event.location && (
|
|
<div>
|
|
<dt>Location</dt>
|
|
<dd>{event.location}</dd>
|
|
</div>
|
|
)}
|
|
{event.showRoleInHero !== false && (
|
|
<div>
|
|
<dt>Role</dt>
|
|
<dd>{event.role}</dd>
|
|
</div>
|
|
)}
|
|
{event.facts?.map((fact) => (
|
|
<div>
|
|
<dt>{fact.label}</dt>
|
|
<dd>{fact.value}</dd>
|
|
</div>
|
|
))}
|
|
</dl>
|
|
</aside>
|
|
</section>
|
|
) : (
|
|
<section class="event-page-heading">
|
|
<nav class="event-breadcrumb" aria-label="Event breadcrumb">
|
|
<a href={basePath}>{eventTitle}</a>
|
|
<span aria-hidden="true">/</span>
|
|
<span>{pageEntry.label}</span>
|
|
</nav>
|
|
<p class="eyebrow">{pageContext}</p>
|
|
<h1>{pageEntry.label}</h1>
|
|
</section>
|
|
)}
|
|
|
|
{shouldRenderBody && (
|
|
<div class:list={["event-shell", "event-shell--single", shouldUseWideBody && "event-shell--wide"]}>
|
|
<div class="event-content">
|
|
{showScheduleBlock && event.schedule && (
|
|
<EventSchedule schedule={event.schedule} asTabs={scheduleAsTabs} />
|
|
)}
|
|
|
|
{isOverview && showOverviewContent && event.links && (
|
|
event.slug === "ncert" ? (
|
|
<section class="content-section quick-links" aria-labelledby="quick-links-title">
|
|
<p class="eyebrow">Quick links</p>
|
|
<h2 id="quick-links-title">Working documents and handbooks</h2>
|
|
<div class="quick-link-grid">
|
|
{event.links.map((link) => (
|
|
<a href={link.href} target="_blank" rel="noreferrer">
|
|
<span>{link.label}</span>
|
|
<strong aria-hidden="true">Open ↗</strong>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</section>
|
|
) : (
|
|
<section class="link-strip" aria-label="Related links">
|
|
{event.links.map((link) => <a href={link.href}>{link.label}</a>)}
|
|
</section>
|
|
)
|
|
)}
|
|
|
|
{isOverview && showOverviewContent && overviewSections.map((section) => (
|
|
<section class="content-section">
|
|
{section.eyebrow && <p class="eyebrow">{section.eyebrow}</p>}
|
|
<h2>{section.title}</h2>
|
|
{section.body?.map((paragraph) => <p>{paragraph}</p>)}
|
|
{section.numbered && (
|
|
<ol class="numbered-list">
|
|
{section.numbered.map((item) => <li>{item}</li>)}
|
|
</ol>
|
|
)}
|
|
{section.bullets && (
|
|
<ul class="check-list">
|
|
{section.bullets.map((bullet) => <li>{bullet}</li>)}
|
|
</ul>
|
|
)}
|
|
{section.links && (
|
|
<div class="resource-grid">
|
|
{section.links.map((link) => (
|
|
<a href={link.href} target="_blank" rel="noreferrer">
|
|
<span>{link.label}</span>
|
|
{link.description && <small>{link.description}</small>}
|
|
<strong aria-hidden="true">Open PDF ↗</strong>
|
|
</a>
|
|
))}
|
|
</div>
|
|
)}
|
|
{section.entries && (
|
|
<div class="minutes-list">
|
|
{section.entries.map((entry) => (
|
|
<article class="minutes-entry">
|
|
<header>
|
|
{entry.meta && <p>{entry.meta}</p>}
|
|
<h3>{entry.title}</h3>
|
|
</header>
|
|
{entry.body.map((paragraph) => <p>{paragraph}</p>)}
|
|
{entry.bullets && (
|
|
<ul>
|
|
{entry.bullets.map((bullet) => <li>{bullet}</li>)}
|
|
</ul>
|
|
)}
|
|
</article>
|
|
))}
|
|
</div>
|
|
)}
|
|
{section.table && (
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>{section.table.headers.map((header) => <th>{header}</th>)}</tr>
|
|
</thead>
|
|
<tbody>
|
|
{section.table.rows.map((row) => (
|
|
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
{section.tables?.map((table) => (
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>{table.headers.map((header) => <th>{header}</th>)}</tr>
|
|
</thead>
|
|
<tbody>
|
|
{table.rows.map((row) => (
|
|
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
))}
|
|
</section>
|
|
))}
|
|
|
|
{isOverview && showOverviewContent && !overviewSection && (
|
|
<section class="content-section">
|
|
<h2>Overview</h2>
|
|
<p>{event.summary}</p>
|
|
</section>
|
|
)}
|
|
|
|
{pageEntry.type === "section" && currentSection && (
|
|
<section class="content-section">
|
|
{currentSection.eyebrow && <p class="eyebrow">{currentSection.eyebrow}</p>}
|
|
<h2>{currentSection.title}</h2>
|
|
{currentSection.body?.map((paragraph) => <p>{paragraph}</p>)}
|
|
{currentSection.numbered && (
|
|
<ol class="numbered-list">
|
|
{currentSection.numbered.map((item) => <li>{item}</li>)}
|
|
</ol>
|
|
)}
|
|
{currentSection.bullets && (
|
|
<ul class="check-list">
|
|
{currentSection.bullets.map((bullet) => <li>{bullet}</li>)}
|
|
</ul>
|
|
)}
|
|
{currentSection.links && (
|
|
<div class="resource-grid">
|
|
{currentSection.links.map((link) => (
|
|
<a href={link.href} target="_blank" rel="noreferrer">
|
|
<span>{link.label}</span>
|
|
{link.description && <small>{link.description}</small>}
|
|
<strong aria-hidden="true">Open PDF ↗</strong>
|
|
</a>
|
|
))}
|
|
</div>
|
|
)}
|
|
{currentSection.entries && (
|
|
<div class="minutes-list">
|
|
{currentSection.entries.map((entry) => (
|
|
<article class="minutes-entry">
|
|
<header>
|
|
{entry.meta && <p>{entry.meta}</p>}
|
|
<h3>{entry.title}</h3>
|
|
</header>
|
|
{entry.body.map((paragraph) => <p>{paragraph}</p>)}
|
|
{entry.bullets && (
|
|
<ul>
|
|
{entry.bullets.map((bullet) => <li>{bullet}</li>)}
|
|
</ul>
|
|
)}
|
|
</article>
|
|
))}
|
|
</div>
|
|
)}
|
|
{currentSection.table && (
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>{currentSection.table.headers.map((header) => <th>{header}</th>)}</tr>
|
|
</thead>
|
|
<tbody>
|
|
{currentSection.table.rows.map((row) => (
|
|
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
{currentSection.tables?.map((table) => (
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>{table.headers.map((header) => <th>{header}</th>)}</tr>
|
|
</thead>
|
|
<tbody>
|
|
{table.rows.map((row) => (
|
|
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
))}
|
|
</section>
|
|
)}
|
|
|
|
{pageEntry.type === "visual" && (
|
|
<section class="content-section image-section">
|
|
<h2>Visual Material</h2>
|
|
{event.gallery ? (
|
|
<div class="gallery-grid">
|
|
{event.gallery.map((image) => (
|
|
<figure>
|
|
<img src={image.src} alt={image.alt} loading="lazy" />
|
|
<figcaption>{image.caption}</figcaption>
|
|
</figure>
|
|
))}
|
|
</div>
|
|
) : event.image && (
|
|
<img src={event.image.src} alt={event.image.alt} loading="lazy" />
|
|
)}
|
|
</section>
|
|
)}
|
|
|
|
{pageEntry.type === "people" && event.people && (
|
|
<section class="content-section">
|
|
<h2>Participants</h2>
|
|
<ul class="people-list">
|
|
{event.people.map((person) => <li>{person}</li>)}
|
|
</ul>
|
|
</section>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</SiteLayout>
|