This commit is contained in:
tree 2022-05-19 17:51:31 +02:00
rodič fde5799d73
revize 715f2a6379
5 změnil soubory, kde provedl 255 přidání a 135 odebrání

Zobrazit soubor

@ -1,6 +1,6 @@
{
"name": "utxo22-web",
"version": "1.2.0",
"version": "1.2.1",
"scripts": {
"dev": "svelte-kit dev",
"build": "svelte-kit build",

Zobrazit soubor

@ -1 +1 @@
export const version = "1.1-dev";
export const version = "1.3-dev";

Zobrazit soubor

@ -1,161 +1,193 @@
<script context="module">
export const prerender = true;
</script>
<script>
import { onMount, onDestroy } from "svelte";
import { format, compareAsc, compareDesc } from "date-fns"
import { format, compareAsc, compareDesc } from "date-fns";
import { bundle, userData, loadInfo, schedulePref } from "$lib/stores.js";
import { cs } from "date-fns/locale/index.js";
let planNumber = 0
$: plan = $bundle ? $bundle.spec['schedule-candidates'][planNumber] : null
let planNumber = 0;
$: plan = $bundle ? $bundle.spec["schedule-candidates"][planNumber] : null;
onMount(async () => {
bundle.subscribe((bundle) => {
const pref = {};
pref.stages = bundle.spec.stages.map((s) => s.id);
pref.tracks = bundle.spec.tracks.map((s) => s.id);
schedulePref.set(pref);
});
});
bundle.subscribe(bundle => {
const pref = {}
pref.stages = bundle.spec.stages.map(s => s.id)
pref.tracks = bundle.spec.tracks.map(s => s.id)
schedulePref.set(pref)
})
})
function filterDateStage (arr, date, stageId) {
function filterDateStage(arr, date, stageId) {
return arr
.filter(i => i.date === date)
.filter(i => i.stage === stageId)
.filter((i) => i.date === date)
.filter((i) => i.stage === stageId);
}
function findSegment (bundle, stage, period) {
function findSegment(bundle, stage, period) {
for (const st of stage.times) {
const p = parsePeriod(bundle, st)
if (compareAsc(period.start, p.period.end) !== -1 && compareDesc(period.end, p.period.start) !== 1) {
continue
const p = parsePeriod(bundle, st);
if (
compareAsc(period.start, p.period.end) !== -1 &&
compareDesc(period.end, p.period.start) !== 1
) {
continue;
}
return p
return p;
}
return null
return null;
}
function dateSlots (pl, period, bundle, schedulePref = null) {
let time = period.start
const endTime = period.end
const arr = []
const rowspans = {}
function dateSlots(pl, period, bundle, schedulePref = null) {
let time = period.start;
const endTime = period.end;
const arr = [];
const rowspans = {};
while (compareAsc(time, endTime) === -1) {
const stages = {}
const stages = {};
for (const stage of bundle.spec.stages) {
if (rowspans[stage.id] > 0) {
stages[stage.id] = null
rowspans[stage.id]--
continue
stages[stage.id] = null;
rowspans[stage.id]--;
continue;
}
if (schedulePref && !schedulePref.stages.includes(stage.id)) {
continue
continue;
}
let si = pl.schedule.find(pi => (new Date(pi.period.start).getTime() === new Date(time).getTime()) && pi.stage === stage.id)
stages[stage.id] = si
let si = pl.schedule.find(
(pi) =>
new Date(pi.period.start).getTime() === new Date(time).getTime() &&
pi.stage === stage.id
);
stages[stage.id] = si;
if (si) {
const span = Math.floor((new Date(si.period.end).getTime() - new Date(si.period.start).getTime())/(1000 * 60) / 30)
si.span = span
const span = Math.floor(
(new Date(si.period.end).getTime() -
new Date(si.period.start).getTime()) /
(1000 * 60) /
30
);
si.span = span;
if (span > 1) {
rowspans[stage.id] = span - 1
rowspans[stage.id] = span - 1;
}
}
}
arr.push({ title: format(time, 'HH:mm'), stages })
time = new Date(time.getTime() + (30 * 60 * 1000))
arr.push({ title: format(time, "HH:mm"), stages });
time = new Date(time.getTime() + 30 * 60 * 1000);
}
return arr
return arr;
}
function showSpeakers (bundle, ev) {
return ev.speakers.map(sId => {
const sp = bundle.spec.speakers.find(s => s.id === sId)
return sp.name + (sp.nickname ? ` (${sp.nickname})` : '')
}).join(', ')
function showSpeakers(bundle, ev) {
return ev.speakers
.map((sId) => {
const sp = bundle.spec.speakers.find((s) => s.id === sId);
return sp.name + (sp.nickname ? ` (${sp.nickname})` : "");
})
.join(", ");
}
function showEventDetail (bundle, ev) {
if (ev.type === 'lightning-series') {
return bundle.spec.events.filter(e => e.parent === ev.id).map(e => `<span class="font-semibold"><a href="/udalosti?id=${e.id}">${e.name}</a></span> - ${showSpeakers(bundle, e) || 'TBD'}`).join('<br>')
function showEventDetail(bundle, ev) {
if (ev.type === "lightning-series") {
return bundle.spec.events
.filter((e) => e.parent === ev.id)
.map(
(e) =>
`<span class="font-semibold"><a href="/udalosti?id=${e.id}">${
e.name
}</a></span> - ${showSpeakers(bundle, e) || "TBD"}`
)
.join("<br>");
}
return showSpeakers(bundle, ev)
return showSpeakers(bundle, ev);
}
function parsePeriod (bundle, str) {
const [ dayNumber, times ] = str.split('/')
const [ start, end ] = times.split('-')
const date = bundle.dates[dayNumber-1]
function parsePeriod(bundle, str) {
const [dayNumber, times] = str.split("/");
const [start, end] = times.split("-");
const date = bundle.dates[dayNumber - 1];
return {
date,
period: {
start: new Date(`${date}T${start}`),
end: new Date(`${date}T${end}`)
}
}
end: new Date(`${date}T${end}`),
},
};
}
function scheduleTimes (bundle) {
return bundle.scheduleTimes.map(item => {
return parsePeriod(bundle, item)
})
function scheduleTimes(bundle) {
return bundle.scheduleTimes.map((item) => {
return parsePeriod(bundle, item);
});
}
function eventTrackClasses (bundle, ev, selectedTracks) {
if (!selectedTracks.includes(ev.track || '')) {
return 'opacity-20'
function eventTrackClasses(bundle, ev, selectedTracks) {
if (!selectedTracks.includes(ev.track || "")) {
return "opacity-20";
}
return 'border border-blue-web/50'
return "border border-blue-web/50";
}
function findEvent (bundle, eventId) {
const ev = bundle.spec.events.find(ev => ev.id === eventId)
function findEvent(bundle, eventId) {
const ev = bundle.spec.events.find((ev) => ev.id === eventId);
if (!ev) {
return null
return null;
}
switch (ev.type) {
case 'panel':
ev.color = 'bg-orange-400/20 hover:bg-orange-400/40'
break
case 'talk':
ev.color = 'bg-custom-green/20 hover:bg-custom-green/40'
break
case 'workshop':
ev.color = 'bg-custom-blue/20 hover:bg-custom-blue/40'
break
case 'campfire':
ev.color = 'bg-purple-400/20 hover:bg-purple-400/40'
break
case 'lightning-series':
ev.color = 'bg-yellow-400/20 hover:bg-yellow-400/40'
break
case "panel":
ev.color = "bg-orange-400/20 hover:bg-orange-400/40";
break;
case "talk":
ev.color = "bg-custom-green/20 hover:bg-custom-green/40";
break;
case "workshop":
ev.color = "bg-custom-blue/20 hover:bg-custom-blue/40";
break;
case "campfire":
ev.color = "bg-purple-400/20 hover:bg-purple-400/40";
break;
case "lightning-series":
ev.color = "bg-yellow-400/20 hover:bg-yellow-400/40";
break;
default:
ev.color = 'bg-white hover:bg-gray-500/10'
ev.color = "bg-white hover:bg-gray-500/10";
}
return ev
return ev;
}
</script>
<svelte:head>
<title>Časová osa | UTXO.22</title>
</svelte:head>
<section class="relative mx-auto pt-6 sm:pt-10 pb-6 px-6 max-w-6xl text-blue-web">
<section
class="relative mx-auto pt-6 sm:pt-10 pb-6 px-6 max-w-6xl text-blue-web"
>
<h1 class="uppercase text-2xl font-bold mb-6">Časová osa</h1>
{#if $bundle}
<div class="font-semibold uppercase mb-1">Plán (řešení)</div>
<div class="flex flex-wrap gap-1">
<select class="border border-blue-web rounded-md p-1.5 text-blue-web bg-white" bind:value={planNumber}>
{#each $bundle.spec['schedule-candidates'] as p, i}
<option value={i}>#{i} [{[ 'score', 'thc:themeCrossing', 'tgc:tagsCrossing' ].map(key => { const [title,rkey] = key.split(':'); return `${title}:${Math.round(p.metrics[rkey || title]*1000)/1000}` }).join(', ')}]</option>
<select
class="border border-blue-web rounded-md p-1.5 text-blue-web bg-white"
bind:value={planNumber}
>
{#each $bundle.spec["schedule-candidates"] as p, i}
<option value={i}
>#{i} [{["score", "thc:themeCrossing", "tgc:tagsCrossing"]
.map((key) => {
const [title, rkey] = key.split(":");
return `${title}:${
Math.round(p.metrics[rkey || title] * 1000) / 1000
}`;
})
.join(", ")}]</option
>
{/each}
</select>
</div>
@ -167,35 +199,82 @@
<div class="">
<div class="font-semibold uppercase mb-1">Sál / Místo</div>
<div class="flex gap-1 flex-wrap">
<div class="m-0.5"><a href="#" class="hover:underline" on:click={() => $schedulePref.stages = $bundle.spec.stages.map(s => s.id)}>Všechny sály</a></div>
<div class="m-0.5">
<a
href="#"
class="hover:underline"
on:click={() =>
($schedulePref.stages = $bundle.spec.stages.map((s) => s.id))}
>Všechny sály</a
>
</div>
{#each $bundle.spec.stages as et}
<div class="u-choose-div m-0.5"><label class="cursor-pointer"><input type="checkbox" bind:group={$schedulePref.stages} value={et.id} /></label> <span class="cursor-pointer" on:click={() => $schedulePref.stages = [et.id]}>{et.name}</span></div>
<div class="u-choose-div m-0.5">
<label class="cursor-pointer"
><input
type="checkbox"
bind:group={$schedulePref.stages}
value={et.id}
/></label
>
<span
class="cursor-pointer"
on:click={() => ($schedulePref.stages = [et.id])}
>{et.name}</span
>
</div>
{/each}
</div>
</div>
<div class="mt-4">
<div class="font-semibold uppercase mb-1">Kategorie</div>
<div class="flex gap-2 flex-wrap">
<div class="m-0.5"><a href="#" class="hover:underline" on:click={() => $schedulePref.tracks = $bundle.spec.tracks.map(s => s.id)}>Všechny kategorie</a></div>
<div class="m-0.5">
<a
href="#"
class="hover:underline"
on:click={() =>
($schedulePref.tracks = $bundle.spec.tracks.map((s) => s.id))}
>Všechny kategorie</a
>
</div>
{#each $bundle.spec.tracks as et}
<div class="u-choose-div m-0.5"><label class="cursor-pointer"><input type="checkbox" bind:group={$schedulePref.tracks} value={et.id} /></label> <span class="cursor-pointer" on:click={() => $schedulePref.tracks = [et.id]}> {et.shortname || et.name}</span></div>
<div class="u-choose-div m-0.5">
<label class="cursor-pointer"
><input
type="checkbox"
bind:group={$schedulePref.tracks}
value={et.id}
/></label
>
<span
class="cursor-pointer"
on:click={() => ($schedulePref.tracks = [et.id])}
>
{et.shortname || et.name}</span
>
</div>
{/each}
</div>
</div>
</div>
{#each scheduleTimes($bundle) as st}
<div class="max-w-6xl mx-auto px-6 mb-4">
<h2 class="uppercase text-xl font-bold">{format(new Date(st.date), 'iiii d.M.y', { locale: cs })}</h2>
<h2 class="uppercase text-xl font-bold">
{format(new Date(st.date), "iiii d.M.y", { locale: cs })}
</h2>
</div>
<div class="relative">
<div class="mt-4 mb-10 overflow-scroll sm:overflow-clip">
<table width="100%" class="table table-auto xl:table-fixed relative">
<thead class="">
<tr>
<th class="xl:w-16"></th>
<th class="xl:w-16" />
{#each $bundle.spec.stages as stage}
{#if $schedulePref && $schedulePref.stages.includes(stage.id)}
<th class="text-md py-1.5 px-1 sticky top-0 bg-white">{stage.name}</th>
<th class="text-md py-1.5 px-1 sticky top-0 bg-white"
>{stage.name}</th
>
{/if}
{/each}
</tr>
@ -203,22 +282,45 @@
<tbody>
{#each dateSlots(plan, st.period, $bundle, $schedulePref) as ds}
<tr class="bg-gray-100">
<th valign="top" class="w-auto pl-2 pr-2 pt-1 text-sm sticky left-0 bg-white" height="110">{ds.title}</th>
<th
valign="top"
class="w-auto pl-2 pr-2 pt-1 text-sm sticky left-0 bg-white"
height="110">{ds.title}</th
>
{#each $bundle.spec.stages as stage}
{#if $schedulePref && $schedulePref.stages.includes(stage.id)}
{#if ds.stages[stage.id] === undefined}
<td></td>
<td />
{:else if ds.stages[stage.id] !== null}
{#each [[ds.stages[stage.id], findEvent($bundle, ds.stages[stage.id].event)]] as [si, event]}
<td class="text-sm h-full {event.color} {eventTrackClasses($bundle, event, $schedulePref.tracks)}" valign="top" rowspan={ds.stages[stage.id].span}>
<td
class="text-sm h-full {event.color} {eventTrackClasses(
$bundle,
event,
$schedulePref.tracks
)}"
valign="top"
rowspan={ds.stages[stage.id].span}
>
<div class="px-2 py-1 mb-1 mt-1">
<div class="text-xs">{format(new Date(si.period.start), 'HH:mm')}-{format(new Date(si.period.end), 'HH:mm')} {#if event.track}[{#each [$bundle.spec.tracks.find(t => t.id === event.track)] as track}{track.shortname || track.name}{/each}]{/if}</div>
<div class="font-semibold mt-1"><a href="/udalosti?id={event.id}">{event.name}</a></div>
<div class="text-xs">
{format(
new Date(si.period.start),
"HH:mm"
)}-{format(new Date(si.period.end), "HH:mm")}
{#if event.track}[{#each [$bundle.spec.tracks.find((t) => t.id === event.track)] as track}{track.shortname ||
track.name}{/each}]{/if}
</div>
<div class="font-semibold mt-1">
<a href="/udalosti?id={event.id}"
>{event.name}</a
>
</div>
<div class="text-xs mt-1">
{@html showEventDetail($bundle, event)}
</div>
<div class="text-xs mt-2 text-blue-web/50">
{event.tags.map(t => `#${t}`).join(', ')}
{event.tags.map((t) => `#${t}`).join(", ")}
</div>
</div>
</td>

Zobrazit soubor

@ -21,7 +21,11 @@
? [
{ name: "Hlavní přednášející (" + leadSpeakersCount + ")", id: "top" },
{ name: "Vše", id: null },
].concat(currentBundle.spec.tracks.filter(t => t.hidden === undefined || t.hidden !== true))
].concat(
currentBundle.spec.tracks.filter(
(t) => t.hidden === undefined || t.hidden !== true
)
)
: null;
function changeTrack(tId) {
@ -41,8 +45,8 @@
});
}
function statsIcon (ico = 'fa-regular fa-calendar') {
return `<i class="${ico} inline-block align-baseline pr-1.5 sm:pr-2.5 text-blue-web/40"></i>`
function statsIcon(ico = "fa-regular fa-calendar") {
return `<i class="${ico} inline-block align-baseline pr-1.5 sm:pr-2.5 text-blue-web/40"></i>`;
}
</script>
@ -54,10 +58,21 @@
{#if $apiStatus}
<section class="bg-blue-web-light">
<div class="pb-4 pt-4 lg:pt-4 lg:pb-4 mx-auto sm:px-2 lg:px-6 2xl:px-16">
<div class="text-center text-xl sm:text-xl lg:text-2xl text-blue-web px-8 flex flex-wrap gap-4 lg:gap-8 justify-center">
<div>{@html statsIcon('fa-solid fa-user-check')} <b>{$bundle.spec.speakers.length}</b> přednášejících</div>
<div>{@html statsIcon('fa-regular fa-calendar')} <b>{$bundle.spec.events.length}</b> událostí</div>
<div>{@html statsIcon('fa-solid fa-users')} <b>{$apiStatus.global.tickets}</b> návstěvníků</div>
<div
class="text-center text-xl sm:text-xl lg:text-2xl text-blue-web px-8 flex flex-wrap gap-4 lg:gap-8 justify-center"
>
<div>
{@html statsIcon("fa-solid fa-user-check")}
<b>{$bundle.spec.speakers.length}</b> přednášejících
</div>
<div>
{@html statsIcon("fa-regular fa-calendar")}
<b>{$bundle.spec.events.length}</b> událostí
</div>
<div>
{@html statsIcon("fa-solid fa-users")}
<b>{$apiStatus.global.tickets}</b> návstěvníků
</div>
</div>
</div>
</section>

Zobrazit soubor

@ -94,7 +94,10 @@
<div class="flex gap-2">
<Avatar speaker={s} size="semi-small" />
<div class="m-auto">
<a href="/lide?id={s.id}" class="text-xl">{s.name} {#if s.nickname} ({s.nickname}){/if}</a>
<a href="/lide?id={s.id}" class="text-xl"
>{s.name}
{#if s.nickname} ({s.nickname}){/if}</a
>
</div>
</div>
{/each}