diff --git a/src/components/EventItem.astro b/src/components/EventItem.astro index 732cb65..1b35f0e 100644 --- a/src/components/EventItem.astro +++ b/src/components/EventItem.astro @@ -1,104 +1,13 @@ --- const { item } = Astro.props; -import { format, compareAsc, addDays, isFuture } from 'date-fns'; import { marked } from 'marked'; import EventsExt from '../events-ext.json'; import core from "../core.json"; -import { imageMetadata } from 'astro/assets/utils'; - -function findExt () { - let slug = null - if (item.links?.web && item.links.web.match(/^https:\/\/lu.ma\//)) { - slug = item.links.web.match(/^https:\/\/lu.ma\/(.+)$/)[1] - } - if (item.links?.rsvp && item.links.rsvp.match(/^https:\/\/lu.ma\//)) { - slug = item.links.rsvp.match(/^https:\/\/lu.ma\/(.+)$/)[1] - } - if (!slug) { - return null - } - return EventsExt.find(ex => ex.url === slug) -} - -function getSpeaker (id) { - return core.people.find(p => p.id === id) -} - -const ext = findExt() - - -const isDate = item.date.match(/^\d{4}-\d{2}-\d{2}$/) -const future = isDate && !isFuture(new Date(item.date)); -const dateMatch = item.date.match(/^(\d{4})/) -const year = dateMatch ? dateMatch[1] : null - -function dateFormat (str) { - if (str.match(/^\d{4}-\d{2}-\d{2}$/)) { - return format(new Date(str), 'MMM d, yyyy') - } - const qm = str.match(/^(\d{4})\/(\w+)$/) - if (qm) { - return `${qm[2]}, ${qm[1]}` - } - return str -} - -function nameRenderer (item) { - let num; - let ccm = item.coincidence?.match(/\[(\w+)\]/) - let cc = ccm && ccm[1] ? ccm[1] : (item.coincidence ? item.coincidence : null) - switch (item.type) { - case 'summit': - num = item.id.match(/^w3ps(\d+)$/)[1] - return `W3PN Summmit #${num} ${item.city}`// + (cc ? ` @ ${cc}` : '') - break; - case 'meetup': - num = item.id.match(/(\d+)$/) - return `W3PN Meetup ${item.city} #${num ? num[1] : 'TBD'}`// + (cc ? ` @ ${cc}` : '') - break; - case 'hackathon': - num = item.id.match(/^w3ph(\d+)$/)[1] - return `W3PN Hackathon #${num} ${item.city}`// + (cc ? ` @ ${cc}` : '') - break; - case 'privacy-corner': - return `Privacy Corner at `+ (item.coincidenceFull ? item.coincidenceFull : `${item.coincidence} ${year}`) - break; - } -} - -function ccRenderer (item) { - let ccm = item.coincidence?.match(/\[(\w+)\]/) - let cc = ccm && ccm[1] ? ccm[1] : (item.coincidence ? item.coincidence : null) - return cc -} - -function dateEnd(str, days) { - return format(addDays(new Date(str), days-1), 'yyyy-MM-dd'); -} - -const statuses = { - preregistration: { - title: 'Pre-registration', - color: 'text-orange-500', - }, - unconfirmed: { - title: 'Planned', - color: '' - }, - confirmed: { - title: 'Confirmed', - color: 'text-green-500', - }, - past: { - title: 'Already happened', - color: 'text-green-800', - } -} - -const status = item.confirmed - ? (future ? statuses.past : statuses.confirmed) - : (item.links?.rsvp ? statuses.preregistration : statuses.unconfirmed); +import { dateFormat, dateInfo, dateEnd, nameRenderer, ccRenderer, eventStatus, getSpeaker, findExt } from '../lib/events.js'; +import SpeakerList from './SpeakerList.astro'; +const ext = findExt(EventsExt, item) +const status = eventStatus(item) ---
@@ -112,7 +21,7 @@ const status = item.confirmed
- {nameRenderer(item)} + {nameRenderer(item)}
{item.type === "hackathon" && HACKATHON} {item.type === "summit" && SUMMIT} @@ -135,7 +44,7 @@ const status = item.confirmed
{item.speakers &&
- {item.speakers.map(spId => getSpeaker(spId)).slice(0,7).map((speaker) => ( + {item.speakers.map(spId => getSpeaker(core, spId)).slice(0,7).map((speaker) => (
))} {item.speakers.length > 7 && @@ -169,7 +78,7 @@ const status = item.confirmed
Date: {dateFormat(item.date)} {item.days ? ' - ' + dateFormat(dateEnd(item.date, item.days)) + ` (${item.days} days)` : ''}
- Place: {item.place && || "TBD"} + Venue: {item.place && || "TBD"} {item.place && item['place-address'] && @ {item['place-address']} @@ -187,27 +96,7 @@ const status = item.confirmed }
- {item.speakers && -
-

Speakers ({item.speakers.length})

-
- {item.speakers.map(spId => getSpeaker(spId)).map((speaker) => ( -
-
-
-
- {speaker.name} - {speaker.refs?.twitter && - (@{speaker.refs.twitter}) - } -
-
-
-
- ))} -
-
- } +
\ No newline at end of file diff --git a/src/components/SpeakerList.astro b/src/components/SpeakerList.astro new file mode 100644 index 0000000..e2178e5 --- /dev/null +++ b/src/components/SpeakerList.astro @@ -0,0 +1,29 @@ +--- +import { marked, } from 'marked'; +const { item, thumbSize } = Astro.props; +import { getSpeaker } from '../lib/events.js'; +import core from "../core.json"; + +--- + +{item.speakers && +
+

Speakers ({item.speakers.length})

+
+ {item.speakers.map(spId => getSpeaker(core, spId)).map((speaker) => ( +
+
+
+
+ {speaker.name} + {speaker.refs?.twitter && + (@{speaker.refs.twitter}) + } +
+
+
+
+ ))} +
+
+} \ No newline at end of file diff --git a/src/layouts/base.astro b/src/layouts/base.astro index 41363cf..8819af5 100644 --- a/src/layouts/base.astro +++ b/src/layouts/base.astro @@ -5,7 +5,7 @@ import * as config from '../config.yaml'; import * as pkg from '../../package.json'; import core from '../core.json'; import '../styles/base.css'; -const {banner, title, description} = Astro.props; +const {banner, title, metaTitle, description} = Astro.props; import cfonts from 'cfonts'; @@ -21,7 +21,7 @@ function genHeading(str) { - {title ? title + ' | ' + config.title : config.title} + {(metaTitle || title) ? ((metaTitle || title) + ' | ' + config.title) : config.title} p.id === id) +} + +export function findExt (eventsExt, item) { + let slug = null + if (item.links?.web && item.links.web.match(/^https:\/\/lu.ma\//)) { + slug = item.links.web.match(/^https:\/\/lu.ma\/(.+)$/)[1] + } + if (item.links?.rsvp && item.links.rsvp.match(/^https:\/\/lu.ma\//)) { + slug = item.links.rsvp.match(/^https:\/\/lu.ma\/(.+)$/)[1] + } + if (!slug) { + return null + } + return eventsExt.find(ex => ex.url === slug) +} \ No newline at end of file diff --git a/src/pages/event/[id].astro b/src/pages/event/[id].astro new file mode 100644 index 0000000..2a842a8 --- /dev/null +++ b/src/pages/event/[id].astro @@ -0,0 +1,82 @@ +--- + +import BaseLayout from '../../layouts/base.astro'; +import SpeakerList from '../../components/SpeakerList.astro'; +import core from '../../core.json'; +import EventsExt from '../../events-ext.json'; +import { dateFormat, dateInfo, dateEnd, nameRenderer, ccRenderer, eventStatus, findExt } from '../../lib/events.js'; +import { marked } from 'marked'; + +const { id } = Astro.params; + +export async function getStaticPaths() { + return core.events.map(event => ({ params: { id: event.id }})); +} + +const item = core.events.find(event => event.id === id) +const status = eventStatus(item) +const ext = findExt(EventsExt, item) +--- + + + +
+ +
+
+

W3PN {nameRenderer(item, true)}

+ +
+ +
+ {item.city}, {item.country.toUpperCase()} + {item.coincidence && +  - {ccRenderer(item)} + } +
+
+ +
+
Date: {dateFormat(item.date)} {item.days ? ' - ' + dateFormat(dateEnd(item.date, item.days)) + ` (${item.days} days)` : ''}
+
+ Venue: {item.place && || "TBD"} + {item.place && item['place-address'] && + @ + {item['place-address']} + } +
+
Status: {status.title}
+
Visitors: + {item.visitors && + {item.visitors} people + } + {!item.visitors && ext && + {ext.guestCount > 0 ? (ext.guestCount + ' people') : 'n/a'} {status.title === 'Pre-registration' ? 'pre-registered' : 'registered'} + } + {!item.visitors && !ext && + n/a + } +
+
Lead: {item.lead || 'n/a'}
+ +
+ {item.links?.rsvp && + + } + {item.links?.web && + + } +
+
+
+
+ {ext && +
+ } +
+
+ + +
+ +
\ No newline at end of file diff --git a/src/pages/events.astro b/src/pages/events.astro index 56ad358..2888dc2 100644 --- a/src/pages/events.astro +++ b/src/pages/events.astro @@ -69,6 +69,9 @@ for (const year of pastYears.reverse()) { if (ev.target.tagName === "BUTTON") { return false; } + if (ev.target.tagName === "A") { + return false; + } const detail = el.parentElement.parentElement.querySelector('.detail') document.querySelectorAll('.detail:not(.hidden)').forEach(e => (detail !== e ? e.classList.add('hidden') : null)); detail.classList.toggle('hidden'); diff --git a/src/styles/base.css b/src/styles/base.css index c1eec7f..692be5a 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -193,6 +193,10 @@ @apply mb-4; } + .w3pn-speaker-list a { + @apply hover:text-white; + } + .icon { @apply inline-block w-12 h-12; }