Lot of new pages
This commit is contained in:
rodič
578cdd2d1b
revize
7327e75e3e
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "utxo22-web",
|
"name": "utxo22-web",
|
||||||
"version": "1.1.0",
|
"version": "1.2.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "utxo22-web",
|
"name": "utxo22-web",
|
||||||
"version": "1.1.0",
|
"version": "1.2.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/fira-mono": "^4.5.0",
|
"@fontsource/fira-mono": "^4.5.0",
|
||||||
|
@ -21,7 +21,8 @@
|
||||||
"ethereum-blockies-base64": "^1.0.2",
|
"ethereum-blockies-base64": "^1.0.2",
|
||||||
"fuse.js": "^6.5.3",
|
"fuse.js": "^6.5.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"remove-markdown": "^0.3.0"
|
"remove-markdown": "^0.3.0",
|
||||||
|
"svelte-youtube": "^0.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^6.1.2",
|
"@faker-js/faker": "^6.1.2",
|
||||||
|
@ -1415,6 +1416,11 @@
|
||||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/load-script": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
|
||||||
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
@ -1870,6 +1876,11 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sister": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA=="
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
@ -1913,7 +1924,6 @@
|
||||||
"version": "3.46.6",
|
"version": "3.46.6",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.6.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.6.tgz",
|
||||||
"integrity": "sha512-o9nNft/OzCz/9kJpmWa1S52GAM+huCjPIsNWydYmgei74ZWlOA9/hN9+Z12INdklghu31seEXZMRHhS1+8DETw==",
|
"integrity": "sha512-o9nNft/OzCz/9kJpmWa1S52GAM+huCjPIsNWydYmgei74ZWlOA9/hN9+Z12INdklghu31seEXZMRHhS1+8DETw==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
|
@ -1943,6 +1953,17 @@
|
||||||
"svelte": "^3.0.0"
|
"svelte": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-youtube": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-youtube/-/svelte-youtube-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-uwHG0MiLwlB9MU9WP2/5drrT5YyXpcf4dAi/titwPQyrYXjk7EVcpL6ZmEwSAA7CAcfAXpsnyFPzJJeoyKxx+A==",
|
||||||
|
"dependencies": {
|
||||||
|
"youtube-player": "^5.5.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.0.23",
|
"version": "3.0.23",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz",
|
||||||
|
@ -2065,6 +2086,29 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^2.6.6",
|
||||||
|
"load-script": "^1.0.0",
|
||||||
|
"sister": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2971,6 +3015,11 @@
|
||||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"load-script": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
|
||||||
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
@ -3249,6 +3298,11 @@
|
||||||
"mri": "^1.1.0"
|
"mri": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sister": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA=="
|
||||||
|
},
|
||||||
"source-map-js": {
|
"source-map-js": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
@ -3279,8 +3333,7 @@
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "3.46.6",
|
"version": "3.46.6",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.6.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.6.tgz",
|
||||||
"integrity": "sha512-o9nNft/OzCz/9kJpmWa1S52GAM+huCjPIsNWydYmgei74ZWlOA9/hN9+Z12INdklghu31seEXZMRHhS1+8DETw==",
|
"integrity": "sha512-o9nNft/OzCz/9kJpmWa1S52GAM+huCjPIsNWydYmgei74ZWlOA9/hN9+Z12INdklghu31seEXZMRHhS1+8DETw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"svelte-hmr": {
|
"svelte-hmr": {
|
||||||
"version": "0.14.11",
|
"version": "0.14.11",
|
||||||
|
@ -3299,6 +3352,14 @@
|
||||||
"marked": "^4.0.10"
|
"marked": "^4.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"svelte-youtube": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-youtube/-/svelte-youtube-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-uwHG0MiLwlB9MU9WP2/5drrT5YyXpcf4dAi/titwPQyrYXjk7EVcpL6ZmEwSAA7CAcfAXpsnyFPzJJeoyKxx+A==",
|
||||||
|
"requires": {
|
||||||
|
"youtube-player": "^5.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tailwindcss": {
|
"tailwindcss": {
|
||||||
"version": "3.0.23",
|
"version": "3.0.23",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz",
|
||||||
|
@ -3377,6 +3438,31 @@
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"youtube-player": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^2.6.6",
|
||||||
|
"load-script": "^1.0.0",
|
||||||
|
"sister": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"ethereum-blockies-base64": "^1.0.2",
|
"ethereum-blockies-base64": "^1.0.2",
|
||||||
"fuse.js": "^6.5.3",
|
"fuse.js": "^6.5.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"remove-markdown": "^0.3.0"
|
"remove-markdown": "^0.3.0",
|
||||||
|
"svelte-youtube": "^0.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="h-full w-full">%svelte.body%</div>
|
<div class="h-full w-full">%svelte.body%</div>
|
||||||
<!--Start of Tawk.to Script-->
|
<!--Start of Tawk.to Script-->
|
||||||
<script type="text/javascript">
|
<!--script type="text/javascript">
|
||||||
var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
|
var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
|
||||||
(function(){
|
(function(){
|
||||||
var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
|
var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
s1.setAttribute('crossorigin','*');
|
s1.setAttribute('crossorigin','*');
|
||||||
s0.parentNode.insertBefore(s1,s0);
|
s0.parentNode.insertBefore(s1,s0);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script--!>
|
||||||
<!--End of Tawk.to Script-->
|
<!--End of Tawk.to Script-->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="text-sm flex flex-wrap gap-3 flex-1">
|
<div class="text-sm flex flex-wrap gap-3 flex-1">
|
||||||
<div><EventTypeLabel event={e} /></div>
|
<div class="opacity-80"><EventTypeLabel event={e} /></div>
|
||||||
{#if duration}<div class="text-xs my-auto">{duration}m</div>{/if}
|
{#if duration}<div class="text-xs my-auto">{duration}m</div>{/if}
|
||||||
{#if e.track}
|
{#if e.track}
|
||||||
<div class="text-sm my-auto">
|
<div class="text-sm my-auto">
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
<script>
|
<script>
|
||||||
export let event = {};
|
export let event = {};
|
||||||
export let size = null;
|
export let size = null;
|
||||||
|
export let black = false;
|
||||||
|
|
||||||
|
const textColor = black ? 'text-black' : 'text-white'
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
panel: { title: "Panelová debata", style: "bg-custom-red text-white" },
|
panel: { title: "Panelová debata", style: "bg-orange-400" },
|
||||||
talk: { title: "Přednáška", style: "bg-custom-green text-white" },
|
talk: { title: "Přednáška", style: "bg-custom-green" },
|
||||||
workshop: { title: "Workshop", style: "bg-custom-blue text-white" },
|
workshop: { title: "Workshop", style: "bg-custom-blue" },
|
||||||
lightning: { title: "Blesková přednáška", style: "bg-pink-400" },
|
lightning: { title: "Blesková přednáška", style: "bg-pink-400" },
|
||||||
"lightning-series": {
|
"lightning-series": {
|
||||||
title: "Pásmo bleskových přednášek",
|
title: "Pásmo bleskových přednášek",
|
||||||
style: "bg-pink-400",
|
style: "bg-yellow-400",
|
||||||
},
|
},
|
||||||
campfire: { title: "Campfire", style: "bg-purple-500" },
|
campfire: { title: "Campfire", style: "bg-purple-400" },
|
||||||
other: { title: "Ostatní", style: "bg-custom-yellow" },
|
other: { title: "Ostatní", style: "bg-rose-400" },
|
||||||
};
|
};
|
||||||
|
|
||||||
$: current = config[event.type];
|
$: current = config[event.type];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex {size === 'big' ? 'h-6 text-sm' : 'h-5 text-xs'}">
|
<div class="flex {size === 'big' ? 'h-6 text-sm' : 'h-5 text-xs'}">
|
||||||
<div class="w-1 rounded-l-sm {current.style}" />
|
|
||||||
<div
|
<div
|
||||||
class="{size === 'big'
|
class="{size === 'big'
|
||||||
? 'px-2 py-0.5'
|
? 'px-2 py-0.5'
|
||||||
: 'px-1.5 py-0.5'} rounded-r-sm bg-gray-100 uppercase"
|
: 'px-1.5 py-0.5'} {current.style} rounded-sm bg-gray-100 uppercase {textColor}"
|
||||||
>
|
>
|
||||||
{current.title}
|
{current.title}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
>
|
>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="lg:flex lg:flex-wrap lg:space-x-10">
|
<div class="lg:flex lg:flex-wrap lg:space-x-10">
|
||||||
{#if $page.url.pathname !== "/"}
|
{#if !["/", "/tv"].includes($page.url.pathname)}
|
||||||
<div
|
<div
|
||||||
class="block justify-start lg:flex-1 my-auto text-center pb-3 lg:pb-0 pt-3 lg:pt-0"
|
class="block justify-start lg:flex-1 my-auto text-center pb-3 lg:pb-0 pt-3 lg:pt-0"
|
||||||
>
|
>
|
||||||
|
@ -40,38 +40,58 @@
|
||||||
<div class="lg:flex-1" />
|
<div class="lg:flex-1" />
|
||||||
{/if}
|
{/if}
|
||||||
<div
|
<div
|
||||||
class="flex lg:space-x-10 uppercase text-sm font-bold text-white"
|
class="flex lg:space-x-10 uppercase text-sm font-bold text-white flex-wrap gap-3"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
href="/"
|
href="/"
|
||||||
class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]"
|
class="m-auto hover:text-[#E16A61] "
|
||||||
class:text-blue-400={$page.url.pathname === "/"}>O konferenci</a
|
class:text-blue-400={$page.url.pathname === "/"}>Úvod</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
sveltekit:prefetch
|
||||||
|
href="/tv"
|
||||||
|
class="m-auto hover:text-[#E16A61] text-custom-green"
|
||||||
|
class:text-blue-400={$page.url.pathname === "/tv"}><i class="fa-solid fa-video mr-1.5"></i> Livestreamy</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
href="/program"
|
href="/program"
|
||||||
class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]"
|
class="m-auto hover:text-[#E16A61]"
|
||||||
class:text-blue-400={$page.url.pathname === "/program"}>Program</a
|
class:text-blue-400={$page.url.pathname === "/program"}>Program</a
|
||||||
>
|
>
|
||||||
|
<a
|
||||||
|
sveltekit:prefetch
|
||||||
|
href="/mapa"
|
||||||
|
class="m-auto hover:text-[#E16A61]"
|
||||||
|
class:text-blue-400={$page.url.pathname === "/mapa"}>Mapa</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
sveltekit:prefetch
|
||||||
|
href="/prakticke"
|
||||||
|
class="m-auto hover:text-[#E16A61]"
|
||||||
|
class:text-blue-400={$page.url.pathname === "/prakticke"}>Praktické</a
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
href="/vstupenky"
|
href="/vstupenky"
|
||||||
class="lg:w-auto w-1/3 m-auto border-solid border border-[#E16A61] rounded-full {$page
|
class="m-auto border-solid border border-[#E16A61] rounded-full {$page
|
||||||
.url.pathname === '/vstupenky'
|
.url.pathname === '/vstupenky'
|
||||||
? 'border-0 bg-utxo-gradient m-px'
|
? 'border-0 bg-utxo-gradient m-px'
|
||||||
: 'hover:border-0 hover:bg-utxo-gradient hover:p-px'}"
|
: 'hover:border-0 hover:bg-utxo-gradient hover:p-px'}"
|
||||||
><div class="py-2 px-1 lg:px-8">
|
><div class="py-1.5 px-2 lg:px-6">
|
||||||
Vstupenky{#if $userDataLocal.tickets && $userDataLocal.tickets.length > 0} ({$userDataLocal
|
Vstupenky{#if $userDataLocal.tickets && $userDataLocal.tickets.length > 0} ({$userDataLocal
|
||||||
.tickets.length}){/if}
|
.tickets.length}){/if}
|
||||||
</div></a
|
</div></a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
{#if $page.url.pathname === '/'}
|
||||||
<div
|
<div
|
||||||
class="hidden lg:block my-auto lg:flex-1 lg:pt-0 pt-4 lg:justify-end justify-center"
|
class="hidden lg:block my-auto lg:flex-1 lg:pt-0 pt-4 lg:justify-end justify-center"
|
||||||
>
|
>
|
||||||
<SocialButtons />
|
<SocialButtons />
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -81,7 +101,7 @@
|
||||||
class="relative mx-auto lg:px-6 px-4 pt-4 sm:pt-6 sm:pb-6 pb-2 max-w-6xl text-left text-white"
|
class="relative mx-auto lg:px-6 px-4 pt-4 sm:pt-6 sm:pb-6 pb-2 max-w-6xl text-left text-white"
|
||||||
>
|
>
|
||||||
<div class="pl-2 sm:pl-6 lg:pl-10">
|
<div class="pl-2 sm:pl-6 lg:pl-10">
|
||||||
<div class="uppercase font-semibold text-md lg:text-lg lg:w-1/3">
|
<div class="uppercase font-semibold text-md lg:text-lg lg:w-1/3 text-white/70">
|
||||||
Otevřená komunitní kryptoměnová konference
|
Otevřená komunitní kryptoměnová konference
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
|
|
|
@ -30,6 +30,9 @@ export const layouts = writable({ test: null })
|
||||||
export const loadInfo = writable({ loaded: false })
|
export const loadInfo = writable({ loaded: false })
|
||||||
|
|
||||||
export const schedulePref = writable({
|
export const schedulePref = writable({
|
||||||
stages: [],
|
stage: null,
|
||||||
tracks: []
|
track: null,
|
||||||
|
time: null,
|
||||||
|
tracks: [],
|
||||||
|
showDescriptions: false
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,355 +0,0 @@
|
||||||
<script context="module">
|
|
||||||
export const prerender = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { onMount, onDestroy } from "svelte";
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function filterDateStage(arr, date, stageId) {
|
|
||||||
return arr
|
|
||||||
.filter((i) => i.date === date)
|
|
||||||
.filter((i) => i.stage === stageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {};
|
|
||||||
for (const stage of bundle.spec.stages) {
|
|
||||||
if (rowspans[stage.id] > 0) {
|
|
||||||
stages[stage.id] = null;
|
|
||||||
rowspans[stage.id]--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (schedulePref && !schedulePref.stages.includes(stage.id)) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (si) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arr.push({ title: format(time, "HH:mm"), stages });
|
|
||||||
time = new Date(time.getTime() + 30 * 60 * 1000);
|
|
||||||
}
|
|
||||||
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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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}`),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
return "border border-blue-web/50";
|
|
||||||
}
|
|
||||||
|
|
||||||
function activeStages (bundle, stages, day, pl) {
|
|
||||||
return stages.filter(stage => {
|
|
||||||
const dt = format(new Date(day), 'yyyy-MM-dd')
|
|
||||||
return Boolean(pl.schedule.filter(i => i.stage === stage.id).find(i => i.date === dt)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function findEvent(bundle, eventId) {
|
|
||||||
const ev = bundle.spec.events.find((ev) => ev.id === eventId);
|
|
||||||
if (!ev) {
|
|
||||||
console.log(`Event not found: ${eventId}`);
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
ev.color = "bg-rose-400/20 hover:bg-rose-400/40";
|
|
||||||
}
|
|
||||||
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"
|
|
||||||
>
|
|
||||||
<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", "exd:exclusivityDev"]
|
|
||||||
.map((key) => {
|
|
||||||
const [title, rkey] = key.split(":");
|
|
||||||
return `${title}:${
|
|
||||||
Math.round(p.metrics[rkey || title] * 1000) / 1000
|
|
||||||
}`;
|
|
||||||
})
|
|
||||||
.join(", ")}]</option
|
|
||||||
>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</section>
|
|
||||||
<section class="relative mx-auto pb-6 sm:pb-10 px-0 text-blue-web">
|
|
||||||
{#if $bundle}
|
|
||||||
<div class="max-w-6xl mx-auto px-6 mb-10">
|
|
||||||
<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>
|
|
||||||
{#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>
|
|
||||||
{/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>
|
|
||||||
{#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>
|
|
||||||
{/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>
|
|
||||||
</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" />
|
|
||||||
{#each activeStages($bundle, $bundle.spec.stages, st.date, plan) as stage}
|
|
||||||
{#if $schedulePref && $schedulePref.stages.includes(stage.id)}
|
|
||||||
<th class="text-md py-1.5 px-1 sticky top-0 bg-white align-bottom">
|
|
||||||
<div class="text-xs font-normal text-blue-web/60 mb-2.5">{stage.capacity.seat} <i class="fa-solid fa-chair"></i> + {stage.capacity.stand} <i class="fa-solid fa-person"></div>
|
|
||||||
<div>{stage.name}</div>
|
|
||||||
</th>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<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
|
|
||||||
>
|
|
||||||
{#each activeStages($bundle, $bundle.spec.stages, st.date, plan) as stage}
|
|
||||||
{#if $schedulePref && $schedulePref.stages.includes(stage.id)}
|
|
||||||
{#if ds.stages[stage.id] === undefined}
|
|
||||||
<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 transition-all {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")} <span class="opacity-70">#{si.id}</span>
|
|
||||||
{#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(", ")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
<!--th valign="top" class="pl-2 pt-1 text-sm" height="70">{ds.title}</th-->
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{:else}
|
|
||||||
Načítám ..
|
|
||||||
{/if}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script context="module">
|
||||||
|
export const prerender = true;
|
||||||
|
|
||||||
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Mapa | {$bundle ? $bundle.name : "UTXO.22"}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
|
<h1 class="uppercase text-2xl font-bold">Mapa</h1>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
TBA
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script context="module">
|
||||||
|
export const prerender = true;
|
||||||
|
|
||||||
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Praktické informace | {$bundle ? $bundle.name : "UTXO.22"}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
|
<h1 class="uppercase text-2xl font-bold">Praktické informace</h1>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
TBA
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -3,155 +3,290 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Event from "$lib/Event.svelte";
|
|
||||||
import { onMount, onDestroy } from "svelte";
|
import { onMount, onDestroy } from "svelte";
|
||||||
import { page } from "$app/stores";
|
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
import { bundle, userData, loadInfo } from "$lib/stores.js";
|
import { page } from "$app/stores";
|
||||||
import { calcDuration } from "$lib/events.js";
|
import { format, compareAsc, compareDesc, addDays } from "date-fns";
|
||||||
import WordCloud from "$lib/WordCloud.svelte";
|
import { bundle, userData, loadInfo, schedulePref } from "$lib/stores.js";
|
||||||
import Fuse from "fuse.js";
|
import { cs } from "date-fns/locale/index.js";
|
||||||
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
|
const renderers = { link: Link };
|
||||||
|
import Link from "$lib/Link.svelte";
|
||||||
|
|
||||||
$: tags = getTags($bundle);
|
let scheduleTimesArr = null
|
||||||
$: totalDuration = calcTotalDuration($bundle);
|
let stagesArr = null
|
||||||
|
|
||||||
let fuse = null;
|
let planNumber = 0;
|
||||||
let searchText = "";
|
$: plan = $bundle ? $bundle.spec["schedule-candidates"][planNumber] : null;
|
||||||
|
|
||||||
function getTags(data) {
|
const params = {
|
||||||
let res = {};
|
time: { key: 'time' },
|
||||||
data.spec.events.forEach((e) => {
|
stage: { key: 'stage' },
|
||||||
if (!e.tags) {
|
desc: { key: 'showDescriptions', type: 'boolean' }
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
e.tags.forEach((t) => {
|
|
||||||
if (!res[t]) {
|
let subs = []
|
||||||
res[t] = { text: t, count: 0 };
|
|
||||||
}
|
subs.push(page.subscribe(() => {
|
||||||
//res[t].count++
|
|
||||||
res[t].count += 1;
|
schedulePref.update(sp => {
|
||||||
});
|
for (const upk of Object.keys(params)) {
|
||||||
});
|
const up = params[upk]
|
||||||
let arr = Object.keys(res).map((k) => res[k]);
|
const _sp = $page.url.searchParams.get(upk)
|
||||||
const max = arr.reduce((p, c) => (c.count > p ? c.count : p), 0);
|
if (up.type === 'boolean') {
|
||||||
arr = arr.map((i) => {
|
if (_sp !== undefined) {
|
||||||
i.count = Math.round(i.count / (max / 40));
|
sp[up.key] = Boolean(_sp)
|
||||||
return i;
|
}
|
||||||
});
|
} else {
|
||||||
return arr;
|
sp[up.key] = _sp ? _sp : 'all'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sp
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
|
||||||
|
const bsub = bundle.subscribe((bundle) => {
|
||||||
|
|
||||||
|
scheduleTimesArr = scheduleTimes(bundle)
|
||||||
|
stagesArr = bundle.spec.stages
|
||||||
|
const pref = {};
|
||||||
|
//pref.stages = bundle.spec.stages.map((s) => s.id);
|
||||||
|
//pref.tracks = bundle.spec.tracks.map((s) => s.id);
|
||||||
|
//pref.times = scheduleTimesArr.map((s) => s.id);
|
||||||
|
//schedulePref.set(pref);
|
||||||
|
});
|
||||||
|
subs.push(bsub)
|
||||||
|
|
||||||
|
const pref = {}
|
||||||
|
let schedulePrefInicialized = null
|
||||||
|
|
||||||
|
const spsub = schedulePref.subscribe((sp) => {
|
||||||
|
const updates = []
|
||||||
|
updates.push([ 'time', sp.time === 'all' ? undefined : sp.time ])
|
||||||
|
updates.push([ 'stage', sp.stage === 'all' ? undefined : sp.stage ])
|
||||||
|
updates.push([ 'desc', sp.showDescriptions === null || sp.showDescriptions === false || sp.showDescriptions === undefined ? undefined : true ])
|
||||||
|
|
||||||
|
let target = '?'
|
||||||
|
if (updates.length > 0) {
|
||||||
|
for (const up of updates) {
|
||||||
|
if (up[1] === undefined && $page.url.searchParams.get(up[0]) !== undefined) {
|
||||||
|
$page.url.searchParams.delete(up[0])
|
||||||
|
} else {
|
||||||
|
$page.url.searchParams.set(up[0], up[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target = `?${$page.url.searchParams.toString()}`
|
||||||
|
}
|
||||||
|
goto(target);
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
subs.push(spsub)
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
for (const unsub of subs) {
|
||||||
|
unsub()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function filterDateStage(arr, date, stageId) {
|
||||||
|
return arr
|
||||||
|
.filter((i) => i.date === date)
|
||||||
|
.filter((i) => i.stage === stageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcTotalDuration(bundle) {
|
|
||||||
if (!bundle) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return bundle.spec.events.reduce(
|
|
||||||
(p, e) => p + (calcDuration(e, bundle) || 0),
|
function dateSlots(pl, period, bundle, schedulePref = null) {
|
||||||
0
|
let time = period.start;
|
||||||
|
const endTime = period.end;
|
||||||
|
const arr = [];
|
||||||
|
const rowspans = {};
|
||||||
|
|
||||||
|
while (compareAsc(time, endTime) === -1) {
|
||||||
|
const stages = {};
|
||||||
|
for (const stage of bundle.spec.stages) {
|
||||||
|
if (rowspans[stage.id] > 0) {
|
||||||
|
stages[stage.id] = null;
|
||||||
|
rowspans[stage.id]--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (schedulePref && (schedulePref.stage !== stage.id && schedulePref.stage !== 'all')) {
|
||||||
|
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;
|
||||||
|
|
||||||
function wordClick(e) {
|
if (si) {
|
||||||
const tag = e.detail.path[0].innerHTML;
|
const span = Math.floor(
|
||||||
if (tag) {
|
(new Date(si.period.end).getTime() -
|
||||||
goto(`/program?tag=${tag}`);
|
new Date(si.period.start).getTime()) /
|
||||||
}
|
(1000 * 60) /
|
||||||
return true;
|
30
|
||||||
}
|
);
|
||||||
|
si.span = span;
|
||||||
$: filters = makeFilters($page, $bundle);
|
if (span > 1) {
|
||||||
$: events = applyFilters(filters, $page, $bundle);
|
rowspans[stage.id] = span - 1;
|
||||||
$: ids = [];
|
|
||||||
|
|
||||||
function makeFilters(pg, bd) {
|
|
||||||
const search = pg.url.searchParams;
|
|
||||||
let fl = [];
|
|
||||||
|
|
||||||
// tags
|
|
||||||
if (search.get("tag")) {
|
|
||||||
fl.push({
|
|
||||||
type: "tag",
|
|
||||||
title: `Tag: #${search.get("tag")}`,
|
|
||||||
key: search.get("tag"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// tracks
|
|
||||||
if (search.get("track")) {
|
|
||||||
const track = bd.spec.tracks.find((t) => t.id === search.get("track"));
|
|
||||||
if (!track) {
|
|
||||||
return goto("/program");
|
|
||||||
}
|
|
||||||
fl.push({ type: "track", title: `Sekce: ${track.name}`, key: track.id });
|
|
||||||
}
|
|
||||||
if (searchText) {
|
|
||||||
fl.push({
|
|
||||||
type: "text",
|
|
||||||
title: `Text: "${searchText}"`,
|
|
||||||
key: searchText,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return fl;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyFilters(fl, pg, bd) {
|
|
||||||
if (!pg || !bd) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let arr = bd.spec.events;
|
|
||||||
for (const f of fl) {
|
|
||||||
if (f.type === "tag") {
|
|
||||||
arr = arr.filter((e) => e.tags && e.tags.includes(f.key));
|
|
||||||
}
|
|
||||||
if (f.type === "track") {
|
|
||||||
arr = arr.filter((e) => e.track === f.key);
|
|
||||||
}
|
|
||||||
if (f.type === "text") {
|
|
||||||
const sr = fuse.search(f.key);
|
|
||||||
if (sr.length > 0) {
|
|
||||||
arr = sr
|
|
||||||
.map((sr) => arr.find((i) => i.id === sr.item.id))
|
|
||||||
.filter((sr) => sr);
|
|
||||||
} else {
|
|
||||||
arr = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ids = arr.map((a) => a.id);
|
arr.push({ title: format(time, "HH:mm"), stages });
|
||||||
|
time = new Date(time.getTime() + 30 * 60 * 1000);
|
||||||
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle.subscribe((bd) => {
|
function showSpeakers(bundle, ev) {
|
||||||
fuse = new Fuse(bd.spec.events, {
|
return ev.speakers
|
||||||
//includeScore: true,
|
.map((sId) => {
|
||||||
//minMatchCharLength: 1,
|
const sp = bundle.spec.speakers.find((s) => s.id === sId);
|
||||||
threshold: 0.4,
|
return sp.name + (sp.nickname ? ` (${sp.nickname})` : "");
|
||||||
keys: [
|
})
|
||||||
{ name: "name", weight: 10 },
|
.join(", ");
|
||||||
{ name: "description", weight: 7 },
|
|
||||||
{ name: "speakers", weight: 5 },
|
|
||||||
{ name: "speakersInfo.nickname", weight: 5 },
|
|
||||||
{ name: "speakersInfo.twitter", weight: 4 },
|
|
||||||
{ name: "track", weight: 2 },
|
|
||||||
{ name: "tags", weight: 2 },
|
|
||||||
{ name: "speakersInfo.bio", weight: 1 },
|
|
||||||
{ name: "speakersInfo.orgs", weight: 1 },
|
|
||||||
{ name: "speakersInfo.description", weight: 1 },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
page.subscribe(() => {
|
|
||||||
searchText = "";
|
|
||||||
});
|
|
||||||
|
|
||||||
function searchTextSubmit() {
|
|
||||||
filters = makeFilters($page, $bundle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelFilter() {
|
function showEventDetail(bundle, ev) {
|
||||||
searchText = "";
|
if (ev.type === "lightning-series") {
|
||||||
filters = makeFilters($page, $bundle);
|
return bundle.spec.events
|
||||||
goto("/program");
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parsePeriod(bundle, str) {
|
||||||
|
const [dayNumber, times, name] = str.split("/");
|
||||||
|
const [start, end] = times.split("-");
|
||||||
|
const date = bundle.dates[dayNumber - 1];
|
||||||
|
|
||||||
|
const endDate = end > start ? date : format(addDays(new Date(date), 1), 'yyyy-MM-dd')
|
||||||
|
return {
|
||||||
|
date,
|
||||||
|
name,
|
||||||
|
period: {
|
||||||
|
start: new Date(`${date}T${start}`),
|
||||||
|
end: new Date(`${endDate}T${end}`),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleTimes(bundle, filter = false) {
|
||||||
|
let arr = bundle.scheduleTimes.map((item, i) => {
|
||||||
|
const out = parsePeriod(bundle, item);
|
||||||
|
out.id = String(i)
|
||||||
|
return out
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filter) {
|
||||||
|
arr = arr.filter(st => st.id === filter || filter === 'all')
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
function eventTrackClasses(bundle, ev, selectedTracks) {
|
||||||
|
/*if (!selectedTracks.includes(ev.track || "")) {
|
||||||
|
return "opacity-20";
|
||||||
|
}*/
|
||||||
|
return "border border-blue-web/50";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPeriodOverlap(x, y) {
|
||||||
|
const xstart = new Date(x.start)
|
||||||
|
const xend = new Date(x.end)
|
||||||
|
const ystart = new Date(y.start)
|
||||||
|
const yend = new Date(y.end)
|
||||||
|
return (xstart.getTime() < yend.getTime() &&
|
||||||
|
xend.getTime() > ystart.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeStages (bundle, stages, st, pl) {
|
||||||
|
return stages.filter(stage => {
|
||||||
|
return Boolean(pl.schedule.filter(i => i.stage === stage.id).find(i => isPeriodOverlap(st.period, i.period))
|
||||||
|
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function allScheduleTimes (bundle) {
|
||||||
|
return [
|
||||||
|
{ id: 'all', name: 'Všechny dny' },
|
||||||
|
...scheduleTimes(bundle)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function allStages (bundle) {
|
||||||
|
return [
|
||||||
|
{ id: 'all', name: 'Všechny sály' },
|
||||||
|
...bundle.spec.stages
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSpoiler(_e) {
|
||||||
|
if (!_e.description) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parts = _e.description.split("\n\n");
|
||||||
|
const stripped = parts.length > 1;
|
||||||
|
return {
|
||||||
|
md: parts[0], // + ` ([Zobrazit celý popis](/udalosti?id=${_e.id}))`,
|
||||||
|
stripped,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function findEvent(bundle, eventId) {
|
||||||
|
const ev = bundle.spec.events.find((ev) => ev.id === eventId);
|
||||||
|
if (!ev) {
|
||||||
|
console.log(`Event not found: ${eventId}`);
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
ev.color = "bg-rose-400/20 hover:bg-rose-400/40";
|
||||||
|
}
|
||||||
|
return ev;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -159,85 +294,213 @@
|
||||||
<title>Program | UTXO.22</title>
|
<title>Program | UTXO.22</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
<section
|
||||||
<h1 class="uppercase text-2xl font-bold">Program</h1>
|
class="relative mx-auto pt-6 sm:pt-10 pb-6 px-6 max-w-6xl text-blue-web"
|
||||||
<div class="mt-2">
|
>
|
||||||
<p>
|
<div class="mb-6">
|
||||||
Program <a href="/changelog" class="underline hover:no-underline"
|
{#if $bundle}
|
||||||
>stále připravujeme</a
|
<div class="font-semibold uppercase mb-1">Plán (řešení)</div>
|
||||||
>. Aktuálně finišujeme jeho přípravu a <span class="font-semibold">nejpozději ráno v pondělí 30. května zde najdete konkrétní časové rozpisy jednotlivých sálů</span>. Těšíme se na vás! 🙏❤️ - <span class="italic">UTXO.22 organizační team</span>
|
<div class="flex flex-wrap gap-1">
|
||||||
</p>
|
<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", "exd:exclusivityDev"]
|
||||||
|
.map((key) => {
|
||||||
|
const [title, rkey] = key.split(":");
|
||||||
|
return `${title}:${
|
||||||
|
Math.round(p.metrics[rkey || title] * 1000) / 1000
|
||||||
|
}`;
|
||||||
|
})
|
||||||
|
.join(", ")}]</option
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<!--div class="mt-6 flex flex-wrap gap-3 px-4 text-center">
|
{/if}
|
||||||
<div class="flex-1">
|
|
||||||
<div class="text-4xl">{$bundle.spec.events.length}</div>
|
|
||||||
<div class="uppercase font-sm mt-1">událostí</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<h1 class="uppercase text-2xl font-bold mb-2">Program</h1>
|
||||||
<div class="text-4xl">{$bundle.spec.speakers.length}</div>
|
<div class="mb-4">
|
||||||
<div class="uppercase font-sm mt-1">přednášejících</div>
|
<a href="/seznam-udalosti" class="underline hover:no-underline">Seznam všech událostí</a>
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class="text-4xl">{Math.round((totalDuration / 60) * 100) / 100}</div>
|
|
||||||
<div class="uppercase font-sm mt-1">hodin obsahu</div>
|
|
||||||
</div>
|
|
||||||
</div-->
|
|
||||||
|
|
||||||
<div class="mt-6 bg-custom-green/30 rounded-lg px-4 py-3">
|
|
||||||
<span class="font-semibold">🔥 Chcete kryptokomunitě něco říct? prezentovat svůj projekt nebo nápad? nebo snad prodiskutovat nějaké krypto téma? Každopádně potkat nové lidi?</span> Uspořádejte <a href="https://docs.utxo.cz/hlavni-program/formaty-programu#campfire-taborovy-ohen" target="_blank" class="font-semibold">Campfire session</a>! Jde o náš nový formát, kterým chceme dát možnost doplnit obsah na UTXO.22 i široké komunitě.<br/>
|
|
||||||
Detaily o Campfire formátu a přihlášku naleznete <a href="https://docs.google.com/forms/d/e/1FAIpQLScYh21d2z3sVDXyE9b15HxG0fabTiW5jJ8qJlAJT_w_j4v23w/viewform?usp=sf_link" target="_blank" class="underline hover:no-underline">na tomto odkazu</a>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if filters.length > 0}
|
|
||||||
<div class="mt-6 flex flex-wrap gap-3">
|
|
||||||
<div class="my-auto">Filtry:</div>
|
|
||||||
<div class="text-sm my-auto flex gap-1">
|
|
||||||
{#each filters as filter}
|
|
||||||
<div class="py-1 px-2 rounded bg-blue-web/60 text-white">
|
|
||||||
{filter.title}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{#if $bundle}
|
||||||
|
<div class="mb-4">
|
||||||
|
<div class="flex gap-1 flex-wrap">
|
||||||
|
<div class="font-semibold uppercase my-auto mx-3">Den</div>
|
||||||
|
{#each allScheduleTimes($bundle) as st}
|
||||||
|
<button class="{($schedulePref.time === st.id) ? 'bg-utxo-gradient text-white' : 'text-blue-web bg-blue-web-light hover:text-[#E16A61] hover:bg-[#E16A61]/20'} font-bold py-2 px-4 rounded-full"
|
||||||
|
on:click={() => $schedulePref.time = st.id}
|
||||||
|
>{st.name}</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-3 my-auto">
|
</div>
|
||||||
<a href="" on:click={cancelFilter}
|
<div class="mb-4">
|
||||||
><i class="fa-solid fa-xmark text-red-500 mr-1" /> Zrušit filtr</a
|
<div class="flex gap-1 flex-wrap">
|
||||||
|
<div class="font-semibold uppercase my-auto mx-3">Sál</div>
|
||||||
|
{#each allStages($bundle) as et}
|
||||||
|
<button class="{($schedulePref.stage === et.id) ? 'bg-utxo-gradient text-white' : 'text-blue-web bg-blue-web-light hover:text-[#E16A61] hover:bg-[#E16A61]/20'} font-bold py-1.5 px-3 rounded-full text-sm"
|
||||||
|
on:click={() => $schedulePref.stage = et.id}
|
||||||
|
>{et.name}</button>
|
||||||
|
<!--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="mb-4">
|
||||||
|
<label><input type="checkbox" bind:checked={$schedulePref.showDescriptions} /> Zobrazit popisy</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--div class="mb-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>
|
||||||
|
{#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>
|
||||||
{:else if $loadInfo.loaded}
|
|
||||||
<div class="mt-6 lg:mt-10 flex sm:justify-center overflow-auto">
|
|
||||||
<WordCloud words={tags} on:click={wordClick} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="mt-6 sm:flex">
|
|
||||||
<div class="my-auto flex-1">
|
|
||||||
<h1 class="uppercase text-lg font-semibold">
|
|
||||||
Seznam událostí ({ids.length}/{$bundle.spec.events.length})
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto flex gap-2 mt-2 sm:mt-0">
|
|
||||||
<div class="my-auto">Hledat:</div>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
bind:value={searchText}
|
|
||||||
on:input={searchTextSubmit}
|
|
||||||
class="border rounded border-blue-web/30 px-1.5 py-1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
{#each ids as id}
|
|
||||||
<Event event={$bundle.spec.events.find((e) => e.id === id)} />
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<!--div class="mt-4">
|
|
||||||
{#each $bundle.spec.events as e}
|
|
||||||
{#if ids.includes(e.id)}
|
|
||||||
<Event event={e} />
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div-->
|
</div-->
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
<section class="relative mx-auto pb-6 sm:pb-10 px-0 text-blue-web">
|
||||||
|
{#if $bundle}
|
||||||
|
{#each scheduleTimes($bundle, $schedulePref.time) as st}
|
||||||
|
<div class="max-w-6xl mx-auto px-6 mb-4">
|
||||||
|
<h2 class="uppercase text-xl font-bold">
|
||||||
|
{#if st.name}
|
||||||
|
{st.name}
|
||||||
|
{:else}
|
||||||
|
{format(new Date(st.date), "iiii d.M.y", { locale: cs })}
|
||||||
|
{/if}
|
||||||
|
</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 top-0 sticky bg-white uppercase text-sm px-0.5 text-custom-blue">{format(new Date(st.date), "iiiiii", { locale: cs })}<br />{format(new Date(st.date), "d.M.")}</th>
|
||||||
|
{#each activeStages($bundle, $bundle.spec.stages, st, plan) as stage}
|
||||||
|
{#if $schedulePref && ($schedulePref.stage === stage.id || $schedulePref.stage === 'all')}
|
||||||
|
<th class="text-md py-1.5 px-1 sticky top-0 bg-white align-bottom">
|
||||||
|
<div class="text-xs font-normal text-blue-web/60 mb-2.5">{stage.capacity.seat} <i class="fa-solid fa-chair"></i> + {stage.capacity.stand} <i class="fa-solid fa-person"></div>
|
||||||
|
<div>{stage.name}</div>
|
||||||
|
</th>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<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 left-0 bg-white"
|
||||||
|
height="40">{ds.title}</th
|
||||||
|
>
|
||||||
|
{#each activeStages($bundle, $bundle.spec.stages, st, plan) as stage}
|
||||||
|
{#if $schedulePref && ($schedulePref.stage === stage.id || $schedulePref.stage === 'all')}
|
||||||
|
{#if ds.stages[stage.id] === undefined}
|
||||||
|
<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 transition-all {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")} <span class="text-blue-web/80">@{si.id}</span>
|
||||||
|
{#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}" class="hover:underline"
|
||||||
|
>{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(", ")}
|
||||||
|
</div>
|
||||||
|
{#if event.description && $schedulePref.showDescriptions}
|
||||||
|
{#each [makeSpoiler(event)] as spoiler}
|
||||||
|
<div class="mt-2 overflow-hidden text-sm text-blue-web/90">
|
||||||
|
<SvelteMarkdown source={spoiler.md} {renderers} />
|
||||||
|
{#if spoiler.stripped}
|
||||||
|
<div class="text-xs text-blue-web/60">
|
||||||
|
(<a href="/udalosti?id={event.id}">Zobrazit celý popis</a>)
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
<!--th valign="top" class="pl-2 pt-1 text-sm" height="70">{ds.title}</th-->
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
Načítám ..
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
<script context="module">
|
||||||
|
export const prerender = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Event from "$lib/Event.svelte";
|
||||||
|
import { onMount, onDestroy } from "svelte";
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import { bundle, userData, loadInfo } from "$lib/stores.js";
|
||||||
|
import { calcDuration } from "$lib/events.js";
|
||||||
|
import WordCloud from "$lib/WordCloud.svelte";
|
||||||
|
import Fuse from "fuse.js";
|
||||||
|
|
||||||
|
$: tags = getTags($bundle);
|
||||||
|
$: totalDuration = calcTotalDuration($bundle);
|
||||||
|
|
||||||
|
let fuse = null;
|
||||||
|
let searchText = "";
|
||||||
|
|
||||||
|
function getTags(data) {
|
||||||
|
let res = {};
|
||||||
|
data.spec.events.forEach((e) => {
|
||||||
|
if (!e.tags) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.tags.forEach((t) => {
|
||||||
|
if (!res[t]) {
|
||||||
|
res[t] = { text: t, count: 0 };
|
||||||
|
}
|
||||||
|
//res[t].count++
|
||||||
|
res[t].count += 1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let arr = Object.keys(res).map((k) => res[k]);
|
||||||
|
const max = arr.reduce((p, c) => (c.count > p ? c.count : p), 0);
|
||||||
|
arr = arr.map((i) => {
|
||||||
|
i.count = Math.round(i.count / (max / 40));
|
||||||
|
return i;
|
||||||
|
});
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcTotalDuration(bundle) {
|
||||||
|
if (!bundle) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return bundle.spec.events.reduce(
|
||||||
|
(p, e) => p + (calcDuration(e, bundle) || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wordClick(e) {
|
||||||
|
const tag = e.detail.path[0].innerHTML;
|
||||||
|
if (tag) {
|
||||||
|
goto(`/program?tag=${tag}`);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: filters = makeFilters($page, $bundle);
|
||||||
|
$: events = applyFilters(filters, $page, $bundle);
|
||||||
|
$: ids = [];
|
||||||
|
|
||||||
|
function makeFilters(pg, bd) {
|
||||||
|
const search = pg.url.searchParams;
|
||||||
|
let fl = [];
|
||||||
|
|
||||||
|
// tags
|
||||||
|
if (search.get("tag")) {
|
||||||
|
fl.push({
|
||||||
|
type: "tag",
|
||||||
|
title: `Tag: #${search.get("tag")}`,
|
||||||
|
key: search.get("tag"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// tracks
|
||||||
|
if (search.get("track")) {
|
||||||
|
const track = bd.spec.tracks.find((t) => t.id === search.get("track"));
|
||||||
|
if (!track) {
|
||||||
|
return goto("/program");
|
||||||
|
}
|
||||||
|
fl.push({ type: "track", title: `Sekce: ${track.name}`, key: track.id });
|
||||||
|
}
|
||||||
|
if (searchText) {
|
||||||
|
fl.push({
|
||||||
|
type: "text",
|
||||||
|
title: `Text: "${searchText}"`,
|
||||||
|
key: searchText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilters(fl, pg, bd) {
|
||||||
|
if (!pg || !bd) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let arr = bd.spec.events;
|
||||||
|
for (const f of fl) {
|
||||||
|
if (f.type === "tag") {
|
||||||
|
arr = arr.filter((e) => e.tags && e.tags.includes(f.key));
|
||||||
|
}
|
||||||
|
if (f.type === "track") {
|
||||||
|
arr = arr.filter((e) => e.track === f.key);
|
||||||
|
}
|
||||||
|
if (f.type === "text") {
|
||||||
|
const sr = fuse.search(f.key);
|
||||||
|
if (sr.length > 0) {
|
||||||
|
arr = sr
|
||||||
|
.map((sr) => arr.find((i) => i.id === sr.item.id))
|
||||||
|
.filter((sr) => sr);
|
||||||
|
} else {
|
||||||
|
arr = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ids = arr.map((a) => a.id);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.subscribe((bd) => {
|
||||||
|
fuse = new Fuse(bd.spec.events, {
|
||||||
|
//includeScore: true,
|
||||||
|
//minMatchCharLength: 1,
|
||||||
|
threshold: 0.4,
|
||||||
|
keys: [
|
||||||
|
{ name: "name", weight: 10 },
|
||||||
|
{ name: "description", weight: 7 },
|
||||||
|
{ name: "speakers", weight: 5 },
|
||||||
|
{ name: "speakersInfo.nickname", weight: 5 },
|
||||||
|
{ name: "speakersInfo.twitter", weight: 4 },
|
||||||
|
{ name: "track", weight: 2 },
|
||||||
|
{ name: "tags", weight: 2 },
|
||||||
|
{ name: "speakersInfo.bio", weight: 1 },
|
||||||
|
{ name: "speakersInfo.orgs", weight: 1 },
|
||||||
|
{ name: "speakersInfo.description", weight: 1 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
page.subscribe(() => {
|
||||||
|
searchText = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchTextSubmit() {
|
||||||
|
filters = makeFilters($page, $bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelFilter() {
|
||||||
|
searchText = "";
|
||||||
|
filters = makeFilters($page, $bundle);
|
||||||
|
goto("/program");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Seznam událostí | UTXO.22</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
|
<h1 class="uppercase text-2xl font-bold"><a href="/program">Program</a> → Seznam událostí</h1>
|
||||||
|
<div class="mt-2">
|
||||||
|
<p>
|
||||||
|
Program <a href="/changelog" class="underline hover:no-underline"
|
||||||
|
>stále připravujeme</a
|
||||||
|
>. Aktuálně finišujeme jeho přípravu a <span class="font-semibold">nejpozději ráno v pondělí 30. května zde najdete konkrétní časové rozpisy jednotlivých sálů</span>. Těšíme se na vás! 🙏❤️ - <span class="italic">UTXO.22 organizační team</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!--div class="mt-6 flex flex-wrap gap-3 px-4 text-center">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="text-4xl">{$bundle.spec.events.length}</div>
|
||||||
|
<div class="uppercase font-sm mt-1">událostí</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="text-4xl">{$bundle.spec.speakers.length}</div>
|
||||||
|
<div class="uppercase font-sm mt-1">přednášejících</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="text-4xl">{Math.round((totalDuration / 60) * 100) / 100}</div>
|
||||||
|
<div class="uppercase font-sm mt-1">hodin obsahu</div>
|
||||||
|
</div>
|
||||||
|
</div-->
|
||||||
|
|
||||||
|
<div class="mt-6 bg-custom-green/30 rounded-lg px-4 py-3">
|
||||||
|
<span class="font-semibold">🔥 Chcete kryptokomunitě něco říct? prezentovat svůj projekt nebo nápad? nebo snad prodiskutovat nějaké krypto téma? Každopádně potkat nové lidi?</span> Uspořádejte <a href="https://docs.utxo.cz/hlavni-program/formaty-programu#campfire-taborovy-ohen" target="_blank" class="font-semibold">Campfire session</a>! Jde o náš nový formát, kterým chceme dát možnost doplnit obsah na UTXO.22 i široké komunitě.<br/>
|
||||||
|
Detaily o Campfire formátu a přihlášku naleznete <a href="https://docs.google.com/forms/d/e/1FAIpQLScYh21d2z3sVDXyE9b15HxG0fabTiW5jJ8qJlAJT_w_j4v23w/viewform?usp=sf_link" target="_blank" class="underline hover:no-underline">na tomto odkazu</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if filters.length > 0}
|
||||||
|
<div class="mt-6 flex flex-wrap gap-3">
|
||||||
|
<div class="my-auto">Filtry:</div>
|
||||||
|
<div class="text-sm my-auto flex gap-1">
|
||||||
|
{#each filters as filter}
|
||||||
|
<div class="py-1 px-2 rounded bg-blue-web/60 text-white">
|
||||||
|
{filter.title}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="ml-3 my-auto">
|
||||||
|
<a href="" on:click={cancelFilter}
|
||||||
|
><i class="fa-solid fa-xmark text-red-500 mr-1" /> Zrušit filtr</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else if $loadInfo.loaded}
|
||||||
|
<div class="mt-6 lg:mt-10 flex sm:justify-center overflow-auto">
|
||||||
|
<WordCloud words={tags} on:click={wordClick} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="mt-6 sm:flex">
|
||||||
|
<div class="my-auto flex-1">
|
||||||
|
<h1 class="uppercase text-lg font-semibold">
|
||||||
|
Seznam událostí ({ids.length}/{$bundle.spec.events.length})
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto flex gap-2 mt-2 sm:mt-0">
|
||||||
|
<div class="my-auto">Hledat:</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={searchText}
|
||||||
|
on:input={searchTextSubmit}
|
||||||
|
class="border rounded border-blue-web/30 px-1.5 py-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
{#each ids as id}
|
||||||
|
<Event event={$bundle.spec.events.find((e) => e.id === id)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<!--div class="mt-4">
|
||||||
|
{#each $bundle.spec.events as e}
|
||||||
|
{#if ids.includes(e.id)}
|
||||||
|
<Event event={e} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div-->
|
||||||
|
</section>
|
|
@ -0,0 +1,141 @@
|
||||||
|
<script context="module">
|
||||||
|
export const prerender = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { onMount, onDestroy } from "svelte";
|
||||||
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
|
import { format, formatDistanceToNow } from "date-fns";
|
||||||
|
import EventTypeLabel from "$lib/EventTypeLabel.svelte";
|
||||||
|
import Avatar from "$lib/Avatar.svelte";
|
||||||
|
import YouTube from 'svelte-youtube';
|
||||||
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
|
import Link from "$lib/Link.svelte";
|
||||||
|
const renderers = { link: Link };
|
||||||
|
|
||||||
|
const stageStatus = {}
|
||||||
|
let events = []
|
||||||
|
let cachedBundle = []
|
||||||
|
|
||||||
|
bundle.subscribe(_bundle => {
|
||||||
|
events = _bundle.spec['schedule-candidates'][0].schedule
|
||||||
|
cachedBundle = _bundle
|
||||||
|
genStatus(cachedBundle)
|
||||||
|
})
|
||||||
|
|
||||||
|
let interval = null
|
||||||
|
onMount(() => {
|
||||||
|
|
||||||
|
interval = setInterval(() => {
|
||||||
|
genStatus(cachedBundle)
|
||||||
|
}, 5000)
|
||||||
|
})
|
||||||
|
onDestroy(() => {
|
||||||
|
clearInterval(interval)
|
||||||
|
})
|
||||||
|
|
||||||
|
function findSpeaker (sp, _bundle) {
|
||||||
|
return _bundle.spec.speakers.find(s => s.id === sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
function extendEvents (arr, _bundle) {
|
||||||
|
for (const ev of arr) {
|
||||||
|
ev._event = _bundle.spec.events.find(e => e.id === ev.event)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
function genStatus(_bundle) {
|
||||||
|
const now = new Date(`2022-06-04T${format(new Date(), 'HH:mm')}`)
|
||||||
|
|
||||||
|
let globalNextEvents = events.filter(ev => {
|
||||||
|
return new Date(ev.period.end).getTime() > now.getTime()
|
||||||
|
})
|
||||||
|
|
||||||
|
const stages = _bundle.spec.stages
|
||||||
|
for (const stage of stages.filter(s => s.livestream)) {
|
||||||
|
let nextEvents = [...globalNextEvents.filter(e => e.stage === stage.id)]
|
||||||
|
let current = null
|
||||||
|
if (new Date(nextEvents[0].period.start).getTime() <= now.getTime()) {
|
||||||
|
current = nextEvents[0]
|
||||||
|
nextEvents = nextEvents.slice(1)
|
||||||
|
}
|
||||||
|
stageStatus[stage.id] = {
|
||||||
|
current: current ? extendEvents([current], _bundle)[0] : null,
|
||||||
|
next: extendEvents(nextEvents.slice(0,2), _bundle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(stageStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSpoiler(_e) {
|
||||||
|
if (!_e.description) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parts = _e.description.split("\n\n");
|
||||||
|
const stripped = parts.length > 1;
|
||||||
|
return {
|
||||||
|
md: parts[0], // + ` ([Zobrazit celý popis](/udalosti?id=${_e.id}))`,
|
||||||
|
stripped,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>UTXO.TV</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="w-full h-full bg-blue-web-bg/90">
|
||||||
|
<section class="relative mx-auto py-6 sm:py-10 px-6 text-white">
|
||||||
|
{#if $bundle}
|
||||||
|
{#each $bundle.spec.stages.filter(s => s.livestream) as stage, i}
|
||||||
|
<div class="mb-8 bg-blue-web-bg/90 p-4 rounded-lg">
|
||||||
|
<h1 class="uppercase text-2xl font-bold">#{i+1} | {stage.name}</h1>
|
||||||
|
<div class="flex gap-6 mt-4 flex-wrap xl:flex-nowrap">
|
||||||
|
<div>
|
||||||
|
<YouTube videoId="bqiZ2xih6Jk" class="bg-blue-web-bg" />
|
||||||
|
</div>
|
||||||
|
<div class="pr-2">
|
||||||
|
{#each [stageStatus[stage.id]] as ss}
|
||||||
|
<div>
|
||||||
|
{#if ss.current}
|
||||||
|
<div class="uppercase text-xs mb-2 font-semibold flex gap-2"><div class="my-auto">Právě probíhá</div> <EventTypeLabel event={ss.current._event} black={true} /></div>
|
||||||
|
<div class="text-xl"><span class="text-white/70">{format(new Date(ss.current.period.start), 'HH:mm')}-{format(new Date(ss.current.period.end), 'HH:mm')}</span> <a href="/udalosti?id={ss.current.event}" class="hover:underline">{ss.current._event.name}</a></div>
|
||||||
|
<div class="flex flex-wrap mt-2 gap-3">
|
||||||
|
{#each ss.current._event.speakers.map(sp => findSpeaker(sp, $bundle)) as speaker}
|
||||||
|
<div class="flex gap-2"><Avatar speaker={speaker} size="extra-small" /><div><a href="/lide?id={speaker.id}" class="hover:underline">{speaker.name} {#if speaker.nickname}({speaker.nickname}){/if}</a></div></div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#if ss.current._event.description}
|
||||||
|
{#each [makeSpoiler(ss.current._event)] as spoiler}
|
||||||
|
<div class="text-sm mt-2 text-white/80">
|
||||||
|
<SvelteMarkdown source={spoiler.md} {renderers} />
|
||||||
|
{#if spoiler.stripped}
|
||||||
|
<div class="text-sm text-white/30">
|
||||||
|
(<a href="/udalosti?id={ss.current.event}">Zobrazit celý popis</a>)
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
<div class="text-sm mt-3 text-white/50">{@html ss.current._event.tags.map(t => `<a href="/seznam-udalosti?tag=${t}" class="hover:underline">#${t}</a>`).join(' ')}</div>
|
||||||
|
{:else}
|
||||||
|
<div class="text-xl">☕ Přestávka</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<div class="uppercase text-xs mb-2 font-semibold mt-6">Následuje</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
{#each stageStatus[stage.id].next as ne}
|
||||||
|
<div><span class="text-white/70">{format(new Date(ne.period.start), 'HH:mm')}-{format(new Date(ne.period.end), 'HH:mm')}</span> <a href="/udalosti?id={ne.event}" class="hover:underline">{ne._event.name}</a></div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
Načítám ...
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
</div>
|
|
@ -21,7 +21,7 @@
|
||||||
$: id = getId($page.url.search);
|
$: id = getId($page.url.search);
|
||||||
$: e = $bundle ? $bundle.spec.events.find((ev) => ev.id === id) : null;
|
$: e = $bundle ? $bundle.spec.events.find((ev) => ev.id === id) : null;
|
||||||
$: duration = e ? calcDuration(e, $bundle) : null;
|
$: duration = e ? calcDuration(e, $bundle) : null;
|
||||||
$: childrens = $bundle.spec.events.filter((i) => i.parent === e.id);
|
$: childrens = e ? $bundle.spec.events.filter((i) => i.parent === e.id) : []
|
||||||
|
|
||||||
function getId(search) {
|
function getId(search) {
|
||||||
const searchParams = new URLSearchParams(search);
|
const searchParams = new URLSearchParams(search);
|
||||||
|
|
Načítá se…
Odkázat v novém úkolu