Heatmap
This commit is contained in:
rodič
910da24ed9
revize
f555c14865
|
@ -0,0 +1,39 @@
|
||||||
|
<script>
|
||||||
|
export let segments;
|
||||||
|
export let date;
|
||||||
|
export let entry;
|
||||||
|
export let bundle;
|
||||||
|
export let event = null;
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="text-2xl">
|
||||||
|
{#each segments as segment}
|
||||||
|
<div class="flex flex-wrap mb-2 gap-3 items-center text-gray-800">
|
||||||
|
<div class="text-xl md:w-32 text-right">{format(new Date(segment.startTime), "HH:mm")} - {format(new Date(segment.endTime), "HH:mm")}</div>
|
||||||
|
<div class="flex flex-wrap gap-2 items-center mb-6 md:mb-0">
|
||||||
|
<div><img src={(segment.event || event).logo} class="{event ? 'w-8' : 'w-10'} rounded" /></div>
|
||||||
|
<div class="">
|
||||||
|
{#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>
|
||||||
|
{:else}
|
||||||
|
<span class="">{event.shortname || event.name}</span>
|
||||||
|
{/if}
|
||||||
|
{#if segment.title}
|
||||||
|
- {segment.title}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<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 || event).venueName}
|
||||||
|
@ {(segment.event || event).venueName}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
|
@ -1,10 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { compareAsc, addDays, addMinutes, format } from 'date-fns';
|
import { compareAsc, addDays, addMinutes, format } from 'date-fns';
|
||||||
export let bundle;
|
import { goto } from '$app/navigation';
|
||||||
|
export let data;
|
||||||
|
|
||||||
const startDate = "2023-06-02"
|
const startDate = "2023-06-02"
|
||||||
const endDate = "2023-06-11"
|
const endDate = "2023-06-11"
|
||||||
const segmentMinutes = 60
|
const segmentMinutes = 60
|
||||||
|
const bundle = data.bundle
|
||||||
|
|
||||||
const days = []
|
const days = []
|
||||||
let currentDate = startDate
|
let currentDate = startDate
|
||||||
|
@ -32,36 +34,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = []
|
function updateTimelineEvent(time, eventId, attendees) {
|
||||||
for (const event of bundle.events) {
|
for (const day of days) {
|
||||||
const defaultTimes = "09:00-18:00"
|
for (const segment of segments) {
|
||||||
const [ tstart, tend ] = (event.times || defaultTimes).split('-').map(t => t.trim())
|
const sstart = new Date(`${day}T${segment}`)
|
||||||
const times = []
|
const send = new Date(addMinutes(sstart, segmentMinutes))
|
||||||
for (let i = 0; i < (event.days || 1); i++) {
|
if (compareAsc(sstart, time.end) < 0 && compareAsc(send, time.start) > 0) {
|
||||||
const time = {
|
//console.log(timelineData[[day, segment].join(';')])
|
||||||
start: addDays(new Date(event.date + "T" + tstart), i),
|
const baseScore = attendees ? (attendees > 3000 ? 3000 : (attendees < 200 ? 200 : attendees)) : 0
|
||||||
end: addDays(new Date(event.date + "T" + tend), (tend < tstart ? i+1 : i))
|
const target = timelineData[[day, segment].join(';')]
|
||||||
}
|
target.score += baseScore || 0
|
||||||
for (const day of days) {
|
target.events.push(eventId)
|
||||||
for (const segment of segments) {
|
|
||||||
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 = event.attendees ? (event.attendees > 3000 ? 3000 : (event.attendees < 200 ? 200 : event.attendees)) : 0
|
|
||||||
const target = timelineData[[day, segment].join(';')]
|
|
||||||
target.score += baseScore || 0
|
|
||||||
target.events.push(event.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.push({
|
}
|
||||||
id: event.id,
|
|
||||||
tstart,
|
const defaultTimes = "09:00-18:00"
|
||||||
tend,
|
for (const event of bundle.events) {
|
||||||
times
|
if (event.segments) {
|
||||||
})
|
for (const eventSegment of event.segments) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const [ tstart, tend ] = (event.times || defaultTimes).split('-').map(t => t.trim())
|
||||||
|
const times = []
|
||||||
|
for (let i = 0; i < (event.days || 1); i++) {
|
||||||
|
const time = {
|
||||||
|
start: addDays(new Date(event.date + "T" + tstart), i),
|
||||||
|
end: addDays(new Date(event.date + "T" + tend), (tend < tstart ? i+1 : i))
|
||||||
|
}
|
||||||
|
updateTimelineEvent(time, event.id, event.attendees)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const segmentsMax = Math.max(...Object.keys(timelineData).map(k => timelineData[k].score))
|
const segmentsMax = Math.max(...Object.keys(timelineData).map(k => timelineData[k].score))
|
||||||
|
@ -85,6 +95,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()}`)
|
||||||
|
}
|
||||||
|
|
||||||
function hiddenSelected() {
|
function hiddenSelected() {
|
||||||
selectedSegment = null
|
selectedSegment = null
|
||||||
}
|
}
|
||||||
|
@ -97,32 +115,32 @@
|
||||||
|
|
||||||
<div class="w-full mb-10 relative">
|
<div class="w-full mb-10 relative">
|
||||||
{#if selectedSegment}
|
{#if selectedSegment}
|
||||||
<div class="absolute top-[74px] w-[300px] border bg-white z-50 py-2 px-4 {selectedSegment ? 'block' : 'hidden'}" style="left: {selectedSegment.event.layerX}px;">
|
<div class="absolute top-[66px] w-[300px] border bg-white z-50 py-2 px-4 {selectedSegment ? 'block' : 'hidden'}" style="left: {selectedSegment.event.layerX}px;">
|
||||||
<div class="uppercase">{selectedSegment.title}</div>
|
<div class="uppercase">{selectedSegment.title}</div>
|
||||||
<div class="text-xl mt-4">
|
<div class="text-xl mt-4">
|
||||||
{#each selectedSegment.data.events.map(e => eventDetail(e)) as item}
|
{#each selectedSegment.data.events.map(e => eventDetail(e)) as item}
|
||||||
<div class="h-12">
|
<div class="h-11">
|
||||||
{#if item.logo}
|
{#if item.logo}
|
||||||
<img src={item.logo} alt={item.name} class="rounded-lg w-full aspect-square object-cover w-10 inline-block mr-1" />
|
<img src={item.logo} alt={item.name} class="rounded aspect-square object-cover w-10 inline-block mr-1" />
|
||||||
{/if}
|
{/if}
|
||||||
{item.name}
|
{item.shortname || item.name}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex text-center text-gray-600 text-sm">
|
<div class="flex text-center text-gray-400 text-sm">
|
||||||
{#each days as day}
|
{#each days as day}
|
||||||
<div class="mb-1 uppercase" style="width: {1/(days.length/100)}%;">
|
<div class="mb-1 uppercase" style="width: {1/(days.length/100)}%;">
|
||||||
{format(new Date(day), 'MMMM d')}
|
<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>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full border border-gray-600 rounded flex">
|
<div class="w-full border border-gray-300 rounded flex">
|
||||||
{#each days as day}
|
{#each days as day, i}
|
||||||
<div class="h-12 flex flex-grow " style="width: {1/(days.length/100)}%; border-right: 1px solid gray;">
|
<div class="h-10 flex flex-grow hover:bg-pbw-yellow/20" style="width: {1/(days.length/100)}%; {days.length-i > 1 ? "border-right: 1px solid silver;" : ""}">
|
||||||
{#each segments as segment}
|
{#each segments as segment}
|
||||||
<div id="{day}-{segment}" data-events={timelineData[[day, segment].join(";")].events} data-score={timelineData[[day, segment].join(";")].score} class="hover:border hover:border-pbw-red flex-grow" style="width: {1/(segments.length/50)}%; background-color: rgba(255, 120, 120, {timelineData[[day, segment].join(";")].perc}%);" on:mouseenter={makeSelected(day, segment, timelineData[[day, segment].join(";")])} on:mouseleave={hiddenSelected}>
|
<div id="{day}-{segment}" data-events={timelineData[[day, segment].join(";")].events} data-score={timelineData[[day, segment].join(";")].score} class="hover:border hover:border-pbw-yellow flex-grow cursor-pointer" style="width: {1/(segments.length/50)}%; background-color: rgba(255, 22, 22, {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>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const config = {
|
||||||
conference: '#d3e5ee',
|
conference: '#d3e5ee',
|
||||||
meetup: '#fdecc8',
|
meetup: '#fdecc8',
|
||||||
hackathon: '#dad7ed',
|
hackathon: '#dad7ed',
|
||||||
expo: '#eee0da'
|
expo: '#eee0da',
|
||||||
|
party: '#dbeddb'
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,19 +2,19 @@
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import "../app.css";
|
import "../app.css";
|
||||||
|
|
||||||
$: homepage = !$page.params.type
|
$: homepage = !$page.params.type && !$page.params.date
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
{#if homepage}
|
{#if homepage}
|
||||||
<div class="bg-slate-100 dark:bg-pbw-dark">
|
<div class="px-6 xl:px-0 dark:bg-pbw-dark">
|
||||||
<div class="max-w-7xl mx-auto py-20">
|
<div class="max-w-7xl mx-auto pt-10 pb-6">
|
||||||
<h1 class="text-5xl uppercase font-bold text-pbw-red"><a href="/{$page.params.entry}">Prague Blockchain Week 2023</a></h1>
|
<h1 class="text-5xl uppercase font-bold text-pbw-red"><a href="/{$page.params.entry}">Prague Blockchain Week 2023</a></h1>
|
||||||
<div class="text-4xl text-pbw-yellow">June 2-11, 2023</div>
|
<div class="text-4xl text-pbw-yellow">June 2-11, 2023</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="pb-24 bg-slate-100 dark:bg-pbw-dark">
|
<div class="pb-24 dark:bg-pbw-dark">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
|
@ -2,6 +2,7 @@ import * as dataApi from "$lib/dataApi";
|
||||||
|
|
||||||
export async function load({ params, url }) {
|
export async function load({ params, url }) {
|
||||||
return {
|
return {
|
||||||
|
params,
|
||||||
bundle: await dataApi.load(params.entry, url.hostname),
|
bundle: await dataApi.load(params.entry, url.hostname),
|
||||||
schema: await dataApi.loadSchema(),
|
schema: await dataApi.loadSchema(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<div class="w-full px-6 xl:mx-0">
|
<div class="w-full px-6 xl:mx-0">
|
||||||
<div class="max-w-7xl mx-auto pt-2 md:pt-7">
|
<div class="max-w-7xl mx-auto pt-2 md:pt-7">
|
||||||
<TimelineHeatmap bundle={data.bundle} />
|
<TimelineHeatmap {data} />
|
||||||
|
|
||||||
<h2 class="text-2xl uppercase font-bold text-gray-500"><a href="/{entry}/events">Conferences & Hackathons</a> ({conferences.length})</h2>
|
<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">
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-6 my-6 text-center text-2xl">
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
import EventTypeBadge from '$lib/components/EventTypeBadge.svelte';
|
import EventTypeBadge from '$lib/components/EventTypeBadge.svelte';
|
||||||
import { formatItemDate, bareDomain, getFlagEmoji } from '$lib/utils.js';
|
import { formatItemDate, bareDomain, getFlagEmoji } from '$lib/utils.js';
|
||||||
import makeBlockie from 'ethereum-blockies-base64';
|
import makeBlockie from 'ethereum-blockies-base64';
|
||||||
|
import TimelineHeatmap from '$lib/components/TimelineHeatmap.svelte';
|
||||||
|
import { compareAsc, compareDesc, addMinutes } from 'date-fns';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
|
@ -17,17 +20,27 @@
|
||||||
$: tc = config.collections[type]
|
$: tc = config.collections[type]
|
||||||
$: items = data.bundle[type]
|
$: items = data.bundle[type]
|
||||||
|
|
||||||
|
function processItems(_items, query = {}) {
|
||||||
function processItems(_items) {
|
|
||||||
if (!_items) return [];
|
if (!_items) return [];
|
||||||
_items = JSON.parse(JSON.stringify(_items))
|
_items = JSON.parse(JSON.stringify(_items))
|
||||||
if (type === 'events') {
|
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
|
||||||
|
})
|
||||||
|
// return compareAsc(item.new Date(query.segment) > 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return _items
|
return _items
|
||||||
}
|
}
|
||||||
|
|
||||||
$: processedItems = processItems(items)
|
$: processedItems = processItems(items) //, Object.fromEntries($page.url.searchParams))
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (!config.collections[$page.params.type]) {
|
if (!config.collections[$page.params.type]) {
|
||||||
|
@ -53,8 +66,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap md:flex-nowrap w-full">
|
<div class="flex flex-wrap md:flex-nowrap w-full">
|
||||||
</div>
|
</div>
|
||||||
|
<TimelineHeatmap {data} />
|
||||||
<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-500 dark:text-gray-400">
|
<div class="text-xl mt-6 text-gray-800 dark:text-gray-400">
|
||||||
<table class="w-full table-auto">
|
<table class="w-full table-auto">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr class="text-left">
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
export let data;
|
export let data;
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import CollectionList from '$lib/components/CollectionList.svelte';
|
import CollectionList from '$lib/components/CollectionList.svelte';
|
||||||
|
import CalendarList from '$lib/components/CalendarList.svelte';
|
||||||
import EventTypeBadge from '$lib/components/EventTypeBadge.svelte';
|
import EventTypeBadge from '$lib/components/EventTypeBadge.svelte';
|
||||||
import Footer from '$lib/components/Footer.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';
|
import { formatItemDate, bareDomain, getFlagEmoji } from '$lib/utils.js';
|
||||||
import { config } from '$lib/pbw';
|
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 ]}))
|
||||||
|
|
||||||
|
@ -16,6 +18,17 @@
|
||||||
linkedin: { col: x => x.linkedin ? 'https://linkedin.com/in/'+x.linkedin : null }
|
linkedin: { col: x => x.linkedin ? 'https://linkedin.com/in/'+x.linkedin : null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function eventDates(event) {
|
||||||
|
const dates = []
|
||||||
|
for (const seg of event.segments) {
|
||||||
|
const date = format(new Date(seg.startTime), 'yyyy-MM-dd')
|
||||||
|
if (!dates.includes(date)) {
|
||||||
|
dates.push(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dates
|
||||||
|
}
|
||||||
|
|
||||||
$: entry = $page.params.entry
|
$: entry = $page.params.entry
|
||||||
$: col = $page.params.type
|
$: col = $page.params.type
|
||||||
$: colPlural = colsDef[col]
|
$: colPlural = colsDef[col]
|
||||||
|
@ -224,6 +237,17 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if col === "event"}
|
{#if col === "event"}
|
||||||
|
{#if item.segments}
|
||||||
|
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Day 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>
|
||||||
|
<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} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
{#if item.venues}
|
{#if item.venues}
|
||||||
<h2 class="text-2xl uppercase font-bold mt-10 text-gray-500">Venues ({item.venues?.length || 0})</h2>
|
<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">
|
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 mt-4 text-center text-xl">
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<script>
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import TimelineHeatmap from '$lib/components/TimelineHeatmap.svelte';
|
||||||
|
import CalendarList from '$lib/components/CalendarList.svelte';
|
||||||
|
import Footer from '$lib/components/Footer.svelte';
|
||||||
|
|
||||||
|
import { format, compareAsc } from 'date-fns';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
function makeSegments (events, date) {
|
||||||
|
const query = {
|
||||||
|
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)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.push({
|
||||||
|
startTime: sg.startTime,
|
||||||
|
endTime: sg.endTime,
|
||||||
|
event: ev,
|
||||||
|
title: sg.title,
|
||||||
|
venues: sg.venues || ev.venues || [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.sort((x, y) => {
|
||||||
|
return x.start > y.start ? 1 : -1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$: 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} Inspector</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><span class="text-pbw-yellow">.days</span></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TimelineHeatmap {data} />
|
||||||
|
<h2 class="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} />
|
||||||
|
</div>
|
||||||
|
<Footer bundle={data.bundle} />
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -19,5 +19,6 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
darkMode: 'class',
|
||||||
plugins: []
|
plugins: []
|
||||||
};
|
};
|
||||||
|
|
Načítá se…
Odkázat v novém úkolu