Format code by "npm run format"
This commit is contained in:
rodič
c1e019f065
revize
d4862f096f
|
@ -1,15 +1,15 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
extends: ["eslint:recommended", "prettier"],
|
||||
plugins: ["svelte3"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
extends: ['eslint:recommended', 'prettier'],
|
||||
plugins: ['svelte3'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
node: true
|
||||
}
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
run: npm run build
|
||||
|
||||
- name: Add custom domain
|
||||
run: "touch build/CNAME && echo \"explore.prgblockweek.com\" >> build/CNAME"
|
||||
run: 'touch build/CNAME && echo "explore.prgblockweek.com" >> build/CNAME'
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||
const config = {
|
||||
webServer: {
|
||||
command: "npm run build && npm run preview",
|
||||
port: 4173,
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: "tests",
|
||||
testDir: 'tests'
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<!-- Plausible -->
|
||||
<script defer data-domain="explore.prgblockweek.com" src="https://x.gwei.cz/js/script.js"></script>
|
||||
<script
|
||||
defer
|
||||
data-domain="explore.prgblockweek.com"
|
||||
src="https://x.gwei.cz/js/script.js"
|
||||
></script>
|
||||
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
|
|
@ -12,9 +12,16 @@
|
|||
|
||||
<div class="text-2xl">
|
||||
{#each segments as segment}
|
||||
<div class="md:flex flex-wrap mb-2 gap-3 items-center text-gray-800 border border-gray-300 rounded-lg md:border-none px-3 py-2 md:px-0 md:py-0">
|
||||
<div
|
||||
class="md:flex flex-wrap mb-2 gap-3 items-center text-gray-800 border border-gray-300 rounded-lg md:border-none px-3 py-2 md:px-0 md:py-0"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<div class="text-xl md:w-32 md:text-right">{format(new Date(segment.startTime), "HH:mm")} - {format(new Date(segment.endTime), "HH:mm")}</div>
|
||||
<div class="text-xl md:w-32 md:text-right">
|
||||
{format(new Date(segment.startTime), 'HH:mm')} - {format(
|
||||
new Date(segment.endTime),
|
||||
'HH:mm'
|
||||
)}
|
||||
</div>
|
||||
{#if !event}
|
||||
<div class="gap-1 items-center md:ml-2 inline-flex md:hidden text-xs">
|
||||
{#each (segment.event || event).types as type}
|
||||
|
@ -26,11 +33,15 @@
|
|||
<div class="md:flex gap-2 items-center mb-6 md:mb-0">
|
||||
<div class="flex gap-2 items-center my-2 md:my-0">
|
||||
<a href="/{entry}/event/{(segment.event || event).id}">
|
||||
<ItemLogo item={segment.event || event} width={event ? 'w-8' : 'w-10'}/>
|
||||
<ItemLogo item={segment.event || event} width={event ? 'w-8' : 'w-10'} />
|
||||
</a>
|
||||
<div>
|
||||
{#if !event}
|
||||
<a href="/{entry}/event/{(segment.event || event).id}" class="text-pbw-red hover:underline">{(segment.event || event)[event && event.shortname ? 'shortname' : 'name']}</a>
|
||||
<a
|
||||
href="/{entry}/event/{(segment.event || event).id}"
|
||||
class="text-pbw-red hover:underline"
|
||||
>{(segment.event || event)[event && event.shortname ? 'shortname' : 'name']}</a
|
||||
>
|
||||
{:else}
|
||||
<span class="">{event.shortname || event.name}</span>
|
||||
{/if}
|
||||
|
@ -49,16 +60,20 @@
|
|||
{/if}
|
||||
<div class="text-xl">
|
||||
{#if segment.venues || event?.venues}
|
||||
📍 {@html ((segment.venues || event.venues).map(vId => {
|
||||
const place = bundle.places.find(p => p.id === vId)
|
||||
return `<a href="/${entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`
|
||||
})).join("<span>, </span>")}
|
||||
{:else if (segment.event?.venueName || event?.venueName)}
|
||||
📍 {(segment.event?.venueName || event?.venueName)}
|
||||
📍 {@html (segment.venues || event.venues)
|
||||
.map((vId) => {
|
||||
const place = bundle.places.find((p) => p.id === vId);
|
||||
return `<a href="/${entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`;
|
||||
})
|
||||
.join('<span>, </span>')}
|
||||
{:else if segment.event?.venueName || event?.venueName}
|
||||
📍 {segment.event?.venueName || event?.venueName}
|
||||
{/if}
|
||||
</div>
|
||||
{#if segment.ecap || event?.attendees || segment.event?.attendees }
|
||||
<div class="text-lg">👥 {segment.ecap || event?.attendees || segment.event?.attendees}</div>
|
||||
{#if segment.ecap || event?.attendees || segment.event?.attendees}
|
||||
<div class="text-lg">
|
||||
👥 {segment.ecap || event?.attendees || segment.event?.attendees}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,67 +4,87 @@
|
|||
import ItemLogo from '$lib/components/ItemLogo.svelte';
|
||||
|
||||
export let arr;
|
||||
export let entry = "23";
|
||||
export let col = "speaker";
|
||||
export let img = "photoUrl";
|
||||
export let aspect = "aspect-square";
|
||||
export let size = "normal";
|
||||
export let entry = '23';
|
||||
export let col = 'speaker';
|
||||
export let img = 'photoUrl';
|
||||
export let aspect = 'aspect-square';
|
||||
export let size = 'normal';
|
||||
export let offer = false;
|
||||
export let bundle = null;
|
||||
export let currentItem = null;
|
||||
|
||||
function findObject (it) {
|
||||
function findObject(it) {
|
||||
if (!bundle) {
|
||||
return it
|
||||
return it;
|
||||
}
|
||||
if (col === "speaker" && !it.name) {
|
||||
let found = null
|
||||
if (col === 'speaker' && !it.name) {
|
||||
let found = null;
|
||||
for (const e of bundle.events) {
|
||||
if (!e.speakers) continue;
|
||||
found = e.speakers.find(s => {
|
||||
return s.id === it.id && s.name
|
||||
})
|
||||
found = e.speakers.find((s) => {
|
||||
return s.id === it.id && s.name;
|
||||
});
|
||||
if (found) break;
|
||||
}
|
||||
Object.assign(it, found || {})
|
||||
Object.assign(it, found || {});
|
||||
}
|
||||
return it
|
||||
return it;
|
||||
}
|
||||
|
||||
const _url = (col, item) => `/${entry}/${col}/${item.id}`
|
||||
const _url = (col, item) => `/${entry}/${col}/${item.id}`;
|
||||
</script>
|
||||
|
||||
{#each arr.map((k) => findObject(k)) as item}
|
||||
<div class="{size === "small" ? "p-0.5 lg:p-1" : "p-1 lg:p-1.5"} hover:bg-pbw-yellow/20 dark:hover:bg-pbw-white/10 {size==="small" ? "rounded-lg" : "rounded-2xl"}">
|
||||
<div
|
||||
class="{size === 'small'
|
||||
? 'p-0.5 lg:p-1'
|
||||
: 'p-1 lg:p-1.5'} hover:bg-pbw-yellow/20 dark:hover:bg-pbw-white/10 {size === 'small'
|
||||
? 'rounded-lg'
|
||||
: 'rounded-2xl'}"
|
||||
>
|
||||
<div class="w-full relative">
|
||||
{#if col === "benefit"}
|
||||
{#if col === 'benefit'}
|
||||
<div class="absolute top-3 -left-4">
|
||||
<div class="bg-pbw-red py-0.5 px-1.5 rounded-md text-white uppercase text-base">{item.slogan}</div>
|
||||
<div class="bg-pbw-red py-0.5 px-1.5 rounded-md text-white uppercase text-base">
|
||||
{item.slogan}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<a href={_url(col, item)}>
|
||||
<ItemLogo {item} width="w-full" {aspect} {img} rounded={size === "small" ? "rounded-lg" : "rounded-2xl"} />
|
||||
<ItemLogo
|
||||
{item}
|
||||
width="w-full"
|
||||
{aspect}
|
||||
{img}
|
||||
rounded={size === 'small' ? 'rounded-lg' : 'rounded-2xl'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{#if col !== "media-partner"}
|
||||
{#if col !== 'media-partner'}
|
||||
<div class="mt-2">
|
||||
<h3 class=" text-pbw-red"><a href={_url(col, item)} class="hover:underline">{item.shortname || item.name}</a></h3>
|
||||
{#if col === "event"}
|
||||
<h3 class=" text-pbw-red">
|
||||
<a href={_url(col, item)} class="hover:underline">{item.shortname || item.name}</a>
|
||||
</h3>
|
||||
{#if col === 'event'}
|
||||
<div class="text-xl text-gray-500 dark:text-gray-400 my-2">
|
||||
<span class="font-bold">{formatItemDate(item)}</span>
|
||||
{#if item.attendees}<br />{item.attendees} ppl{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "media-partner"}
|
||||
{#if col === 'media-partner'}
|
||||
<div class="text-base text-gray-500 dark:text-gray-400 my-2">{item.description}</div>
|
||||
{/if}
|
||||
{#if col === "speaker"}
|
||||
<div class="text-base text-gray-500 dark:text-gray-400 my-2"><SvelteMarkdown source={item.caption} /></div>
|
||||
{#if col === 'speaker'}
|
||||
<div class="text-base text-gray-500 dark:text-gray-400 my-2">
|
||||
<SvelteMarkdown source={item.caption} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "union"}
|
||||
<div class="text-base text-gray-500 dark:text-gray-400 my-2"><SvelteMarkdown source={item.description} /></div>
|
||||
{#if col === 'union'}
|
||||
<div class="text-base text-gray-500 dark:text-gray-400 my-2">
|
||||
<SvelteMarkdown source={item.description} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "place"}
|
||||
{#if col === 'place'}
|
||||
<div class="text-xl text-gray-500 dark:text-gray-400 my-2">{item.capacity} ppl</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -72,12 +92,20 @@
|
|||
</div>
|
||||
{/each}
|
||||
{#if offer}
|
||||
<div class="flex text-gray-400 self-start {col==="event" ? "mt-8" : ""}">
|
||||
<div class="flex text-gray-400 self-start {col === 'event' ? 'mt-8' : ''}">
|
||||
<div class="p-4">
|
||||
<div class="text-6xl">+</div>
|
||||
<div>
|
||||
{#if col === 'event'}<a href="https://guide.prgblockweek.com/event-host-guide" target="_blank" class="underline hover:no-underline">Host your own event!</a>{/if}
|
||||
{#if col === 'benefit'}<a href="https://guide.prgblockweek.com/event-host-guide" target="_blank" class="underline hover:no-underline">Offer visitors your own benefit!</a>{/if}
|
||||
{#if col === 'event'}<a
|
||||
href="https://guide.prgblockweek.com/event-host-guide"
|
||||
target="_blank"
|
||||
class="underline hover:no-underline">Host your own event!</a
|
||||
>{/if}
|
||||
{#if col === 'benefit'}<a
|
||||
href="https://guide.prgblockweek.com/event-host-guide"
|
||||
target="_blank"
|
||||
class="underline hover:no-underline">Offer visitors your own benefit!</a
|
||||
>{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<script>
|
||||
import { config } from '$lib/pbw.js';
|
||||
export let type = "conference";
|
||||
|
||||
export let type = 'conference';
|
||||
</script>
|
||||
|
||||
<div class="text-sm uppercase rounded px-1.5 py-0.5 text-black" style="background-color: {config.eventTypeColors[type]};">
|
||||
<div
|
||||
class="text-sm uppercase rounded px-1.5 py-0.5 text-black"
|
||||
style="background-color: {config.eventTypeColors[type]};"
|
||||
>
|
||||
{type}
|
||||
</div>
|
||||
|
|
|
@ -1,39 +1,76 @@
|
|||
<script>
|
||||
import { config } from '$lib/pbw';
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
|
||||
export let item;
|
||||
export let col;
|
||||
export let bundle;
|
||||
|
||||
const cc = Object.keys(config.collections).find(c => config.collections[c].model === col)
|
||||
const cc = Object.keys(config.collections).find((c) => config.collections[c].model === col);
|
||||
|
||||
let showSource = false;
|
||||
</script>
|
||||
|
||||
|
||||
<div class="mt-20">
|
||||
<div class="bg-gray-100 p-4 text-lg text-gray-600">
|
||||
<div>⚙ This page is automatically generated using the structured dataset which can be consumed as a single JSON file → <a href="https://data.prgblockweek.com/23/index.json" class="underline hover:no-underline" target="_blank">data.prgblockweek.com/23/index.json</a>.
|
||||
<div class="h-4"></div>
|
||||
📖 The source data GitHub repository → <a href="https://github.com/utxo-foundation/prague-blockchain-week" class="underline hover:no-underline" target="_blank">utxo-foundation/prague-blockchain-week</a>.
|
||||
Go ahead and do PRs!
|
||||
<div>
|
||||
⚙ This page is automatically generated using the structured dataset which can be consumed as a
|
||||
single JSON file → <a
|
||||
href="https://data.prgblockweek.com/23/index.json"
|
||||
class="underline hover:no-underline"
|
||||
target="_blank">data.prgblockweek.com/23/index.json</a
|
||||
>.
|
||||
<div class="h-4" />
|
||||
📖 The source data GitHub repository →<a
|
||||
href="https://github.com/utxo-foundation/prague-blockchain-week"
|
||||
class="underline hover:no-underline"
|
||||
target="_blank">utxo-foundation/prague-blockchain-week</a
|
||||
>. Go ahead and do PRs!
|
||||
</div>
|
||||
</div>
|
||||
{#if bundle}
|
||||
<div class="mt-4 text-gray-400">
|
||||
<div class="mt-2">
|
||||
Last update: <a href="https://github.com/utxo-foundation/prague-blockchain-week/commits/main" target="_blank" class="underline hover:no-underline">{formatDistanceToNow(new Date(bundle.time))} ago</a>
|
||||
| <a href="https://analytics.gwei.cz/explore.prgblockweek.com" class="underline hover:no-underline" target="_blank">Analytics</a>
|
||||
| <a href="https://github.com/utxo-foundation/pbw-explore" class="underline hover:no-underline" target="_blank">pbw-explore {__VERSION__}</a>
|
||||
Last update: <a
|
||||
href="https://github.com/utxo-foundation/prague-blockchain-week/commits/main"
|
||||
target="_blank"
|
||||
class="underline hover:no-underline">{formatDistanceToNow(new Date(bundle.time))} ago</a
|
||||
>
|
||||
|
|
||||
<a
|
||||
href="https://analytics.gwei.cz/explore.prgblockweek.com"
|
||||
class="underline hover:no-underline"
|
||||
target="_blank">Analytics</a
|
||||
>
|
||||
|
|
||||
<a
|
||||
href="https://github.com/utxo-foundation/pbw-explore"
|
||||
class="underline hover:no-underline"
|
||||
target="_blank">pbw-explore {__VERSION__}</a
|
||||
>
|
||||
{#if item}
|
||||
| ID: <a href="https://github.com/utxo-foundation/prague-blockchain-week/tree/main/data/23/{cc}/{item.id}" class="underline hover:no-underline" target="_blank">{item.id}</a> [{cc}]
|
||||
| <button class="cursor-pointer underline hover:no-underline" on:click={() => { showSource = !showSource; return false; }}>Toggle JSON source</button>
|
||||
| ID: <a
|
||||
href="https://github.com/utxo-foundation/prague-blockchain-week/tree/main/data/23/{cc}/{item.id}"
|
||||
class="underline hover:no-underline"
|
||||
target="_blank">{item.id}</a
|
||||
>
|
||||
[{cc}] |
|
||||
<button
|
||||
class="cursor-pointer underline hover:no-underline"
|
||||
on:click={() => {
|
||||
showSource = !showSource;
|
||||
return false;
|
||||
}}>Toggle JSON source</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if showSource}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">JSON source-code</h2>
|
||||
<div class="mt-4 font-mono whitespace-pre-wrap p-4 rounded-md bg-slate-200 text-sm text-black">{JSON.stringify(item, null, 2)}</div>
|
||||
<div
|
||||
class="mt-4 font-mono whitespace-pre-wrap p-4 rounded-md bg-slate-200 text-sm text-black"
|
||||
>
|
||||
{JSON.stringify(item, null, 2)}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -2,16 +2,23 @@
|
|||
import makeBlockie from 'ethereum-blockies-base64';
|
||||
|
||||
export let item;
|
||||
export let img = "logo";
|
||||
export let width = "w-10";
|
||||
export let aspect = "aspect-square";
|
||||
export let rounded = "rounded";
|
||||
export let img = 'logo';
|
||||
export let width = 'w-10';
|
||||
export let aspect = 'aspect-square';
|
||||
export let rounded = 'rounded';
|
||||
|
||||
$: blockie = !item[img] && item.hash ? makeBlockie('0x'+item.hash.substr(0,40)) : null
|
||||
$: blockie = !item[img] && item.hash ? makeBlockie('0x' + item.hash.substr(0, 40)) : null;
|
||||
</script>
|
||||
|
||||
{#if item[img]}
|
||||
<img src={item[img]} class="{width} {rounded} {aspect} object-cover dark:bg-white" alt={item.name} />
|
||||
<img
|
||||
src={item[img]}
|
||||
class="{width} {rounded} {aspect} object-cover dark:bg-white"
|
||||
alt={item.name}
|
||||
/>
|
||||
{:else if item.hash}
|
||||
<div class="{width} {rounded} {aspect} object-cover dark:bg-white" style="background: url({blockie}); background-size: 100% 100%;"></div>
|
||||
<div
|
||||
class="{width} {rounded} {aspect} object-cover dark:bg-white"
|
||||
style="background: url({blockie}); background-size: 100% 100%;"
|
||||
/>
|
||||
{/if}
|
|
@ -5,111 +5,134 @@
|
|||
export let data;
|
||||
export let highlightDay = false;
|
||||
|
||||
const startDate = "2023-06-02"
|
||||
const endDate = "2023-06-11"
|
||||
const segmentMinutes = 60
|
||||
const bundle = data.bundle
|
||||
const startDate = '2023-06-02';
|
||||
const endDate = '2023-06-11';
|
||||
const segmentMinutes = 60;
|
||||
const bundle = data.bundle;
|
||||
|
||||
const days = []
|
||||
let currentDate = startDate
|
||||
const days = [];
|
||||
let currentDate = startDate;
|
||||
while (compareAsc(new Date(currentDate), new Date(endDate)) <= 0) {
|
||||
days.push(format(new Date(currentDate), 'yyyy-MM-dd'))
|
||||
currentDate = addDays(new Date(currentDate), 1)
|
||||
days.push(format(new Date(currentDate), 'yyyy-MM-dd'));
|
||||
currentDate = addDays(new Date(currentDate), 1);
|
||||
}
|
||||
|
||||
const segments = []
|
||||
let currentSegment = "00:00"
|
||||
const endSegmentDate = addDays(new Date(startDate), 1)
|
||||
while(!segments.includes(currentSegment)) {
|
||||
segments.push(format(new Date(startDate+"T"+currentSegment), 'HH:mm'))
|
||||
currentSegment = format(addMinutes(new Date(startDate+"T"+currentSegment), segmentMinutes), "HH:mm")
|
||||
const segments = [];
|
||||
let currentSegment = '00:00';
|
||||
const endSegmentDate = addDays(new Date(startDate), 1);
|
||||
while (!segments.includes(currentSegment)) {
|
||||
segments.push(format(new Date(startDate + 'T' + currentSegment), 'HH:mm'));
|
||||
currentSegment = format(
|
||||
addMinutes(new Date(startDate + 'T' + currentSegment), segmentMinutes),
|
||||
'HH:mm'
|
||||
);
|
||||
}
|
||||
|
||||
const timelineData = {}
|
||||
const timelineData = {};
|
||||
for (const day of days) {
|
||||
for (const segment of segments) {
|
||||
const score = 0
|
||||
const score = 0;
|
||||
timelineData[[day, segment].join(';')] = {
|
||||
score,
|
||||
events: []
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimelineEvent(time, eventId, attendees, eventSegmentId) {
|
||||
for (const day of days) {
|
||||
for (const segment of segments) {
|
||||
const sstart = new Date(`${day}T${segment}`)
|
||||
const send = new Date(addMinutes(sstart, segmentMinutes))
|
||||
const sstart = new Date(`${day}T${segment}`);
|
||||
const send = new Date(addMinutes(sstart, segmentMinutes));
|
||||
if (compareAsc(sstart, time.end) < 0 && compareAsc(send, time.start) > 0) {
|
||||
//console.log(timelineData[[day, segment].join(';')])
|
||||
const baseScore = attendees ? (attendees > 3000 ? 3000 : (attendees < 200 ? 200 : attendees)) : 0
|
||||
const target = timelineData[[day, segment].join(';')]
|
||||
target.score += baseScore || 0
|
||||
target.events.push([eventId, eventSegmentId])
|
||||
const baseScore = attendees
|
||||
? attendees > 3000
|
||||
? 3000
|
||||
: attendees < 200
|
||||
? 200
|
||||
: attendees
|
||||
: 0;
|
||||
const target = timelineData[[day, segment].join(';')];
|
||||
target.score += baseScore || 0;
|
||||
target.events.push([eventId, eventSegmentId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const defaultTimes = "09:00-18:00"
|
||||
const defaultTimes = '09:00-18:00';
|
||||
for (const event of bundle.events) {
|
||||
for (let i = 0; i < event.segments.length; i++) {
|
||||
const eventSegment = event.segments[i]
|
||||
const [ tstart, tend ] = (eventSegment.times || defaultTimes).split('-')
|
||||
const eventSegment = event.segments[i];
|
||||
const [tstart, tend] = (eventSegment.times || defaultTimes).split('-');
|
||||
const time = {
|
||||
start: new Date(`${eventSegment.date}T${tstart}`),
|
||||
end: new Date(`${tend <= tstart ? format(addDays(new Date(eventSegment.date),1), 'yyyy-MM-dd') : eventSegment.date}T${tend}`)
|
||||
}
|
||||
updateTimelineEvent(time, event.id, eventSegment.ecap || event.attendees, i)
|
||||
end: new Date(
|
||||
`${
|
||||
tend <= tstart
|
||||
? format(addDays(new Date(eventSegment.date), 1), 'yyyy-MM-dd')
|
||||
: eventSegment.date
|
||||
}T${tend}`
|
||||
)
|
||||
};
|
||||
updateTimelineEvent(time, event.id, eventSegment.ecap || event.attendees, i);
|
||||
}
|
||||
}
|
||||
|
||||
const segmentsMax = Math.max(...Object.keys(timelineData).map(k => timelineData[k].score))
|
||||
const segmentsMax = Math.max(...Object.keys(timelineData).map((k) => timelineData[k].score));
|
||||
for (const sgm of Object.keys(timelineData)) {
|
||||
const it = timelineData[sgm]
|
||||
it.perc = (it.score / (segmentsMax/100))
|
||||
const it = timelineData[sgm];
|
||||
it.perc = it.score / (segmentsMax / 100);
|
||||
}
|
||||
|
||||
let selectedSegment = null
|
||||
let selectedSegment = null;
|
||||
|
||||
function makeSelected (day, segment, keys) {
|
||||
const baseDate = new Date(`${day}T${segment}`)
|
||||
const title = format(baseDate, "EEEE MMMM d | HH:mm - ") + format(addMinutes(baseDate, segmentMinutes), "HH:mm")
|
||||
function makeSelected(day, segment, keys) {
|
||||
const baseDate = new Date(`${day}T${segment}`);
|
||||
const title =
|
||||
format(baseDate, 'EEEE MMMM d | HH:mm - ') +
|
||||
format(addMinutes(baseDate, segmentMinutes), 'HH:mm');
|
||||
return (event) => {
|
||||
selectedSegment = {
|
||||
day,
|
||||
segment,
|
||||
data: keys,
|
||||
event,
|
||||
title,
|
||||
}
|
||||
}
|
||||
title
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function makeClick (day, segment, keys) {
|
||||
const start = new Date(`${day}T${segment}`)
|
||||
const end = addMinutes(start, segmentMinutes)
|
||||
function makeClick(day, segment, keys) {
|
||||
const start = new Date(`${day}T${segment}`);
|
||||
const end = addMinutes(start, segmentMinutes);
|
||||
//goto(`/${data.params.entry}/events?start=${start.toISOString()}&end=${end.toISOString()}`)
|
||||
goto(`/${data.params.entry}/day/${day}?start=${start.toISOString()}&end=${end.toISOString()}`)
|
||||
goto(`/${data.params.entry}/day/${day}?start=${start.toISOString()}&end=${end.toISOString()}`);
|
||||
}
|
||||
|
||||
function hiddenSelected() {
|
||||
selectedSegment = null
|
||||
selectedSegment = null;
|
||||
}
|
||||
|
||||
function eventDetail (id) {
|
||||
return bundle.events.find(e => e.id === id)
|
||||
function eventDetail(id) {
|
||||
return bundle.events.find((e) => e.id === id);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="w-full mb-10 relative">
|
||||
{#if selectedSegment}
|
||||
<div class="absolute top-[81px] w-[300px] border bg-white z-50 py-2 px-4 {selectedSegment ? 'hidden md:block' : 'hidden'}" style="left: {selectedSegment.event.layerX}px;">
|
||||
<div
|
||||
class="absolute top-[81px] w-[300px] border bg-white z-50 py-2 px-4 {selectedSegment
|
||||
? 'hidden md:block'
|
||||
: 'hidden'}"
|
||||
style="left: {selectedSegment.event.layerX}px;"
|
||||
>
|
||||
<div class="uppercase">{selectedSegment.title}</div>
|
||||
<div class="text-xl mt-4">
|
||||
{#each selectedSegment.data.events.map(e => { return [eventDetail(e[0]), e[1]] }) as [item, segmentId]}
|
||||
{#each selectedSegment.data.events.map((e) => {
|
||||
return [eventDetail(e[0]), e[1]];
|
||||
}) as [item, segmentId]}
|
||||
<div class="flex gap-2 items-center mb-1">
|
||||
<div class="">
|
||||
<ItemLogo {item} width="h-8" />
|
||||
|
@ -127,8 +150,16 @@
|
|||
{/if}
|
||||
<div class="flex text-center text-gray-400 text-sm items-end h-10">
|
||||
{#each days as day}
|
||||
<div class="mb-1 uppercase {highlightDay && highlightDay !== day ? "text-gray-400 text-lg" : "text-pbw-red text-lg"}" style="width: {1/(days.length/100)}%;">
|
||||
<a href="/23/day/{format(new Date(day), 'yyyy-MM-dd')}"><span class="hidden md:inline-block">{format(new Date(day), 'eee ')}</span> {format(new Date(day), 'd')}</a>
|
||||
<div
|
||||
class="mb-1 uppercase {highlightDay && highlightDay !== day
|
||||
? 'text-gray-400 text-lg'
|
||||
: 'text-pbw-red text-lg'}"
|
||||
style="width: {1 / (days.length / 100)}%;"
|
||||
>
|
||||
<a href="/23/day/{format(new Date(day), 'yyyy-MM-dd')}"
|
||||
><span class="hidden md:inline-block">{format(new Date(day), 'eee ')}</span>
|
||||
{format(new Date(day), 'd')}</a
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -136,20 +167,28 @@
|
|||
{#each days as day, i}
|
||||
<div
|
||||
class="h-10 flex flex-grow hover:bg-pbw-yellow/20"
|
||||
style="width: {1/(days.length/100)}%; {(highlightDay && highlightDay === day ? "border: 1px solid rgb(255, 22, 22);" : (!highlightDay ? "border-right: 1px solid rgb(255, 22, 22);" : (days.length-i > 1 ? "border-right: 1px solid silver;" : "")))}"
|
||||
style="width: {1 / (days.length / 100)}%; {highlightDay && highlightDay === day
|
||||
? 'border: 1px solid rgb(255, 22, 22);'
|
||||
: !highlightDay
|
||||
? 'border-right: 1px solid rgb(255, 22, 22);'
|
||||
: days.length - i > 1
|
||||
? 'border-right: 1px solid silver;'
|
||||
: ''}"
|
||||
>
|
||||
{#each segments as segment}
|
||||
<div
|
||||
id="{day}-{segment}"
|
||||
data-events={timelineData[[day, segment].join(";")].events}
|
||||
data-score={timelineData[[day, segment].join(";")].score}
|
||||
data-events={timelineData[[day, segment].join(';')].events}
|
||||
data-score={timelineData[[day, segment].join(';')].score}
|
||||
class="md:hover:border md:hover:border-pbw-yellow flex-grow cursor-pointer"
|
||||
style="width: {1/(segments.length/50)}%; background-color: rgba({!highlightDay || highlightDay === day ? "255, 22, 22" : "115, 115, 115"}, {timelineData[[day, segment].join(";")].perc}%);"
|
||||
on:click={makeClick(day, segment, timelineData[[day, segment].join(";")])}
|
||||
on:mouseenter={makeSelected(day, segment, timelineData[[day, segment].join(";")])}
|
||||
style="width: {1 / (segments.length / 50)}%; background-color: rgba({!highlightDay ||
|
||||
highlightDay === day
|
||||
? '255, 22, 22'
|
||||
: '115, 115, 115'}, {timelineData[[day, segment].join(';')].perc}%);"
|
||||
on:click={makeClick(day, segment, timelineData[[day, segment].join(';')])}
|
||||
on:mouseenter={makeSelected(day, segment, timelineData[[day, segment].join(';')])}
|
||||
on:mouseleave={hiddenSelected}
|
||||
>
|
||||
</div>
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import localData from "$lib/data.json";
|
||||
import localData from '$lib/data.json';
|
||||
|
||||
export async function load(entry = "23", host = null) {
|
||||
export async function load(entry = '23', host = null) {
|
||||
let data = null;
|
||||
if (host === "localhost") {
|
||||
if (host === 'localhost') {
|
||||
data = localData;
|
||||
} else {
|
||||
const resp = await fetch(
|
||||
`https://data.prgblockweek.com/${entry}/index.json`,
|
||||
);
|
||||
const resp = await fetch(`https://data.prgblockweek.com/${entry}/index.json`);
|
||||
data = await resp.json();
|
||||
}
|
||||
data.events.sort((a, b) => (a.attendees || 0) < (b.attendees || 0) ? 1 : -1)
|
||||
data.events.sort((a, b) => ((a.attendees || 0) < (b.attendees || 0) ? 1 : -1));
|
||||
//console.log(data.events)
|
||||
data.speakers = [];
|
||||
for (const event of data.events) {
|
||||
|
@ -24,8 +22,6 @@ export async function load(entry = "23", host = null) {
|
|||
}
|
||||
|
||||
export async function loadSchema() {
|
||||
const resp = await fetch(
|
||||
"https://data.prgblockweek.com/schema/1/bundle.json",
|
||||
);
|
||||
const resp = await fetch('https://data.prgblockweek.com/schema/1/bundle.json');
|
||||
return resp.json();
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
export const config = {
|
||||
collections: {
|
||||
places: {
|
||||
title: "Places",
|
||||
model: "place",
|
||||
img: "photo"
|
||||
title: 'Places',
|
||||
model: 'place',
|
||||
img: 'photo'
|
||||
},
|
||||
events: {
|
||||
title: "Events",
|
||||
model: "event"
|
||||
title: 'Events',
|
||||
model: 'event'
|
||||
},
|
||||
speakers: {
|
||||
title: "Speakers",
|
||||
model: "speaker",
|
||||
img: "photoUrl"
|
||||
title: 'Speakers',
|
||||
model: 'speaker',
|
||||
img: 'photoUrl'
|
||||
},
|
||||
"media-partners": {
|
||||
title: "Media Partners & Communities",
|
||||
model: "media-partner",
|
||||
aspect: "aspect-video"
|
||||
'media-partners': {
|
||||
title: 'Media Partners & Communities',
|
||||
model: 'media-partner',
|
||||
aspect: 'aspect-video'
|
||||
},
|
||||
benefits: {
|
||||
title: "Benefits for visitors",
|
||||
model: "benefit"
|
||||
title: 'Benefits for visitors',
|
||||
model: 'benefit'
|
||||
},
|
||||
unions: {
|
||||
title: "Event Unions",
|
||||
model: "union"
|
||||
title: 'Event Unions',
|
||||
model: 'union'
|
||||
},
|
||||
chains: {
|
||||
title: "Blockchains",
|
||||
model: "chain"
|
||||
title: 'Blockchains',
|
||||
model: 'chain'
|
||||
}
|
||||
},
|
||||
eventTypeColors: {
|
||||
|
@ -39,6 +39,6 @@ export const config = {
|
|||
expo: '#eee0da',
|
||||
party: '#dbeddb'
|
||||
},
|
||||
date: "2023-06-02",
|
||||
days: 10,
|
||||
}
|
||||
date: '2023-06-02',
|
||||
days: 10
|
||||
};
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
|
||||
import { format, addDays } from 'date-fns';
|
||||
|
||||
const langMapper = {
|
||||
czech: 'cz',
|
||||
slovak: 'sk',
|
||||
english: 'gb'
|
||||
}
|
||||
};
|
||||
|
||||
export function formatItemDate (item, opts = {}) {
|
||||
let dt = format(new Date(item.date), "MMMM d" + (opts.full && item.days === 1 ? ', yyyy' : ''))
|
||||
export function formatItemDate(item, opts = {}) {
|
||||
let dt = format(new Date(item.date), 'MMMM d' + (opts.full && item.days === 1 ? ', yyyy' : ''));
|
||||
if (item.days > 1) {
|
||||
dt += "-" + format(addDays(new Date(item.date), item.days-1), "d"+ (opts.full ? ', yyyy' : ''))
|
||||
dt +=
|
||||
'-' + format(addDays(new Date(item.date), item.days - 1), 'd' + (opts.full ? ', yyyy' : ''));
|
||||
}
|
||||
return dt
|
||||
return dt;
|
||||
}
|
||||
|
||||
export function bareDomain (link, type="") {
|
||||
let out = link.replace(/https?:\/\/(twitter\.com\/|t\.me\/|www\.youtube\.com\/c\/|linkedin\.com\/in\/|www\.|)/g, '').replace(/\/$/, "")
|
||||
if ([ "twitter", "telegram", "youtube" ].includes(type)) {
|
||||
out = "@" + out
|
||||
export function bareDomain(link, type = '') {
|
||||
let out = link
|
||||
.replace(
|
||||
/https?:\/\/(twitter\.com\/|t\.me\/|www\.youtube\.com\/c\/|linkedin\.com\/in\/|www\.|)/g,
|
||||
''
|
||||
)
|
||||
.replace(/\/$/, '');
|
||||
if (['twitter', 'telegram', 'youtube'].includes(type)) {
|
||||
out = '@' + out;
|
||||
}
|
||||
return out
|
||||
return out;
|
||||
}
|
||||
|
||||
export function getFlagEmoji(str, mapper = true) {
|
||||
const codePoints = (mapper ? langMapper[str] : str)
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.map(char => 127397 + char.charCodeAt());
|
||||
.map((char) => 127397 + char.charCodeAt());
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import "../app.css";
|
||||
import '../app.css';
|
||||
|
||||
$: homepage = !$page.params.type && !$page.params.date && $page.route.id !== "/[entry]/schedule"
|
||||
$: homepage = !$page.params.type && !$page.params.date && $page.route.id !== '/[entry]/schedule';
|
||||
</script>
|
||||
|
||||
|
||||
{#if homepage}
|
||||
<div class="px-6 xl:px-0 dark:bg-pbw-dark">
|
||||
<div class="max-w-7xl mx-auto pt-10 pb-6">
|
||||
<h1 class="text-5xl uppercase font-bold text-pbw-red"><a href="https://prgblockweek.com">Prague Blockchain Week 2023</a></h1>
|
||||
<h1 class="text-5xl uppercase font-bold text-pbw-red">
|
||||
<a href="https://prgblockweek.com">Prague Blockchain Week 2023</a>
|
||||
</h1>
|
||||
<div class="text-4xl text-pbw-yellow">June 2-11, 2023</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { redirect } from "@sveltejs/kit";
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export function load() {
|
||||
throw redirect(302, "/23");
|
||||
throw redirect(302, '/23');
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
<title>Prague Blockchain Week | Explore</title>
|
||||
</svelte:head>
|
||||
|
||||
<div></div>
|
||||
<div />
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as dataApi from "$lib/dataApi";
|
||||
import * as dataApi from '$lib/dataApi';
|
||||
|
||||
export async function load({ params, url }) {
|
||||
return {
|
||||
params,
|
||||
bundle: await dataApi.load(params.entry, url.hostname),
|
||||
schema: await dataApi.loadSchema(),
|
||||
schema: await dataApi.loadSchema()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,20 +5,24 @@
|
|||
import { page } from '$app/stores';
|
||||
|
||||
export let data;
|
||||
$: entry = $page.params.entry
|
||||
$: conferences = data.bundle.events.filter(e => e.types.find(t => ['conference', 'hackathon'].includes(t)))
|
||||
$: otherEvents = data.bundle.events.filter(e => !e.types.find(t => ['conference', 'hackathon'].includes(t)))
|
||||
$: entry = $page.params.entry;
|
||||
$: conferences = data.bundle.events.filter((e) =>
|
||||
e.types.find((t) => ['conference', 'hackathon'].includes(t))
|
||||
);
|
||||
$: otherEvents = data.bundle.events.filter(
|
||||
(e) => !e.types.find((t) => ['conference', 'hackathon'].includes(t))
|
||||
);
|
||||
|
||||
const collections = [
|
||||
{ title: "Days", value: 10, col: "schedule" },
|
||||
{ title: "Events", col: "events" },
|
||||
{ title: "Speakers", col: "speakers" },
|
||||
{ title: "Places", col: "places" },
|
||||
{ title: "Media Partners", col: "media-partners" },
|
||||
{ title: 'Days', value: 10, col: 'schedule' },
|
||||
{ title: 'Events', col: 'events' },
|
||||
{ title: 'Speakers', col: 'speakers' },
|
||||
{ title: 'Places', col: 'places' },
|
||||
{ title: 'Media Partners', col: 'media-partners' },
|
||||
//{ title: "Blockchains", col: "chains" },
|
||||
//{ title: "Unions", col: "unions" },
|
||||
{ title: "Benefits", col: "benefits" },
|
||||
]
|
||||
{ title: 'Benefits', col: 'benefits' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -27,12 +31,14 @@
|
|||
|
||||
<div class="w-full px-6 xl:mx-0">
|
||||
<div class="max-w-7xl mx-auto pt-2">
|
||||
|
||||
<div class="flex flex-wrap gap-2 my-6 text-center text-2xl">
|
||||
{#each collections as cd}
|
||||
<a href="/{$page.params.entry}/{cd.col}">
|
||||
<button class="border rounded border-pbw-red hover:bg-pbw-red hover:text-white py-2 px-2 text-pbw-red">
|
||||
{cd.value || data.bundle[cd.col]?.length} {cd.title}
|
||||
<button
|
||||
class="border rounded border-pbw-red hover:bg-pbw-red hover:text-white py-2 px-2 text-pbw-red"
|
||||
>
|
||||
{cd.value || data.bundle[cd.col]?.length}
|
||||
{cd.title}
|
||||
</button>
|
||||
</a>
|
||||
{/each}
|
||||
|
@ -40,42 +46,103 @@
|
|||
|
||||
<TimelineHeatmap {data} />
|
||||
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500"><a href="/{entry}/events">Conferences & Hackathons</a> ({conferences.length})</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl">
|
||||
<CollectionList arr={conferences} img="logo" col="event" entry={entry} offer={true}/>
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">
|
||||
<a href="/{entry}/events">Conferences & Hackathons</a> ({conferences.length})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl"
|
||||
>
|
||||
<CollectionList arr={conferences} img="logo" col="event" {entry} offer={true} />
|
||||
</div>
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500"><a href="/{entry}/events">Other events</a> ({otherEvents.length})</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl">
|
||||
<CollectionList arr={otherEvents} img="logo" col="event" entry={entry} />
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">
|
||||
<a href="/{entry}/events">Other events</a> ({otherEvents.length})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl"
|
||||
>
|
||||
<CollectionList arr={otherEvents} img="logo" col="event" {entry} />
|
||||
</div>
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500"><a href="/{entry}/speakers">Speakers</a> ({data.bundle.speakers.length})</h2>
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
<a href="/{entry}/speakers">Speakers</a> ({data.bundle.speakers.length})
|
||||
</h2>
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">International 🌎</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 my-6 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.speakers.filter(s => !['cz', 'sk'].includes(s.country))} entry={entry} />
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 my-6 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.speakers.filter((s) => !['cz', 'sk'].includes(s.country))}
|
||||
{entry}
|
||||
/>
|
||||
</div>
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">Local - Czech 🇨🇿 & Slovak 🇸🇰 </h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 my-6 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.speakers.filter(s => ['cz', 'sk'].includes(s.country))} entry={entry} />
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">Local - Czech 🇨🇿 & Slovak 🇸🇰</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 my-6 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.speakers.filter((s) => ['cz', 'sk'].includes(s.country))}
|
||||
{entry}
|
||||
/>
|
||||
</div>
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500"><a href="/{entry}/places">Places</a> ({data.bundle.places.length})</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl">
|
||||
<CollectionList arr={data.bundle.places} col="place" img="photo" entry={entry} />
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
<a href="/{entry}/places">Places</a> ({data.bundle.places.length})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl"
|
||||
>
|
||||
<CollectionList arr={data.bundle.places} col="place" img="photo" {entry} />
|
||||
</div>
|
||||
{#if data.bundle.benefits}
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500"><a href="/{entry}/benefits">Benefits for visitors</a> ({data.bundle.benefits.length})</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-xl mb-8">
|
||||
<CollectionList arr={data.bundle.benefits} img="logo" col="benefit" entry={entry} aspect="aspect-[16/9]" offer={true}/>
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">
|
||||
<a href="/{entry}/benefits">Benefits for visitors</a> ({data.bundle.benefits.length})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-xl mb-8"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.benefits}
|
||||
img="logo"
|
||||
col="benefit"
|
||||
{entry}
|
||||
aspect="aspect-[16/9]"
|
||||
offer={true}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if data.bundle["media-partners"]}
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500"><a href="/{entry}/media-partners">Media Partners & Communities</a> ({data.bundle["media-partners"].length})</h2>
|
||||
{#if data.bundle['media-partners']}
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">
|
||||
<a href="/{entry}/media-partners">Media Partners & Communities</a> ({data.bundle[
|
||||
'media-partners'
|
||||
].length})
|
||||
</h2>
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">International 🌎</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-7 xl:grid-cols-9 my-6 text-center text-2xl mb-8">
|
||||
<CollectionList arr={data.bundle["media-partners"].filter(m => !['czech', 'slovak'].includes(m.languages[0]))} img="logo" col="media-partner" entry={entry} aspect="aspect-[16/9]" size="small" />
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-7 xl:grid-cols-9 my-6 text-center text-2xl mb-8"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle['media-partners'].filter(
|
||||
(m) => !['czech', 'slovak'].includes(m.languages[0])
|
||||
)}
|
||||
img="logo"
|
||||
col="media-partner"
|
||||
{entry}
|
||||
aspect="aspect-[16/9]"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">Local - Czech 🇨🇿 & Slovak 🇸🇰 </h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-7 xl:grid-cols-9 my-6 text-center text-2xl mb-8">
|
||||
<CollectionList arr={data.bundle["media-partners"].filter(m => ['czech', 'slovak'].includes(m.languages[0]))} img="logo" col="media-partner" entry={entry} aspect="aspect-[16/9]" size="small" />
|
||||
<h2 class="text-xl uppercase font-bold mt-10 text-gray-500">Local - Czech 🇨🇿 & Slovak 🇸🇰</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-7 xl:grid-cols-9 my-6 text-center text-2xl mb-8"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle['media-partners'].filter((m) =>
|
||||
['czech', 'slovak'].includes(m.languages[0])
|
||||
)}
|
||||
img="logo"
|
||||
col="media-partner"
|
||||
{entry}
|
||||
aspect="aspect-[16/9]"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<!--h2 class="text-2xl uppercase font-bold text-gray-500">Unions ({data.bundle.unions.length})</h2>
|
||||
|
|
|
@ -17,42 +17,45 @@
|
|||
|
||||
export let data;
|
||||
|
||||
let entry = $page.params.entry
|
||||
let entry = $page.params.entry;
|
||||
$: type = $page.params.type;
|
||||
$: tc = config.collections[type]
|
||||
$: items = data.bundle[type]
|
||||
$: tc = config.collections[type];
|
||||
$: items = data.bundle[type];
|
||||
|
||||
function processItems(_items, query = {}) {
|
||||
if (!_items) return [];
|
||||
_items = JSON.parse(JSON.stringify(_items))
|
||||
_items = JSON.parse(JSON.stringify(_items));
|
||||
if (type === 'events') {
|
||||
_items = _items.sort((x, y) => x.date > y.date ? 1 : -1)
|
||||
_items = _items.sort((x, y) => (x.date > y.date ? 1 : -1));
|
||||
}
|
||||
if (type === 'events' && query.start && query.end) {
|
||||
_items = _items.filter(item => {
|
||||
return item.segments.find(sgm => {
|
||||
const [ tstart, tend ] = sgm.times.split("-")
|
||||
return compareAsc(new Date(sgm.startTime), new Date(query.start)) <= 0
|
||||
&& compareAsc(new Date(sgm.endTime), new Date(query.end)) >= 0
|
||||
})
|
||||
_items = _items.filter((item) => {
|
||||
return item.segments.find((sgm) => {
|
||||
const [tstart, tend] = sgm.times.split('-');
|
||||
return (
|
||||
compareAsc(new Date(sgm.startTime), new Date(query.start)) <= 0 &&
|
||||
compareAsc(new Date(sgm.endTime), new Date(query.end)) >= 0
|
||||
);
|
||||
});
|
||||
// return compareAsc(item.new Date(query.segment) > 0)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return _items
|
||||
return _items;
|
||||
}
|
||||
|
||||
$: processedItems = processItems(items) //, Object.fromEntries($page.url.searchParams))
|
||||
$: processedItems = processItems(items); //, Object.fromEntries($page.url.searchParams))
|
||||
|
||||
onMount(async () => {
|
||||
if (!config.collections[$page.params.type]) {
|
||||
const ftype = Object.keys(config.collections).find(k => config.collections[k].model === $page.params.type)
|
||||
const ftype = Object.keys(config.collections).find(
|
||||
(k) => config.collections[k].model === $page.params.type
|
||||
);
|
||||
if (ftype) {
|
||||
goto(`/${$page.params.entry}/${ftype}`)
|
||||
goto(`/${$page.params.entry}/${ftype}`);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -60,43 +63,49 @@
|
|||
</svelte:head>
|
||||
|
||||
{#if tc}
|
||||
<div class="w-full">
|
||||
<div class="w-full">
|
||||
<div class="max-w-7xl mx-auto pt-5 md:pt-10">
|
||||
<div class="mx-4 xl:mx-0">
|
||||
<div class="flex gap-8 mb-6 md:mb-10">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red"><a href="/{$page.params.entry}">#PBW23</a><span class="text-pbw-yellow">.{$page.params.type}</span></h1>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red">
|
||||
<a href="/{$page.params.entry}">#PBW23</a><span class="text-pbw-yellow"
|
||||
>.{$page.params.type}</span
|
||||
>
|
||||
</h1>
|
||||
</div>
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">{tc.title} ({processedItems.length})</h2>
|
||||
<h2 class="text-2xl uppercase font-bold text-gray-500">
|
||||
{tc.title} ({processedItems.length})
|
||||
</h2>
|
||||
<div class="text-xl mt-6 text-gray-800 dark:text-gray-400">
|
||||
<table class="w-full table-auto">
|
||||
<thead>
|
||||
<tr class="text-left">
|
||||
{#if type === 'events'}
|
||||
<th class="text-right pr-4">📅</th>
|
||||
<th></th>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
<th class="hidden md:table-cell">📍</th>
|
||||
<th class="hidden md:table-cell">👥</th>
|
||||
{/if}
|
||||
{#if type === 'speakers'}
|
||||
<th></th>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
<th>🌎</th>
|
||||
<th class="hidden md:table-cell">🐦</th>
|
||||
<th class="hidden md:table-cell">Bio</th>
|
||||
{/if}
|
||||
{#if type === 'media-partners'}
|
||||
<th></th>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
<th>🌎</th>
|
||||
<th class="hidden md:table-cell">Description</th>
|
||||
{/if}
|
||||
{#if type === 'benefits'}
|
||||
<th></th>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
{/if}
|
||||
{#if type === 'places'}
|
||||
<th></th>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
<th>👥</th>
|
||||
<th class="hidden md:table-cell">Address</th>
|
||||
|
@ -107,14 +116,20 @@
|
|||
{#each processedItems as item}
|
||||
<tr class="hover:bg-pbw-yellow/20 dark:hover:bg-pbw-white/10">
|
||||
{#if type === 'events'}
|
||||
<td class="text-right pr-2 md:pr-4 text-base md:text-xl">{formatItemDate(item)}</td>
|
||||
<td class="text-right pr-2 md:pr-4 text-base md:text-xl"
|
||||
>{formatItemDate(item)}</td
|
||||
>
|
||||
<td class="w-12 md:w-14">
|
||||
<a href="/{entry}/{tc.model}/{item.id}">
|
||||
<ItemLogo {item} />
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-lg md:text-2xl flex items-center h-12">
|
||||
<div class=""><a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline">{item.name}</a></div>
|
||||
<div class="">
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline"
|
||||
>{item.name}</a
|
||||
>
|
||||
</div>
|
||||
<div class="gap-1 items-center ml-4 hidden md:flex">
|
||||
{#each item.types as type}
|
||||
<EventTypeBadge {type} />
|
||||
|
@ -123,19 +138,26 @@
|
|||
</td>
|
||||
<td class="hidden md:table-cell">
|
||||
{#if item.venues}
|
||||
{@html item.venues.map(vId => {
|
||||
const place = data.bundle.places.find(p => p.id === vId)
|
||||
return `<a href="/${$page.params.entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`
|
||||
}).join(", ")}
|
||||
{@html item.venues
|
||||
.map((vId) => {
|
||||
const place = data.bundle.places.find((p) => p.id === vId);
|
||||
return `<a href="/${$page.params.entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`;
|
||||
})
|
||||
.join(', ')}
|
||||
{:else if item.venueName}
|
||||
{#if item.venueUrl}
|
||||
<a href={item.venueUrl} class="underline hover:no-underline external">{item.venueName}</a>
|
||||
{:else}
|
||||
{#if item.venueName && item.venueName !== "TBA"}{item.venueName}{:else}<span class="opacity-50">TBA</span>{/if}
|
||||
{/if}
|
||||
<a href={item.venueUrl} class="underline hover:no-underline external"
|
||||
>{item.venueName}</a
|
||||
>
|
||||
{:else if item.venueName && item.venueName !== 'TBA'}{item.venueName}{:else}<span
|
||||
class="opacity-50">TBA</span
|
||||
>{/if}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="hidden md:table-cell">{#if item.attendees}{item.attendees}{:else}<span class="opacity-50">TBA</span>{/if}</td>
|
||||
<td class="hidden md:table-cell"
|
||||
>{#if item.attendees}{item.attendees}{:else}<span class="opacity-50">TBA</span
|
||||
>{/if}</td
|
||||
>
|
||||
<td class="hidden md:table-cell">
|
||||
{#if item.languages && item.languages.length > 0}
|
||||
<div class="flex gap-1">
|
||||
|
@ -153,12 +175,21 @@
|
|||
</a>
|
||||
</td>
|
||||
<td class="text-2xl h-12">
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline">{item.name}</a>
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline"
|
||||
>{item.name}</a
|
||||
>
|
||||
</td>
|
||||
<td>{item.country && item.country !== 'xx' ? getFlagEmoji(item.country, false) : ''}</td>
|
||||
<td
|
||||
>{item.country && item.country !== 'xx'
|
||||
? getFlagEmoji(item.country, false)
|
||||
: ''}</td
|
||||
>
|
||||
<td class="hidden md:table-cell">
|
||||
{#if item.twitter}
|
||||
@<a href="https://twitter.com/{item.twitter}" class="underline hover:no-underline">{item.twitter}</a>
|
||||
@<a
|
||||
href="https://twitter.com/{item.twitter}"
|
||||
class="underline hover:no-underline">{item.twitter}</a
|
||||
>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="hidden md:table-cell"><SvelteMarkdown source={item.caption} /></td>
|
||||
|
@ -170,7 +201,9 @@
|
|||
</a>
|
||||
</td>
|
||||
<td class="text-2xl h-12">
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline">{item.name}</a>
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline"
|
||||
>{item.name}</a
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
{#if item.languages && item.languages.length > 0}
|
||||
|
@ -192,7 +225,9 @@
|
|||
</a>
|
||||
</td>
|
||||
<td class="text-2xl h-12">
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline">{item.name}</a>
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline"
|
||||
>{item.name}</a
|
||||
>
|
||||
</td>
|
||||
{/if}
|
||||
{#if type === 'places'}
|
||||
|
@ -202,7 +237,9 @@
|
|||
</a>
|
||||
</td>
|
||||
<td class="text-2xl h-12">
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline">{item.name}</a>
|
||||
<a href="/{entry}/{tc.model}/{item.id}" class="text-pbw-red hover:underline"
|
||||
>{item.name}</a
|
||||
>
|
||||
</td>
|
||||
<td>{item.capacity}</td>
|
||||
<td class="hidden md:table-cell">{item.address}</td>
|
||||
|
@ -215,5 +252,5 @@
|
|||
<Footer bundle={data.bundle} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
|
@ -11,30 +11,34 @@
|
|||
import { config } from '$lib/pbw';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
const colsDef = Object.fromEntries(Object.keys(config.collections).map(col => { return [ config.collections[col].model, col ]}))
|
||||
const colsDef = Object.fromEntries(
|
||||
Object.keys(config.collections).map((col) => {
|
||||
return [config.collections[col].model, col];
|
||||
})
|
||||
);
|
||||
|
||||
const speakerLinks = {
|
||||
twitter: { col: x => x.twitter ? 'https://twitter.com/'+x.twitter : null },
|
||||
web: { col: x => x.web?.url },
|
||||
linkedin: { col: x => x.linkedin ? 'https://linkedin.com/in/'+x.linkedin : null }
|
||||
}
|
||||
twitter: { col: (x) => (x.twitter ? 'https://twitter.com/' + x.twitter : null) },
|
||||
web: { col: (x) => x.web?.url },
|
||||
linkedin: { col: (x) => (x.linkedin ? 'https://linkedin.com/in/' + x.linkedin : null) }
|
||||
};
|
||||
|
||||
function eventDates(event) {
|
||||
const dates = []
|
||||
const dates = [];
|
||||
for (const seg of event.segments) {
|
||||
const date = format(new Date(seg.startTime), 'yyyy-MM-dd')
|
||||
const date = format(new Date(seg.startTime), 'yyyy-MM-dd');
|
||||
if (!dates.includes(date)) {
|
||||
dates.push(date)
|
||||
dates.push(date);
|
||||
}
|
||||
}
|
||||
return dates
|
||||
return dates;
|
||||
}
|
||||
|
||||
$: entry = $page.params.entry
|
||||
$: col = $page.params.type
|
||||
$: colPlural = colsDef[col]
|
||||
$: item = data.bundle[colPlural].find(e => e.id === $page.params.slug)
|
||||
$: defs = data.schema ? data.schema.definitions[col] : {}
|
||||
$: entry = $page.params.entry;
|
||||
$: col = $page.params.type;
|
||||
$: colPlural = colsDef[col];
|
||||
$: item = data.bundle[colPlural].find((e) => e.id === $page.params.slug);
|
||||
$: defs = data.schema ? data.schema.definitions[col] : {};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -46,12 +50,20 @@
|
|||
<div class="mx-4 xl:mx-0">
|
||||
<div class="flex gap-8 mb-6 md:mb-10">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red">
|
||||
<a href="/{$page.params.entry}">#PBW23</a><a href="/{$page.params.entry}/{colsDef[$page.params.type]}"><span class="text-pbw-yellow">.{$page.params.type}</span></a>
|
||||
<a href="/{$page.params.entry}">#PBW23</a><a
|
||||
href="/{$page.params.entry}/{colsDef[$page.params.type]}"
|
||||
><span class="text-pbw-yellow">.{$page.params.type}</span></a
|
||||
>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex flex-wrap md:flex-nowrap w-full">
|
||||
|
||||
<ItemLogo {item} img={config.collections[colPlural]?.img || 'logo'} aspect={config[col]?.aspect || 'aspect-square'} width="w-48 md:w-56 mr-5" rounded="rounded-xl"/>
|
||||
<ItemLogo
|
||||
{item}
|
||||
img={config.collections[colPlural]?.img || 'logo'}
|
||||
aspect={config[col]?.aspect || 'aspect-square'}
|
||||
width="w-48 md:w-56 mr-5"
|
||||
rounded="rounded-xl"
|
||||
/>
|
||||
<div class="flex-grow">
|
||||
<!--div class="font-normal text opacity-50 mt-4 md:mt-0 mb-1" style="line-height: 0.6em;"><a href="/{entry}/{col}">{col.toUpperCase()}</a></div-->
|
||||
<h2 class="text-4xl md:text-5xl font-bold text-gray-600 dark:text-gray-400 mt-4 md:mt-0">
|
||||
|
@ -65,14 +77,21 @@
|
|||
{/each}
|
||||
</div>
|
||||
<div class="">{formatItemDate(item, { full: true })}</div>
|
||||
<div>📍
|
||||
<div>
|
||||
📍
|
||||
{#if item.venues}
|
||||
{@html item.venues.map(vId => {
|
||||
const place = data.bundle.places.find(p => p.id === vId)
|
||||
return `<a href="/${$page.params.entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`
|
||||
}).join(", ")}
|
||||
{@html item.venues
|
||||
.map((vId) => {
|
||||
const place = data.bundle.places.find((p) => p.id === vId);
|
||||
return `<a href="/${$page.params.entry}/place/${place.id}" class=\"underline hover:no-underline\">${place.name}</a>`;
|
||||
})
|
||||
.join(', ')}
|
||||
{:else if item.venueUrl}
|
||||
<a href="{item.venueUrl}" target="_blank" class="underline hover:no-underline external">{item.venueName}</a>
|
||||
<a
|
||||
href={item.venueUrl}
|
||||
target="_blank"
|
||||
class="underline hover:no-underline external">{item.venueName}</a
|
||||
>
|
||||
{:else}
|
||||
{item.venueName}
|
||||
{/if}
|
||||
|
@ -89,7 +108,15 @@
|
|||
<div class="flex flex-wrap gap-4 mt-4 text-xl">
|
||||
{#each Object.keys(speakerLinks) as lk}
|
||||
{#if speakerLinks[lk].col(item)}
|
||||
<div><span class="opacity-40 text-sm uppercase">{lk} →</span> <a href={speakerLinks[lk].col(item)} target="_blank" class="underline hover:no-underline">{bareDomain(speakerLinks[lk].col(item), lk)}</a></div>
|
||||
<div>
|
||||
<span class="opacity-40 text-sm uppercase">{lk} →</span>
|
||||
<a
|
||||
href={speakerLinks[lk].col(item)}
|
||||
target="_blank"
|
||||
class="underline hover:no-underline"
|
||||
>{bareDomain(speakerLinks[lk].col(item), lk)}</a
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -100,18 +127,19 @@
|
|||
<div>
|
||||
<div class="uppercase text-sm opacity-40">Chains</div>
|
||||
<div class="flex gap-2">
|
||||
{#each item.chains.map(chId => {
|
||||
const chItem = data.bundle.chains.find(x => x.id === chId)
|
||||
{#each item.chains.map((chId) => {
|
||||
const chItem = data.bundle.chains.find((x) => x.id === chId);
|
||||
if (!chItem) {
|
||||
return {
|
||||
name: chain.substr(0, 1).toUpperCase() + chain.substr(1)
|
||||
return { name: chain.substr(0, 1).toUpperCase() + chain.substr(1) };
|
||||
}
|
||||
}
|
||||
return chItem
|
||||
return chItem;
|
||||
}) as chain}
|
||||
<div class="flex items-center">
|
||||
{#if chain.id}
|
||||
<a href="/{entry}/chain/{chain.id}" class="flex items-center underline hover:no-underline">
|
||||
<a
|
||||
href="/{entry}/chain/{chain.id}"
|
||||
class="flex items-center underline hover:no-underline"
|
||||
>
|
||||
{#if chain.logo}
|
||||
<ItemLogo item={chain} width="w-5 h-5 mr-1" />
|
||||
{/if}
|
||||
|
@ -145,9 +173,15 @@
|
|||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div><div class="uppercase text-sm opacity-40">Organizator</div><div class="markdown"><SvelteMarkdown source={item.org || 'TBD'} /></div></div>
|
||||
<div>
|
||||
<div class="uppercase text-sm opacity-40">Organizator</div>
|
||||
<div class="markdown"><SvelteMarkdown source={item.org || 'TBD'} /></div>
|
||||
</div>
|
||||
{#if item.poc}
|
||||
<div><div class="uppercase text-sm opacity-40">Point of contact</div><div class="markdown"><SvelteMarkdown source={item.poc} /></div></div>
|
||||
<div>
|
||||
<div class="uppercase text-sm opacity-40">Point of contact</div>
|
||||
<div class="markdown"><SvelteMarkdown source={item.poc} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -184,7 +218,12 @@
|
|||
{#if item.links}
|
||||
<div class="flex flex-wrap gap-4 mt-4 text-xl">
|
||||
{#each Object.keys(item.links) as lk}
|
||||
<div><span class="opacity-40 text-sm uppercase">{lk} →</span> <a href={item.links[lk]} target="_blank" class="underline hover:no-underline">{bareDomain(item.links[lk], lk)}</a></div>
|
||||
<div>
|
||||
<span class="opacity-40 text-sm uppercase">{lk} →</span>
|
||||
<a href={item.links[lk]} target="_blank" class="underline hover:no-underline"
|
||||
>{bareDomain(item.links[lk], lk)}</a
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -196,7 +235,9 @@
|
|||
{#if item.registration.link}
|
||||
<div class="pb-2">
|
||||
<a href={item.registration.link} class="" target="_blank">
|
||||
<div class="inline-block py-3 px-6 border border-pbw-red hover:bg-pbw-red hover:text-white text-pbw-red text-xl rounded-lg">
|
||||
<div
|
||||
class="inline-block py-3 px-6 border border-pbw-red hover:bg-pbw-red hover:text-white text-pbw-red text-xl rounded-lg"
|
||||
>
|
||||
{#if item.registration.button}
|
||||
{item.registration.button}
|
||||
{:else if item.registration.type === 'tickets'}
|
||||
|
@ -208,7 +249,9 @@
|
|||
</a>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="inline-block py-2 px-4 border border-gray-400 text-gray-400 text-lg rounded-lg mb-2 cursor-not-allowed">
|
||||
<div
|
||||
class="inline-block py-2 px-4 border border-gray-400 text-gray-400 text-lg rounded-lg mb-2 cursor-not-allowed"
|
||||
>
|
||||
{#if item.registration.type === 'tickets'}
|
||||
Tickets not yet available
|
||||
{:else if item.registration.type === 'invites'}
|
||||
|
@ -218,7 +261,8 @@
|
|||
{/if}
|
||||
<div>
|
||||
{#if item.registration.status}
|
||||
<div><span class="opacity-40 text-sm uppercase mr-1">Status</span>
|
||||
<div>
|
||||
<span class="opacity-40 text-sm uppercase mr-1">Status</span>
|
||||
{#if item.registration.status === 'available'}
|
||||
<span class="text-green-700">• Available</span>
|
||||
{:else if item.registration.status === 'sold-out'}
|
||||
|
@ -228,7 +272,8 @@
|
|||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div><span class="opacity-40 text-sm uppercase mr-1">Price</span>
|
||||
<div>
|
||||
<span class="opacity-40 text-sm uppercase mr-1">Price</span>
|
||||
{#if item.registration.type === 'tickets'}
|
||||
{item.registration.price || 'TBA'}
|
||||
{:else}
|
||||
|
@ -247,7 +292,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{#if col === "event"}
|
||||
{#if col === 'event'}
|
||||
{#if item.tracks}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Tracks</h2>
|
||||
<div class="flex flex-wrap gap-2 mt-4">
|
||||
|
@ -263,58 +308,116 @@
|
|||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Schedule</h2>
|
||||
{#each eventDates(item) as date}
|
||||
<div class="mb-6">
|
||||
<h3 class="mt-4 text-xl uppercase text-gray-500"><a href="/{entry}/day/{date}">{format(new Date(date), "EEEE - MMMM d, yyyy")}</a></h3>
|
||||
<h3 class="mt-4 text-xl uppercase text-gray-500">
|
||||
<a href="/{entry}/day/{date}">{format(new Date(date), 'EEEE - MMMM d, yyyy')}</a>
|
||||
</h3>
|
||||
<div class="mt-4">
|
||||
<CalendarList date={date} segments={item.segments.filter(s => s.startTime.match(new RegExp("^"+date)))} entry={entry} bundle={data.bundle} event={item} />
|
||||
<CalendarList
|
||||
{date}
|
||||
segments={item.segments.filter((s) => s.startTime.match(new RegExp('^' + date)))}
|
||||
{entry}
|
||||
bundle={data.bundle}
|
||||
event={item}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{#if item.speakers}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Speakers ({item.speakers?.length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Speakers ({item.speakers?.length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl"
|
||||
>
|
||||
<CollectionList arr={item.speakers} bundle={data.bundle} currentItem={item} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if item.events}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Sub-Events ({item.events?.length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center">
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Sub-Events ({item.events?.length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center"
|
||||
>
|
||||
<CollectionList arr={item.events} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if item.venues}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Venues ({item.venues?.length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.places.filter(p => item.venues.includes(p.id))} col="place" img="photo" />
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Venues ({item.venues?.length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.places.filter((p) => item.venues.includes(p.id))}
|
||||
col="place"
|
||||
img="photo"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if col === "union"}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Big events ({item.events?.map(eId => data.bundle.events.find(e => e.id === eId)).length})</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 mt-4 text-2xl text-center">
|
||||
<CollectionList arr={item.events?.map(eId => data.bundle.events.find(e => e.id === eId))} col="event" img="logo" />
|
||||
{#if col === 'union'}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Big events ({item.events?.map((eId) => data.bundle.events.find((e) => e.id === eId))
|
||||
.length})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 mt-4 text-2xl text-center"
|
||||
>
|
||||
<CollectionList
|
||||
arr={item.events?.map((eId) => data.bundle.events.find((e) => e.id === eId))}
|
||||
col="event"
|
||||
img="logo"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "speaker"}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Events ({data.bundle.events.filter(e => e.speakers?.find(s => s.id === item.id)).length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.events.filter(e => e.speakers?.find(s => s.id === item.id))} col="event" img="logo" />
|
||||
{#if col === 'speaker'}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Events ({data.bundle.events.filter((e) => e.speakers?.find((s) => s.id === item.id))
|
||||
.length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.events.filter((e) => e.speakers?.find((s) => s.id === item.id))}
|
||||
col="event"
|
||||
img="logo"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "place"}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Events ({data.bundle.events.filter(e => e.venues?.includes(item.id)).length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.events.filter(e => e.venues?.includes(item.id))} col="event" img="logo" />
|
||||
{#if col === 'place'}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Events ({data.bundle.events.filter((e) => e.venues?.includes(item.id)).length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.events.filter((e) => e.venues?.includes(item.id))}
|
||||
col="event"
|
||||
img="logo"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if col === "chain"}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Events ({data.bundle.events.filter(e => e.chains?.includes(item.id)).length || 0})</h2>
|
||||
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||
<CollectionList arr={data.bundle.events.filter(e => e.chains?.includes(item.id))} col="event" img="logo" />
|
||||
{#if col === 'chain'}
|
||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">
|
||||
Events ({data.bundle.events.filter((e) => e.chains?.includes(item.id)).length || 0})
|
||||
</h2>
|
||||
<div
|
||||
class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl"
|
||||
>
|
||||
<CollectionList
|
||||
arr={data.bundle.events.filter((e) => e.chains?.includes(item.id))}
|
||||
col="event"
|
||||
img="logo"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Footer col={col} item={item} bundle={data.bundle} />
|
||||
<Footer {col} {item} bundle={data.bundle} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -8,16 +8,20 @@
|
|||
|
||||
export let data;
|
||||
|
||||
function makeSegments (events, date) {
|
||||
function makeSegments(events, date) {
|
||||
const query = {
|
||||
start: date+"T00:00",
|
||||
end: date+"T23:59"
|
||||
}
|
||||
let arr = []
|
||||
start: date + 'T00:00',
|
||||
end: date + 'T23:59'
|
||||
};
|
||||
let arr = [];
|
||||
for (const ev of events) {
|
||||
for (const sg of ev.segments) {
|
||||
if (!(compareAsc(new Date(sg.startTime), new Date(query.end)) <= 0
|
||||
&& compareAsc(new Date(sg.startTime), new Date(query.start)) >= 0)) {
|
||||
if (
|
||||
!(
|
||||
compareAsc(new Date(sg.startTime), new Date(query.end)) <= 0 &&
|
||||
compareAsc(new Date(sg.startTime), new Date(query.start)) >= 0
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -26,33 +30,46 @@
|
|||
endTime: sg.endTime,
|
||||
event: ev,
|
||||
title: sg.title,
|
||||
venues: sg.venues || ev.venues || false,
|
||||
})
|
||||
venues: sg.venues || ev.venues || false
|
||||
});
|
||||
}
|
||||
}
|
||||
return arr.sort((x, y) => {
|
||||
return x.startTime > y.startTime ? 1 : -1
|
||||
})
|
||||
return x.startTime > y.startTime ? 1 : -1;
|
||||
});
|
||||
}
|
||||
|
||||
$: segments = makeSegments(data.bundle.events, $page.params.date)
|
||||
$: segments = makeSegments(data.bundle.events, $page.params.date);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{format(new Date($page.params.date), "EEEE MMMM d, yyyy")} | #PBW{$page.params.entry} Explore</title>
|
||||
<title
|
||||
>{format(new Date($page.params.date), 'EEEE MMMM d, yyyy')} | #PBW{$page.params.entry} Explore</title
|
||||
>
|
||||
</svelte:head>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="max-w-7xl mx-auto pt-5 md:pt-10">
|
||||
<div class="mx-4 xl:mx-0">
|
||||
<div class="flex gap-8 mb-6 md:mb-10">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red"><a href="/{$page.params.entry}">#PBW23</a><a href="/{$page.params.entry}/schedule"><span class="text-pbw-yellow">.day</span></a></h1>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red">
|
||||
<a href="/{$page.params.entry}">#PBW23</a><a href="/{$page.params.entry}/schedule"
|
||||
><span class="text-pbw-yellow">.day</span></a
|
||||
>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<TimelineHeatmap {data} highlightDay={$page.params.date} />
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-600">{format(new Date($page.params.date), "MMMM d, yyyy - EEEE")}</h2>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-600">
|
||||
{format(new Date($page.params.date), 'MMMM d, yyyy - EEEE')}
|
||||
</h2>
|
||||
<div class="mt-10">
|
||||
<CalendarList date={$page.params.date} segments={segments} entry={$page.params.entry} bundle={data.bundle} />
|
||||
<CalendarList
|
||||
date={$page.params.date}
|
||||
{segments}
|
||||
entry={$page.params.entry}
|
||||
bundle={data.bundle}
|
||||
/>
|
||||
</div>
|
||||
<Footer bundle={data.bundle} />
|
||||
</div>
|
||||
|
|
|
@ -9,20 +9,24 @@
|
|||
|
||||
export let data;
|
||||
|
||||
function makeDaysSegments (events) {
|
||||
const days = []
|
||||
function makeDaysSegments(events) {
|
||||
const days = [];
|
||||
for (let i = 0; i < config.days; i++) {
|
||||
const date = format(addDays(new Date(config.date), i), "yyyy-MM-dd")
|
||||
const date = format(addDays(new Date(config.date), i), 'yyyy-MM-dd');
|
||||
//console.log(date)
|
||||
const query = {
|
||||
start: date+"T00:00",
|
||||
end: date+"T23:59"
|
||||
}
|
||||
let arr = []
|
||||
start: date + 'T00:00',
|
||||
end: date + 'T23:59'
|
||||
};
|
||||
let arr = [];
|
||||
for (const ev of events) {
|
||||
for (const sg of ev.segments) {
|
||||
if (!(compareAsc(new Date(sg.startTime), new Date(query.end)) <= 0
|
||||
&& compareAsc(new Date(sg.startTime), new Date(query.start)) >= 0)) {
|
||||
if (
|
||||
!(
|
||||
compareAsc(new Date(sg.startTime), new Date(query.end)) <= 0 &&
|
||||
compareAsc(new Date(sg.startTime), new Date(query.start)) >= 0
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -31,19 +35,19 @@
|
|||
endTime: sg.endTime,
|
||||
event: ev,
|
||||
title: sg.title,
|
||||
venues: sg.venues || ev.venues || false,
|
||||
})
|
||||
venues: sg.venues || ev.venues || false
|
||||
});
|
||||
}
|
||||
}
|
||||
arr = arr.sort((x, y) => {
|
||||
return x.startTime > y.startTime ? 1 : -1
|
||||
})
|
||||
days.push({ date, segments: arr })
|
||||
return x.startTime > y.startTime ? 1 : -1;
|
||||
});
|
||||
days.push({ date, segments: arr });
|
||||
}
|
||||
return days
|
||||
return days;
|
||||
}
|
||||
|
||||
$: days = makeDaysSegments(data.bundle.events)
|
||||
$: days = makeDaysSegments(data.bundle.events);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -54,15 +58,27 @@
|
|||
<div class="max-w-7xl mx-auto pt-5 md:pt-10">
|
||||
<div class="mx-4 xl:mx-0">
|
||||
<div class="flex gap-8 mb-6 md:mb-10">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red"><a href="/{$page.params.entry}">#PBW23</a><span class="text-pbw-yellow">.schedule</span></h1>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-pbw-red">
|
||||
<a href="/{$page.params.entry}">#PBW23</a><span class="text-pbw-yellow">.schedule</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<TimelineHeatmap {data} highlightDay={$page.params.date} />
|
||||
{#each days as day}
|
||||
<div class="mb-14">
|
||||
<h2 class="text-3xl md:text-3xl"><a href="/{$page.params.entry}/day/{day.date}" class=" text-pbw-red hover:underline">{format(new Date(day.date), "MMMM d, yyyy")}</a> - {format(new Date(day.date), "EEEE")}</h2>
|
||||
<h2 class="text-3xl md:text-3xl">
|
||||
<a href="/{$page.params.entry}/day/{day.date}" class=" text-pbw-red hover:underline"
|
||||
>{format(new Date(day.date), 'MMMM d, yyyy')}</a
|
||||
>
|
||||
- {format(new Date(day.date), 'EEEE')}
|
||||
</h2>
|
||||
<div class="mt-6">
|
||||
<CalendarList date={$page.params.date} segments={day.segments} entry={$page.params.entry} bundle={data.bundle} />
|
||||
<CalendarList
|
||||
date={$page.params.date}
|
||||
segments={day.segments}
|
||||
entry={$page.params.entry}
|
||||
bundle={data.bundle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import adapter from "@sveltejs/adapter-static";
|
||||
import { vitePreprocess } from "@sveltejs/kit/vite";
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
adapter: adapter()
|
||||
},
|
||||
preprocess: vitePreprocess(),
|
||||
preprocess: vitePreprocess()
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
"sans": ["Barlow Semi Condensed", ...defaultTheme.fontFamily.sans],
|
||||
sans: ['Barlow Semi Condensed', ...defaultTheme.fontFamily.sans]
|
||||
},
|
||||
colors: {
|
||||
"pbw": {
|
||||
"red": "#ff1616",
|
||||
"yellow": "#ffde59",
|
||||
"white": "#ffffff",
|
||||
"dark": "#252525"
|
||||
},
|
||||
},
|
||||
},
|
||||
pbw: {
|
||||
red: '#ff1616',
|
||||
yellow: '#ffde59',
|
||||
white: '#ffffff',
|
||||
dark: '#252525'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
darkMode: 'class',
|
||||
plugins: []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test("index page has expected h1", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
expect(await page.textContent("h1")).toBe("Welcome to SvelteKit");
|
||||
test('index page has expected h1', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import pkg from "./package.json" assert { type: 'json'};
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import pkg from './package.json' assert { type: 'json' };
|
||||
|
||||
const config = {
|
||||
plugins: [sveltekit()],
|
||||
|
|
Načítá se…
Odkázat v novém úkolu