mirror of
https://github.com/web3privacy/web
synced 2024-10-15 18:26:27 +02:00
Merge branch 'beta'
This commit is contained in:
commit
13c57ae8ed
12 changed files with 353 additions and 151 deletions
4
.github/workflows/ipfs-deploy.yml
vendored
4
.github/workflows/ipfs-deploy.yml
vendored
|
@ -3,8 +3,8 @@ name: Deploy to IPFS
|
||||||
on:
|
on:
|
||||||
# Trigger the workflow every time you push to the `main` branch
|
# Trigger the workflow every time you push to the `main` branch
|
||||||
# Using a different branch name? Replace `main` with your branch’s name
|
# Using a different branch name? Replace `main` with your branch’s name
|
||||||
push:
|
#push:
|
||||||
branches: [ beta ]
|
# branches: [ beta ]
|
||||||
|
|
||||||
# Allow this job to clone the repo and create a page deployment
|
# Allow this job to clone the repo and create a page deployment
|
||||||
permissions:
|
permissions:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "w3pn-web",
|
"name": "w3pn-web",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
|
|
|
@ -4,6 +4,30 @@ import * as config from '../config.yaml';
|
||||||
import core from '../core.json';
|
import core from '../core.json';
|
||||||
import contributors from '../contributors.json';
|
import contributors from '../contributors.json';
|
||||||
|
|
||||||
|
function findPerson(src) {
|
||||||
|
const p = core.people.find(p => src.refs?.twitter ? p.refs?.twitter === src.refs.twitter : (src.refs?.bsky ? p.refs.bsky === src.refs.bsky : {}))
|
||||||
|
if (p) {
|
||||||
|
p.ct = src
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
function personLink(person) {
|
||||||
|
return person.refs?.twitter ? `https://twitter.com/${person.refs.twitter}` : (person.refs?.bsky ? `https://bsky.app/profile/${person.refs.bsky}` : '#')
|
||||||
|
}
|
||||||
|
|
||||||
|
function coreTeamGithubLink(person) {
|
||||||
|
return `https://github.com/${person.ct.refs.github}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterCoreTeam(person) {
|
||||||
|
if (person.login) {
|
||||||
|
return !(core['core-team'].find(ctm => ctm.refs.github.toLowerCase() === person.login.toLowerCase()))
|
||||||
|
}
|
||||||
|
const res = core['core-team'].find(ctm => ctm.refs.twitter ? ctm.refs.twitter?.toLowerCase() === person.refs?.twitter?.toLowerCase() : ctm.refs?.bsky?.toLowerCase() === person.refs?.bsky?.toLowerCase())
|
||||||
|
return !res
|
||||||
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="mt-20">
|
<div class="mt-20">
|
||||||
|
@ -34,13 +58,41 @@ import contributors from '../contributors.json';
|
||||||
<h1><a href="https://docs.web3privacy.info/get-involved">Join the Community</a></h1>
|
<h1><a href="https://docs.web3privacy.info/get-involved">Join the Community</a></h1>
|
||||||
<div>{config.landing.community}</div>
|
<div>{config.landing.community}</div>
|
||||||
|
|
||||||
<div class="flex gap-4 flex-wrap my-14 items-center">
|
<!--h2 class="my-6">Core Team</h2>
|
||||||
{contributors.items.map((contrib) => (
|
<div class="flex gap-4 flex-wrap mb-14 items-center">
|
||||||
<div><a href={contrib.html_url} target="_blank" title={contrib.login}><img src={contrib.avatar_url} class="w-16 rounded-full aspect-square"></a></div>
|
{core['core-team'].map(findPerson).map((person) => (
|
||||||
|
<div>
|
||||||
|
<a href={coreTeamGithubLink(person)}>
|
||||||
|
<img src={person.imageUrl} title={person.name} class="w-14 rounded-full aspect-square" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div-->
|
||||||
|
|
||||||
|
<h2 class="my-6">Speakers</h2>
|
||||||
|
<div class="flex gap-4 flex-wrap items-center">
|
||||||
|
{core.people.filter(filterCoreTeam).filter(p => p.imageUrl).map((person) => (
|
||||||
|
<div>
|
||||||
|
<a href={personLink(person)}>
|
||||||
|
<img src={person.imageUrl} title={person.name} class="w-14 rounded-full aspect-square" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-4 lg:gap-10 pt-4 flex-wrap">
|
<div class="flex gap-4 lg:gap-6 pt-4 flex-wrap mt-4 mb-14">
|
||||||
|
<a href={core.links.cfp} class="button inverted"><button>Submit your proposal (CfP)</button></a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="my-6">Git Contributors</h2>
|
||||||
|
<div class="flex gap-4 flex-wrap mb-4 items-center">
|
||||||
|
{contributors.items.filter(filterCoreTeam).map((contrib) => (
|
||||||
|
<div><a href={contrib.html_url} target="_blank" title={contrib.login}><img src={contrib.avatar_url} class="w-14 rounded-full aspect-square"></a></div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-4 lg:gap-6 pt-4 flex-wrap">
|
||||||
<a href="https://docs.web3privacy.info/get-involved" class="button inverted"><button>Get involved</button></a>
|
<a href="https://docs.web3privacy.info/get-involved" class="button inverted"><button>Get involved</button></a>
|
||||||
<a href="/leaderboard" class="button inverted"><button>Leaderboard</button></a>
|
<a href="/leaderboard" class="button inverted"><button>Leaderboard</button></a>
|
||||||
<a href="https://docs.web3privacy.info/donate/" class="button inverted"><button>Donate</button></a>
|
<a href="https://docs.web3privacy.info/donate/" class="button inverted"><button>Donate</button></a>
|
||||||
|
|
|
@ -1,104 +1,13 @@
|
||||||
---
|
---
|
||||||
const { item } = Astro.props;
|
const { item } = Astro.props;
|
||||||
import { format, compareAsc, addDays, isFuture } from 'date-fns';
|
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import EventsExt from '../events-ext.json';
|
import EventsExt from '../events-ext.json';
|
||||||
import core from "../core.json";
|
import core from "../core.json";
|
||||||
import { imageMetadata } from 'astro/assets/utils';
|
import { dateFormat, dateInfo, dateEnd, nameRenderer, ccRenderer, eventStatus, getSpeaker, findExt } from '../lib/events.js';
|
||||||
|
import SpeakerList from './SpeakerList.astro';
|
||||||
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);
|
|
||||||
|
|
||||||
|
const ext = findExt(EventsExt, item)
|
||||||
|
const status = eventStatus(item)
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="w3pn-event-item">
|
<div class="w3pn-event-item">
|
||||||
|
@ -112,7 +21,7 @@ const status = item.confirmed
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<span class="text-white text-lg">{nameRenderer(item)}</span>
|
<a href={`/event/${item.id}`} class="text-white text-lg hover:underline">{nameRenderer(item)}</a>
|
||||||
<div class="inline-block ml-2">
|
<div class="inline-block ml-2">
|
||||||
{item.type === "hackathon" && <span class="text-xs ml-2 text-black bg-white px-1 py-0.5">HACKATHON</span>}
|
{item.type === "hackathon" && <span class="text-xs ml-2 text-black bg-white px-1 py-0.5">HACKATHON</span>}
|
||||||
{item.type === "summit" && <span class="text-xs ml-2 text-black bg-white px-1 py-0.5">SUMMIT</span>}
|
{item.type === "summit" && <span class="text-xs ml-2 text-black bg-white px-1 py-0.5">SUMMIT</span>}
|
||||||
|
@ -135,7 +44,7 @@ const status = item.confirmed
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
{item.speakers &&
|
{item.speakers &&
|
||||||
<div class="flex -space-x-3">
|
<div class="flex -space-x-3">
|
||||||
{item.speakers.map(spId => getSpeaker(spId)).slice(0,7).map((speaker) => (
|
{item.speakers.map(spId => getSpeaker(core, spId)).slice(0,7).map((speaker) => (
|
||||||
<div><img src={speaker.imageUrl} class="w-8 h-8 aspect-square object-fit rounded-full border-gray-800 border-2" /></div>
|
<div><img src={speaker.imageUrl} class="w-8 h-8 aspect-square object-fit rounded-full border-gray-800 border-2" /></div>
|
||||||
))}
|
))}
|
||||||
{item.speakers.length > 7 &&
|
{item.speakers.length > 7 &&
|
||||||
|
@ -169,7 +78,7 @@ const status = item.confirmed
|
||||||
<div>
|
<div>
|
||||||
<div>Date: <span class="text-white">{dateFormat(item.date)} {item.days ? ' - ' + dateFormat(dateEnd(item.date, item.days)) + ` (${item.days} days)` : ''}</span></div>
|
<div>Date: <span class="text-white">{dateFormat(item.date)} {item.days ? ' - ' + dateFormat(dateEnd(item.date, item.days)) + ` (${item.days} days)` : ''}</span></div>
|
||||||
<div>
|
<div>
|
||||||
Place: {item.place && <span class="text-white" set:html={marked.parseInline(item.place)}></span> || "TBD"}
|
Venue: {item.place && <span class="text-white" set:html={marked.parseInline(item.place)}></span> || "TBD"}
|
||||||
{item.place && item['place-address'] &&
|
{item.place && item['place-address'] &&
|
||||||
<span> @ </span>
|
<span> @ </span>
|
||||||
<span class="text-white">{item['place-address']}</span>
|
<span class="text-white">{item['place-address']}</span>
|
||||||
|
@ -187,27 +96,7 @@ const status = item.confirmed
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{item.speakers &&
|
<SpeakerList {item} />
|
||||||
<div class="mt-6 mb-6">
|
|
||||||
<h2>Speakers ({item.speakers.length})</h2>
|
|
||||||
<div class="grid grid-cols-1 gap-6 mt-4">
|
|
||||||
{item.speakers.map(spId => getSpeaker(spId)).map((speaker) => (
|
|
||||||
<div class="flex gap-4">
|
|
||||||
<div><img class="w-14 h-14 aspect-square rounded-full" src={speaker.imageUrl} /></div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<span class="text-white">{speaker.name}</span>
|
|
||||||
{speaker.refs?.twitter &&
|
|
||||||
<span class="ml-2">(<a href={"https://twitter.com/"+speaker.refs.twitter}>@{speaker.refs.twitter}</a>)</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div set:html={marked.parseInline(speaker.caption)} class="text-sm"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
44
src/components/SpeakerList.astro
Normal file
44
src/components/SpeakerList.astro
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
import { marked, } from 'marked';
|
||||||
|
const { item, thumbSize } = Astro.props;
|
||||||
|
import { getSpeaker } from '../lib/events.js';
|
||||||
|
import core from "../core.json";
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{item.speakers &&
|
||||||
|
<div class="my-6">
|
||||||
|
<h2>Speakers ({item.speakers.length})</h2>
|
||||||
|
<div class="w3pn-speaker-list grid grid-cols-1 gap-6 mt-4">
|
||||||
|
{item.speakers.map(spId => getSpeaker(core, spId)).map((speaker) => (
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<div><img class={`${thumbSize === 'big' ? 'w-16 h-16' : 'w-14 h-14'} aspect-square rounded-full object-contain`} src={speaker.imageUrl} /></div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span class="text-white">{speaker.name}</span>
|
||||||
|
{speaker.refs?.twitter &&
|
||||||
|
<span class="ml-2">(<a href={"https://twitter.com/"+speaker.refs.twitter}>@{speaker.refs.twitter}</a>)</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div set:html={marked.parseInline(speaker.caption)} class="text-sm"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8">
|
||||||
|
<a href={core.links.cfp} class="button inverted"><button>Submit proposal (CfP)</button></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{!item.speakers &&
|
||||||
|
<div class="my-6">
|
||||||
|
<h2>Speakers (0)</h2>
|
||||||
|
|
||||||
|
<div class="mt-4">Stay tuned. Speakers coming :-)</div>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<a href={core.links.cfp} class="button inverted"><button>Submit proposal (CfP)</button></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -58,7 +58,7 @@
|
||||||
"received_events_url": "https://api.github.com/users/burningtree/received_events",
|
"received_events_url": "https://api.github.com/users/burningtree/received_events",
|
||||||
"type": "User",
|
"type": "User",
|
||||||
"site_admin": false,
|
"site_admin": false,
|
||||||
"contributions": 694
|
"contributions": 699
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"login": "EclecticSamurai",
|
"login": "EclecticSamurai",
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
"forum": "https://forum.web3privacy.info",
|
"forum": "https://forum.web3privacy.info",
|
||||||
"explorer": "https://explorer.web3privacy.info",
|
"explorer": "https://explorer.web3privacy.info",
|
||||||
"news": "https://news.web3privacy.info",
|
"news": "https://news.web3privacy.info",
|
||||||
"telegram": "https://t.me/web3privacynow"
|
"telegram": "https://t.me/web3privacynow",
|
||||||
|
"cfp": "https://cfp.web3privacy.info"
|
||||||
},
|
},
|
||||||
"core-team": [
|
"core-team": [
|
||||||
{
|
{
|
||||||
|
@ -539,7 +540,7 @@
|
||||||
],
|
],
|
||||||
"events": [
|
"events": [
|
||||||
{
|
{
|
||||||
"id": "w3ps1",
|
"id": "s23prg",
|
||||||
"type": "summit",
|
"type": "summit",
|
||||||
"date": "2023-06-05",
|
"date": "2023-06-05",
|
||||||
"city": "Prague",
|
"city": "Prague",
|
||||||
|
@ -581,7 +582,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3ps2",
|
"id": "s23rom",
|
||||||
"type": "summit",
|
"type": "summit",
|
||||||
"date": "2023-10-05",
|
"date": "2023-10-05",
|
||||||
"city": "Rome",
|
"city": "Rome",
|
||||||
|
@ -616,7 +617,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-prg1",
|
"id": "m23prg",
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2023-11-14",
|
"date": "2023-11-14",
|
||||||
"city": "Prague",
|
"city": "Prague",
|
||||||
|
@ -638,7 +639,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-ath1",
|
"id": "m24ath",
|
||||||
|
"issue": 22,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024/Mar",
|
"date": "2024/Mar",
|
||||||
"city": "Athens",
|
"city": "Athens",
|
||||||
|
@ -653,7 +655,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-buc1",
|
"id": "m24buc",
|
||||||
|
"issue": 8,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-03-28",
|
"date": "2024-03-28",
|
||||||
"city": "Bucharest",
|
"city": "Bucharest",
|
||||||
|
@ -675,7 +678,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-ams1",
|
"id": "m24ams",
|
||||||
|
"issue": 9,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-04-11",
|
"date": "2024-04-11",
|
||||||
"city": "Amsterdam",
|
"city": "Amsterdam",
|
||||||
|
@ -698,7 +702,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-tal1",
|
"id": "m24tll",
|
||||||
|
"issue": 10,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-04-18",
|
"date": "2024-04-18",
|
||||||
"city": "Tallinn",
|
"city": "Tallinn",
|
||||||
|
@ -712,7 +717,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-por1",
|
"id": "m24opo",
|
||||||
|
"issue": 21,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024/May",
|
"date": "2024/May",
|
||||||
"city": "Porto",
|
"city": "Porto",
|
||||||
|
@ -725,7 +731,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-ber1",
|
"id": "m24ber",
|
||||||
|
"issue": 6,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"tags": [
|
"tags": [
|
||||||
"sfe"
|
"sfe"
|
||||||
|
@ -750,7 +757,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3ps3",
|
"id": "s24prg",
|
||||||
|
"issue": 11,
|
||||||
"type": "summit",
|
"type": "summit",
|
||||||
"date": "2024-05-30",
|
"date": "2024-05-30",
|
||||||
"city": "Prague",
|
"city": "Prague",
|
||||||
|
@ -773,7 +781,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3ph1",
|
"id": "h24ble",
|
||||||
|
"issue": 7,
|
||||||
"type": "hackathon",
|
"type": "hackathon",
|
||||||
"date": "2024-06-19",
|
"date": "2024-06-19",
|
||||||
"days": 7,
|
"days": 7,
|
||||||
|
@ -802,7 +811,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-lju1",
|
"id": "m24lju",
|
||||||
|
"issue": 12,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-06-21",
|
"date": "2024-06-21",
|
||||||
"city": "Ljubljana",
|
"city": "Ljubljana",
|
||||||
|
@ -823,7 +833,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-bcn1",
|
"id": "m24bcn",
|
||||||
|
"issue": 20,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024/Jul",
|
"date": "2024/Jul",
|
||||||
"city": "Barcelona",
|
"city": "Barcelona",
|
||||||
|
@ -833,7 +844,8 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-bru1",
|
"id": "m24bru",
|
||||||
|
"issue": 16,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-07-12",
|
"date": "2024-07-12",
|
||||||
"city": "Brussels",
|
"city": "Brussels",
|
||||||
|
@ -852,7 +864,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-waw1",
|
"id": "m24waw",
|
||||||
|
"issue": 19,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024/Sep",
|
"date": "2024/Sep",
|
||||||
"city": "Warsaw",
|
"city": "Warsaw",
|
||||||
|
@ -863,7 +876,8 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-cph1",
|
"id": "m24cph",
|
||||||
|
"issue": 18,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024/Sep",
|
"date": "2024/Sep",
|
||||||
"city": "Copenhagen",
|
"city": "Copenhagen",
|
||||||
|
@ -877,7 +891,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-rom2",
|
"id": "m24rom",
|
||||||
|
"issue": 13,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-10-04",
|
"date": "2024-10-04",
|
||||||
"city": "Rome",
|
"city": "Rome",
|
||||||
|
@ -897,7 +912,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "pc-rome-2024",
|
"id": "c24rom",
|
||||||
|
"issue": 23,
|
||||||
"type": "privacy-corner",
|
"type": "privacy-corner",
|
||||||
"date": "2024-10-04",
|
"date": "2024-10-04",
|
||||||
"days": 3,
|
"days": 3,
|
||||||
|
@ -908,7 +924,8 @@
|
||||||
"lead": "Tree"
|
"lead": "Tree"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3ps4",
|
"id": "s24brn",
|
||||||
|
"issue": 14,
|
||||||
"type": "summit",
|
"type": "summit",
|
||||||
"date": "2024-10-24",
|
"date": "2024-10-24",
|
||||||
"city": "Brno",
|
"city": "Brno",
|
||||||
|
@ -931,7 +948,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "pc-brno-2024",
|
"id": "c24brn",
|
||||||
|
"issue": 24,
|
||||||
"type": "privacy-corner",
|
"type": "privacy-corner",
|
||||||
"date": "2024-10-25",
|
"date": "2024-10-25",
|
||||||
"days": 3,
|
"days": 3,
|
||||||
|
@ -942,7 +960,8 @@
|
||||||
"lead": "Tree"
|
"lead": "Tree"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "w3pm-dc1",
|
"id": "m24dc",
|
||||||
|
"issue": 15,
|
||||||
"type": "meetup",
|
"type": "meetup",
|
||||||
"date": "2024-11-11",
|
"date": "2024-11-11",
|
||||||
"city": "Bangkok",
|
"city": "Bangkok",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as config from '../config.yaml';
|
||||||
import * as pkg from '../../package.json';
|
import * as pkg from '../../package.json';
|
||||||
import core from '../core.json';
|
import core from '../core.json';
|
||||||
import '../styles/base.css';
|
import '../styles/base.css';
|
||||||
const {banner, title, description} = Astro.props;
|
const {banner, title, metaTitle, description} = Astro.props;
|
||||||
|
|
||||||
import cfonts from 'cfonts';
|
import cfonts from 'cfonts';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ function genHeading(str) {
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
<title>{title ? title + ' | ' + config.title : config.title}</title>
|
<title>{(metaTitle || title) ? ((metaTitle || title) + ' | ' + config.title) : config.title}</title>
|
||||||
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
|
|
99
src/lib/events.js
Normal file
99
src/lib/events.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import { format, compareAsc, addDays, isFuture } from 'date-fns';
|
||||||
|
|
||||||
|
export function dateInfo (item) {
|
||||||
|
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
|
||||||
|
|
||||||
|
return { isDate, isFuture: future, year }
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dateEnd(str, days) {
|
||||||
|
return format(addDays(new Date(str), days-1), 'yyyy-MM-dd');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function nameRenderer (item, full = false) {
|
||||||
|
let num;
|
||||||
|
let ccm = item.coincidence?.match(/\[(\w+)\]/)
|
||||||
|
let cc = ccm && ccm[1] ? ccm[1] : (item.coincidence ? item.coincidence : null)
|
||||||
|
const date = dateInfo(item)
|
||||||
|
switch (item.type) {
|
||||||
|
case 'summit':
|
||||||
|
//num = item.id.match(/^w3ps(\d+)$/)[1]
|
||||||
|
return `Summmit ${item.city}` + (full ? ` ${date.year}`: '')// + (cc ? ` @ ${cc}` : '')
|
||||||
|
break;
|
||||||
|
case 'meetup':
|
||||||
|
//num = item.id.match(/(\d+)$/)
|
||||||
|
return `Meetup ${item.city}` + (full ? ` ${date.year}`: '')// + (cc ? ` @ ${cc}` : '')
|
||||||
|
break;
|
||||||
|
case 'hackathon':
|
||||||
|
//num = item.id.match(/^w3ph(\d+)$/)[1]
|
||||||
|
return `Hackathon ${item.city}` + (full ? ` ${date.year}`: '')// + (cc ? ` @ ${cc}` : '')
|
||||||
|
break;
|
||||||
|
case 'privacy-corner':
|
||||||
|
return `Privacy Corner at `+ (item.coincidenceFull ? item.coincidenceFull : `${item.coincidence} ${date.year}`)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ccRenderer (item) {
|
||||||
|
let ccm = item.coincidence?.match(/\[(\w+)\]/)
|
||||||
|
let cc = ccm && ccm[1] ? ccm[1] : (item.coincidence ? item.coincidence : null)
|
||||||
|
return cc
|
||||||
|
}
|
||||||
|
|
||||||
|
export function eventStatus (item) {
|
||||||
|
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 date = dateInfo(item)
|
||||||
|
return item.confirmed
|
||||||
|
? (date.isDate ? statuses.past : statuses.confirmed)
|
||||||
|
: (item.links?.rsvp ? statuses.preregistration : statuses.unconfirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSpeaker (core, id) {
|
||||||
|
return core.people.find(p => 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)
|
||||||
|
}
|
92
src/pages/event/[id].astro
Normal file
92
src/pages/event/[id].astro
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
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)
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout title={id} metaTitle={nameRenderer(item, true)}>
|
||||||
|
|
||||||
|
<div class="middle-pane-medium mt-10">
|
||||||
|
|
||||||
|
<div class="lg:flex w-full ">
|
||||||
|
<div class="lg:mr-10 mb-8 lg:mb-0">
|
||||||
|
<div><img src={ext ? ext.coverUrl : '/logo.svg'} class="rounded border border-white/20 w-80 aspect-square object-contain" class:list={[!ext ? 'p-10' : '']} /></div>
|
||||||
|
</div>
|
||||||
|
<div class="grow">
|
||||||
|
<h1 id="upcoming">W3PN {nameRenderer(item, true)}</h1>
|
||||||
|
|
||||||
|
<div class="flex gap-2 mb-4 text-lg">
|
||||||
|
<img src={`/flags/${item.country}.svg`} class="w-4" />
|
||||||
|
<div>
|
||||||
|
{item.city}, {item.country.toUpperCase()}
|
||||||
|
{item.coincidence &&
|
||||||
|
<span> - {ccRenderer(item)}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>Date: <span class="text-white">{dateFormat(item.date)} {item.days ? ' - ' + dateFormat(dateEnd(item.date, item.days)) + ` (${item.days} days)` : ''}</span></div>
|
||||||
|
<div>
|
||||||
|
Venue: {item.place && <span class="text-white" set:html={marked.parseInline(item.place)}></span> || "TBD"}
|
||||||
|
{item.place && item['place-address'] &&
|
||||||
|
<span> @ </span>
|
||||||
|
<span class="text-white">{item['place-address']}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div>Status: <span class:list={[status.color]} class="mr-1.5 text-xs">●</span> {status.title}</div>
|
||||||
|
<div>Visitors:
|
||||||
|
{item.visitors &&
|
||||||
|
<span class="text-white">{item.visitors} people</span>
|
||||||
|
}
|
||||||
|
{!item.visitors && ext &&
|
||||||
|
<span><span class="text-white">{ext.guestCount > 0 ? (ext.guestCount + ' people') : 'n/a'}</span> {status.title === 'Pre-registration' ? 'pre-registered' : 'registered'}</span>
|
||||||
|
}
|
||||||
|
{!item.visitors && !ext &&
|
||||||
|
<span>n/a</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 mb-2">
|
||||||
|
{item.links?.rsvp &&
|
||||||
|
<a href={item.links.rsvp} class="button inverted"><button>{status.title === 'Pre-registration' ? 'Pre-registration' : 'Registration'}</button></a>
|
||||||
|
}
|
||||||
|
{item.links?.web &&
|
||||||
|
<a href={item.links.web} class="button inverted"><button>Website</button></a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-[#0f0f0f] px-4 py-2 mt-6 flex gap-6 w-full">
|
||||||
|
<div>ID: <span class="py-1 px-2 rounded bg-white/70 text-black">{item.id}</span></div>
|
||||||
|
<div>Lead: <span class="">{item.lead || 'n/a'}</span></div>
|
||||||
|
<div class="grow flex items-right justify-end gap-6">
|
||||||
|
{item.links?.rsvp &&
|
||||||
|
<a href={item.links.rsvp} class="hover:text-white">Lu.ma</a>
|
||||||
|
}
|
||||||
|
{item.issue &&
|
||||||
|
<a href={`https://github.com/web3privacy/events/issues/${item.issue}`} class="hover:text-white">PM</a>
|
||||||
|
}
|
||||||
|
<a href="https://github.com/web3privacy/data/blob/main/src/events/index.yaml" class="hover:text-white">Source</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SpeakerList {item} thumbSize="big"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</BaseLayout>
|
|
@ -69,6 +69,9 @@ for (const year of pastYears.reverse()) {
|
||||||
if (ev.target.tagName === "BUTTON") {
|
if (ev.target.tagName === "BUTTON") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (ev.target.tagName === "A") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const detail = el.parentElement.parentElement.querySelector('.detail')
|
const detail = el.parentElement.parentElement.querySelector('.detail')
|
||||||
document.querySelectorAll('.detail:not(.hidden)').forEach(e => (detail !== e ? e.classList.add('hidden') : null));
|
document.querySelectorAll('.detail:not(.hidden)').forEach(e => (detail !== e ? e.classList.add('hidden') : null));
|
||||||
detail.classList.toggle('hidden');
|
detail.classList.toggle('hidden');
|
||||||
|
|
|
@ -193,6 +193,10 @@
|
||||||
@apply mb-4;
|
@apply mb-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w3pn-speaker-list a {
|
||||||
|
@apply hover:text-white;
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@apply inline-block w-12 h-12;
|
@apply inline-block w-12 h-12;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue