Rework item details
This commit is contained in:
rodič
86516c6b4f
revize
c784b062aa
|
@ -6,16 +6,8 @@
|
||||||
export let aspect = "aspect-square";
|
export let aspect = "aspect-square";
|
||||||
export let size = "normal";
|
export let size = "normal";
|
||||||
|
|
||||||
import { format, addDays } from 'date-fns';
|
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
import SvelteMarkdown from 'svelte-markdown';
|
||||||
|
import { formatItemDate } from '$lib/utils.js';
|
||||||
function formateItemDate (item) {
|
|
||||||
let dt = format(new Date(item.date), "MMMM d")
|
|
||||||
if (item.days > 1) {
|
|
||||||
dt += "-" + format(addDays(new Date(item.date), item.days-1), "d")
|
|
||||||
}
|
|
||||||
return dt
|
|
||||||
}
|
|
||||||
|
|
||||||
const _url = (col, item) => `/${entry}/${col}/${item.id}`
|
const _url = (col, item) => `/${entry}/${col}/${item.id}`
|
||||||
</script>
|
</script>
|
||||||
|
@ -39,7 +31,7 @@
|
||||||
<h3 class=" text-pbw-red"><a href={_url(col, item)}>{item.shortname || item.name}</a></h3>
|
<h3 class=" text-pbw-red"><a href={_url(col, item)}>{item.shortname || item.name}</a></h3>
|
||||||
{#if col === "event"}
|
{#if col === "event"}
|
||||||
<div class="text-xl text-gray-500 my-2">
|
<div class="text-xl text-gray-500 my-2">
|
||||||
<span class="font-bold">{formateItemDate(item)}</span>
|
<span class="font-bold">{formatItemDate(item)}</span>
|
||||||
{#if item.attendees}<br />{item.attendees}+ ppl{/if}
|
{#if item.attendees}<br />{item.attendees}+ ppl{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script>
|
||||||
|
export let item;
|
||||||
|
export let 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 #PBW23 dataset which can be found at <a href="https://data.prgblockweek.com/23/index.json" class="underline hover:no-underline" target="_blank">data.prgblockweek.com</a>.
|
||||||
|
<br />📖 The source data is hosted in the 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>
|
||||||
|
{#if item}
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="mt-2">
|
||||||
|
<a href="" class="text-gray-400">[{col}:{item.id}]</a> <a href="https://github.com/utxo-foundation/prague-blockchain-week/tree/main/data/23/events/{item.id}" class="underline hover:no-underline" target="_blank">Show on GitHub</a>
|
||||||
|
- <button class="cursor-pointer underline hover:no-underline" on:click={() => { showSource = !showSource; return false; }}>Toggle JSON source</button>
|
||||||
|
</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">{JSON.stringify(item, null, 2)}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
import { format, addDays } from 'date-fns';
|
||||||
|
|
||||||
|
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' : ''))
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFlagEmoji(countryCode) {
|
||||||
|
const codePoints = countryCode
|
||||||
|
.toUpperCase()
|
||||||
|
.split('')
|
||||||
|
.map(char => 127397 + char.charCodeAt());
|
||||||
|
return String.fromCodePoint(...codePoints);
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import CollectionList from '$lib/CollectionList.svelte';
|
import CollectionList from '$lib/components/CollectionList.svelte';
|
||||||
|
import Footer from '$lib/components/Footer.svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
@ -46,5 +47,6 @@
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-5 my-6 text-center text-3xl mb-8">
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-5 my-6 text-center text-3xl mb-8">
|
||||||
<CollectionList arr={data.bundle.unions} img="logo" col="union" entry={entry}/>
|
<CollectionList arr={data.bundle.unions} img="logo" col="union" entry={entry}/>
|
||||||
</div>
|
</div>
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,8 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
export let data;
|
export let data;
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import CollectionList from '$lib/CollectionList.svelte';
|
import CollectionList from '$lib/components/CollectionList.svelte';
|
||||||
|
import Footer from '$lib/components/Footer.svelte';
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
import SvelteMarkdown from 'svelte-markdown';
|
||||||
|
import { formatItemDate, bareDomain, getFlagEmoji } from '$lib/utils.js';
|
||||||
|
|
||||||
const colsDef = {
|
const colsDef = {
|
||||||
union: "unions",
|
union: "unions",
|
||||||
|
@ -12,12 +14,22 @@
|
||||||
benefit: "benefits",
|
benefit: "benefits",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const langMapper = {
|
||||||
|
czech: 'cz',
|
||||||
|
slovak: 'sk',
|
||||||
|
english: 'gb'
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
|
||||||
$: col = $page.params.type
|
$: col = $page.params.type
|
||||||
$: colPlural = colsDef[col]
|
$: colPlural = colsDef[col]
|
||||||
$: item = data.bundle[colPlural].find(e => e.id === $page.params.slug)
|
$: item = data.bundle[colPlural].find(e => e.id === $page.params.slug)
|
||||||
$: defs = data.schema ? data.schema.definitions[col] : {}
|
$: defs = data.schema ? data.schema.definitions[col] : {}
|
||||||
|
|
||||||
let showSource = false;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -26,14 +38,106 @@
|
||||||
|
|
||||||
<div class="w-full mx-6 xl:mx-0">
|
<div class="w-full mx-6 xl:mx-0">
|
||||||
<div class="max-w-7xl mx-auto pt-5 md:pt-10">
|
<div class="max-w-7xl mx-auto pt-5 md:pt-10">
|
||||||
<div class="flex gap-8">
|
<div class="flex gap-8 mb-10">
|
||||||
<h1 class="text-5xl uppercase font-bold text-pbw-red"><a href="/{$page.params.entry}">#PBW23</a></h1>
|
<h1 class="text-5xl uppercase font-bold text-pbw-red"><a href="/{$page.params.entry}">#PBW23</a></h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap mb-4">
|
||||||
|
{#if item.logo}
|
||||||
|
<div class=" w-24 mr-5">
|
||||||
|
<img src={item.logo} class="rounded-xl" alt={item.name} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if item.photoUrl}
|
||||||
|
<div class="w-48 mr-5">
|
||||||
|
<img src={item.photoUrl} class="rounded-xl" alt={item.name} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div>
|
<div>
|
||||||
<div class="font-normal text opacity-50" style="line-height: 0.6em;">{col.toUpperCase()}</div>
|
<div class="font-normal text opacity-50" style="line-height: 0.6em;">{col.toUpperCase()}</div>
|
||||||
<h2 class="text-4xl font-bold text-gray-600">{item.name}</h2>
|
<h2 class="text-5xl font-bold text-gray-600">{item.name}</h2>
|
||||||
|
{#if col === 'event'}
|
||||||
|
<div class="text-2xl flex gap-4 mt-2 flex-wrap">
|
||||||
|
<div class="flex gap-1 items-center">
|
||||||
|
{#each item.types as type}
|
||||||
|
<div class="text-sm uppercase text-white bg-pbw-red rounded px-1.5 py-0.5">{type}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="">{formatItemDate(item, { full: true })}</div>
|
||||||
|
<div>📍
|
||||||
|
{#if item.venueUrl}
|
||||||
|
<a href="{item.venueUrl}" target="_blank" class="underline hover:no-underline">{item.venueName}</a>
|
||||||
|
{:else}
|
||||||
|
{item.venueName}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if item.attendees}
|
||||||
|
<div>👥 {item.attendees}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if col === 'speaker'}
|
||||||
|
<div class="text-2xl mt-2">
|
||||||
|
<SvelteMarkdown source={item.caption} />
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 text-xl m-6">
|
|
||||||
|
{#if item.desc || item.description}
|
||||||
|
<div class="mt-4 text-xl">
|
||||||
|
<div><SvelteMarkdown source={item.desc || item.description} /></div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if col === 'event'}
|
||||||
|
<div class="flex flex-wrap gap-6 text-xl mt-4">
|
||||||
|
<div><div class="uppercase text-sm opacity-40">Organizator</div><SvelteMarkdown source={item.org || 'TBD'} /></div>
|
||||||
|
{#if item.languages}
|
||||||
|
<div>
|
||||||
|
<div class="uppercase text-sm opacity-40">Languages</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
{#each item.languages as lang}
|
||||||
|
<div>{getFlagEmoji(langMapper[lang])} {lang}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if item.chains}
|
||||||
|
<div>
|
||||||
|
<div class="uppercase text-sm opacity-40">Chains</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
{#each item.chains as chain}
|
||||||
|
<div>{chain.substr(0, 1).toUpperCase() + chain.substr(1)}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if item.tags}
|
||||||
|
<div>
|
||||||
|
<div class="uppercase text-sm opacity-40">Tags</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
{#each item.tags as tag}
|
||||||
|
<div>#{tag}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#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>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<!--div class="p-2 text-xl m-6">
|
||||||
<table>
|
<table>
|
||||||
{#each Object.keys(defs.properties) as key}
|
{#each Object.keys(defs.properties) as key}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -79,24 +183,20 @@
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div-->
|
||||||
|
|
||||||
{#if col === "event"}
|
{#if col === "event"}
|
||||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Speakers ({item.speakers?.length || 0})</h2>
|
|
||||||
{#if item.speakers}
|
{#if item.speakers}
|
||||||
<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">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} />
|
<CollectionList arr={item.speakers} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<div class="my-4">No speakers yet.</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Sub-Events ({item.events?.length || 0})</h2>
|
|
||||||
{#if item.events}
|
{#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">
|
<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} />
|
<CollectionList arr={item.events} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<div class="my-4">No sub-events yet.</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if col === "union"}
|
{#if col === "union"}
|
||||||
|
@ -105,15 +205,13 @@
|
||||||
<CollectionList arr={item.events?.map(eId => data.bundle.events.find(e => e.id === eId))} col="event" img="logo" />
|
<CollectionList arr={item.events?.map(eId => data.bundle.events.find(e => e.id === eId))} col="event" img="logo" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if col === "speaker"}
|
||||||
<h2 class="text-2xl uppercase font-bold mt-10 mb-4 col-span-1">Source code / Edit</h2>
|
<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>
|
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||||
<a href="#" class="underline hover:no-underline" on:click={() => { showSource = !showSource; }}>Show/Hide source</a>,
|
<CollectionList arr={data.bundle.events.filter(e => e.speakers?.find(s => s.id === item.id))} col="event" img="logo" />
|
||||||
<a href="https://github.com/utxo-foundation/prague-blockchain-week/tree/main/data/23/events/{item.id}" class="underline hover:no-underline">Edit on GitHub</a>
|
</div>
|
||||||
</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">{JSON.stringify(item, null, 2)}</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<Footer col={col} item={item} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Načítá se…
Odkázat v novém úkolu